For the next Claude Code instance (or human) picking up Plutus development. Snapshot: 2026-06-23, version 0.5.1.
The billing engine (plutus_agent) is live — on PyPI (pip install plutus-agent), GHCR, and deployed at https://plutus.perseus.observer. The self-serve loop (open signup → API key → POST /v1/usage → dashboard → Stripe upgrade) works end-to-end, and we're dogfooding it on our own Hermes spend. A deep code review is done; the path to 1.0 is in ROADMAP-1.0.md.
| Repo | Perseus-Computing-LLC/plutus (public, MIT) — plutus_agent/ is the engine; plutus.py/plutus_route.py are the original monitor |
| PyPI | plutus-agent |
| Image | ghcr.io/perseus-computing-llc/plutus:latest (built on v* tag via .github/workflows/release.yml) |
| Hosted | https://plutus.perseus.observer — container plutus on greg, media-net, port 8420, data vol /data |
| Hosted DB | /data/plutus.db in-container (PLUTUS_HOME=/data); host: /mnt/cache/appdata/plutus/data |
| Docs | README.md, docs/api.md (ingest API + SDK remote mode), docs/auth.md, docs/claude-code.md |
- v0.4.0 self-serve signup funnel · v0.5.0 ingest API (
POST /v1/usage) + API keys + SDK remote mode · v0.5.1 Cloudflare-UA fix. - Hermes spend syncs into the dashboard via
examples/hermes_sync.pyon a host-level cron (every 15 min) — seeHANDOFF-HERMES-SYNC.md. - 79 tests pass (
pytest tests/). Production monitor untouched.
The deep review filed issues #26–#38. Sequencing in ROADMAP-1.0.md:
- v0.6 — money & concurrency correctness (1.0 blocker): #26 webhook idempotency (check-then-act → double-credit), #27
/v1/usagenot atomic (partial-batch double-count), #30 sqlite concurrency (nobusy_timeout, non-atomicbalance_after, quota race), #29 credit from Stripeamount_totalnot metadata, #28 prepaid-credit hard-stop, #38 integer money. #26/#27/#30 collapse into one "make ingest + webhook atomic + busy_timeout" change — start here. - v0.7 — security hardening (gates public launch): #31 body-size cap, #32 CSRF + POST logout, #33 signup rate-limit, #34 report escaping, #35 SMTP TLS, #36 OIDC JWKS, #37 polish.
- v0.8 — Team tier ($149/mo) + LangChain/CrewAI/MCP integrations (the revenue/distribution lever; can run in parallel).
- Do not launch publicly before v0.7 — open signup + live money are exposed.
- Hermes is NOT a separate box — it's containers on greg. Reach it via
ssh greg+docker exec hermes …. State.db:/opt/data/webui/minions-hermes-config/state.db(in-container). - greg uses HOST
docker compose, not Dockge (the dockge container isn't running). Redeploy:docker compose -f /mnt/cache/appdata/stacks/plutus/compose.yaml pull/up -d --force-recreate plutus. Thegreg-deployskill'sdocker exec dockgepath does not work here. - Cloudflare blocks the default
Python-urllibUser-Agent (error 1010). Anything POSTing to the public URL with urllib must send a realUser-Agent(fixed in 0.5.1). Internal service-to-service useshttp://plutus:8420(samemedia-net), which bypasses CF. - Deployed image is still 0.5.0. The 0.5.1 UA fix is client-side, so the server needs no redeploy — but tag
v0.5.1to publish the fixed SDK to PyPI (external ingest is broken without it). Greg cron already uses the internal URL, so it's unaffected. - Unraid cron persistence: host cron lives in
/boot/config/plugins/dynamix/*.cron+update_cron→ writes/etc/cron.d/root. Plaincrontab -lreads the wrong spool; verify withcrontab -c /etc/cron.d -l. - The dogfood ingest API key lives only in the greg cron / dynamix file (and the operator's hands) — never commit it (public repo). Re-mint anytime:
docker exec plutus plutus keys create --name … --org "Perseus Computing". - Stripe is LIVE on the hosted instance. Be careful with billing-path changes.
- Branch → PR → a human merges. A safety classifier gates heavy/outward-facing actions — merging to
main, tagging/releasing, redeploying greg, and editing~/.claude/settings.jsonall require explicit per-action user authorization. Don't expect to self-merge; prepare the PR and ask. - Tests:
pytest tests/(stdlibunittest, fully offline). Keep them green. - Commit trailer:
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>. - Secrets come from env, never config/repo (
config._strip_env_secretsenforces this on save).
curl -fsS https://plutus.perseus.observer/healthz # {"ok":true,"version":"0.5.x"}
ssh greg 'docker ps --filter name=plutus --format "{{.Names}} {{.Status}}"'
cd <repo> && pytest tests/ -qOpen the v0.6 atomic-correctness PR (#26/#27/#30 together): wrap /v1/usage ingest and webhook handling in single transactions, add PRAGMA busy_timeout, and make balance_after/quota checks atomic. It's the highest-leverage pre-launch work and makes "the money is correct" true.