Skip to content

About

Prometheus — a private suite of AI tools. First: Socrates, a book summarizer that reads with Claude and keeps both book and summary.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

19 Commits

Folders and files

Repository files navigation

🔥 Prometheus

A private workshop for a few good tools.

First tool in the fire: Socrates — upload a book, get a real summary, keep both.


What Socrates does

You drop in a PDF, EPUB, DOCX, TXT or Markdown file. Your browser pulls the text out locally — the file itself never leaves your device. The text goes to a small API, a runner on your own machine reads it end to end with Claude, and a structured summary comes back: core argument, key themes, chapter-by-chapter, takeaways, and the passages worth quoting.

Both the summary and the full text stay in your library, so you can come back and re-read either. Export the summary as PDF, Word or Markdown.

How it is put together

GitHub Pages cannot run server code, and a Claude Pro/Max subscription has no HTTP API — so the work splits three ways:

Piece Runs on Job
apps/web GitHub Pages React app. Google sign-in, text extraction, reading, export
apps/api Cloudflare Worker Verifies identity, enforces the allowlist, stores books (R2) and jobs (D1)
apps/runner Your Mac or home server Polls for jobs, drives claude -p on your subscription

The runner pulls work. Nothing connects to your machine — no open port, no tunnel. The Worker never holds a Claude credential.

See docs/ARCHITECTURE.md for the reasoning and the trust boundaries.

Setup

Four things to create: a Google OAuth client, a D1 database, an R2 bucket, and two secrets. Roughly 20 minutes.

1. Install

git clone https://github.com/rafsunsheikh/prometheus.git
cd prometheus
npm install

2. Google OAuth client

At console.cloud.google.com:

  1. Create a project, then Create Credentials → OAuth client ID → Web application.
  2. Under Authorized JavaScript origins, add both:
    • https://rafsunsheikh.github.io
    • http://localhost:5173 (for local development)
  3. Leave redirect URIs empty — Google Identity Services does not use them here.
  4. Copy the Client ID. It is a public value; it ships in the bundle by design.

On the OAuth consent screen, set the publishing status to Testing and add the Gmail accounts you want as test users. That is Google's own gate; the allowlist below is yours, and both apply.

3. Cloudflare

npx wrangler login

# Database
npx wrangler d1 create prometheus-db
#   → copy the printed database_id into apps/api/wrangler.toml

# Object storage
npx wrangler r2 bucket create prometheus-library

Then edit apps/api/wrangler.toml:

[vars]
ALLOWED_ORIGINS = "https://rafsunsheikh.github.io,http://localhost:5173"
GOOGLE_CLIENT_ID = "<the client ID from step 2>"

[[d1_databases]]
database_id = "<the id wrangler printed>"

The allowlist is deliberately not here — it is a secret, set below.

Set the two secrets and deploy:

cd apps/api
openssl rand -base64 48 | npx wrangler secret put SESSION_SECRET
openssl rand -hex 32   | npx wrangler secret put RUNNER_TOKEN   # save this, the runner needs it

# Who may sign in. A secret rather than a var, because this repo is public and
# these are real addresses. "," separates people, "|" joins one person's.
echo 'you@example.com|you.alt@example.com' | npx wrangler secret put ALLOWED_EMAILS
npx wrangler d1 migrations apply prometheus-db --remote
npx wrangler deploy

Note the deployed URL — https://prometheus-api.<subdomain>.workers.dev.

4. The runner

The machine that runs this must already be signed into Claude Code. Run claude once interactively and complete the login if you have not.

cp apps/runner/.env.example apps/runner/.env
PROMETHEUS_API_URL="https://prometheus-api.<subdomain>.workers.dev"
PROMETHEUS_RUNNER_TOKEN="<the RUNNER_TOKEN from step 3>"
CLAUDE_BIN="/Users/you/.local/bin/claude"
CLAUDE_MODEL="sonnet"

CLAUDE_BIN must point at the real binary, not a shell function. Check with type claude — if it prints a function body, use the path inside it.

npm run dev:runner          # foreground
npm run once -w @prometheus/runner   # drain one job and exit

To keep it alive, see apps/runner/com.prometheus.runner.plist.example (macOS) or apps/runner/prometheus-runner.service.example (Linux).

4b. Using Prometheus from more than one machine

The web app needs nothing — it is a website. Sign in with Google from any browser and your whole library is there, because books and summaries live in D1 and R2 rather than on any one computer. Uploading works from anywhere too: extraction runs in whatever browser you are sitting at, and only the text is sent on.

The runner is the only part tied to a machine, because it needs your Claude login. Two options:

  • Run it on your always-on box (home server, spare laptop). Jobs you queue from a phone or a work laptop get picked up whether or not your Mac is awake.
  • Run it on several of your machines at once. This is safe: claiming a job is an atomic conditional UPDATE, so two runners can never take the same job, and a long queue simply drains faster.

Each machine needs the repo, apps/runner/.env with the same RUNNER_TOKEN, and Claude Code already signed in as that user.

Running multiple runners is safe because Prometheus is single-user. Every runner claims from one shared queue regardless of who owns the job, so before adding a second person to ALLOWED_EMAILS, the claim query must be scoped by owner — otherwise their runner would summarize your books on their machine.

5. Deploy the web app

In the GitHub repo, under Settings → Secrets and variables → Actions → Variables, add two repository variables:

Name Value
VITE_API_URL https://prometheus-api.<subdomain>.workers.dev
VITE_GOOGLE_CLIENT_ID the client ID from step 2

Then Settings → Pages → Source: GitHub Actions, and push to main. The site lands at https://rafsunsheikh.github.io/prometheus/.

Local development

cp apps/api/.dev.vars.example apps/api/.dev.vars     # fill in both secrets
cp apps/web/.env.example apps/web/.env.local         # point at http://127.0.0.1:8787

npm run db:migrate:local
npm run dev:api      # → http://127.0.0.1:8787
npm run dev:web      # → http://localhost:5173
npm run dev:runner

Commands

Command What it does
npm run dev:web Vite dev server
npm run dev:api Worker on 127.0.0.1:8787
npm run dev:runner Poll and summarize continuously
npm run typecheck Typecheck every workspace
npm run build Typecheck the API, build the web bundle
npm run db:migrate:remote Apply migrations to the live D1

Adding or removing people

ALLOWED_EMAILS is a Cloudflare secret, not a committed value — this repo is public and those are real addresses. To change it:

cd apps/api
echo 'you@example.com|you.alt@example.com, friend@example.com' \
  | npx wrangler secret put ALLOWED_EMAILS

No redeploy needed. It is re-read on every request, so removing someone cuts them off immediately rather than when their token happens to expire. If the secret is never set, nobody gets in — it fails closed, and says so distinctly rather than pretending you are simply not on the list.

Two separators, and the difference matters:

ALLOWED_EMAILS = "you@example.com|you.alt@example.com, friend@example.com"
#                 └──── one person, two addresses ────┘  └─ a different person
  • , separates people. Each gets their own private library.
  • | joins one person's addresses. They all open the same library, and the first address is the identity the books are filed under.

If you forget a |, you get two separate libraries — never an accidentally shared one. Adding an alias to an existing person is safe: their books stay put, because ownership follows the first address in the group. Reordering a group, though, re-files that person's library under a different address, so don't.

Gmail ignores dots and +tags, and treats googlemail.com as gmail.com, so those variants all resolve to the same account automatically. Dots are significant on every other domain.

Whichever address you sign in with, the header shows the library you are in and which account you arrived by.

Also: Google's own list

The consent screen in Testing mode only admits accounts listed as test users. Add every address there too, or sign-in fails before Prometheus ever sees it.

Notes and limits

  • Scanned PDFs do not work. If the pages are images, there is no text to extract. Run OCR first.
  • PDF export goes through the browser's print dialog. That gives real, selectable text and correct pagination, which a canvas-rasterizing library does not — the trade is one extra click on "Save".
  • The runner is a single worker. Jobs run one at a time, in order. Parallel headless Claude sessions contend for the same subscription limits.
  • A 500-page book takes several minutes and burns a real slice of your subscription allowance. The runner logs the cost of each run.
  • Your subscription is for your own use. Keep the allowlist small and personal.

Licence

MIT

About

Prometheus — a private suite of AI tools. First: Socrates, a book summarizer that reads with Claude and keeps both book and summary.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages