docs(handoff): 2026-05-02 — state after 1.5.0 + v0.2.0 backend
Three pending sessions ranked by leverage: ship 1.6.0 npm release, fix migration drift, build web chat UI.
This commit is contained in:
106
.artifacts/specs/2026-05-02-handoff.md
Normal file
106
.artifacts/specs/2026-05-02-handoff.md
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
# claudemesh handoff — 2026-05-02
|
||||||
|
|
||||||
|
State of the world after a long session that shipped 1.5.0 and the v0.2.0 backend. Read this before the next session — it captures what's done, what's deployed where, what's not, and the architectural decisions worth knowing.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Where things stand
|
||||||
|
|
||||||
|
### Released to npm
|
||||||
|
- **`claudemesh-cli@1.5.0`** (latest tag, published earlier today). CLI-first architecture lock-in: zero-tool MCP, policy engine, bundled `claudemesh` skill. Verified install + smoke-tested via clean `npm i -g`.
|
||||||
|
|
||||||
|
### In `main` but NOT released yet
|
||||||
|
Everything below is committed, deployed to the broker (`wss://ic.claudemesh.com/ws`) and the web app (Vercel `claudemesh.com`), but **`claudemesh-cli@1.5.0` on npm doesn't have any of it**. Users won't see it until v1.6.0 publishes.
|
||||||
|
|
||||||
|
| Feature | Code path | Verified live? |
|
||||||
|
|---|---|---|
|
||||||
|
| Topics (schema, broker routing, CLI verbs, skill) | `packages/db/src/schema/mesh.ts`, `apps/broker/src/broker.ts`, `apps/cli/src/commands/topic.ts` | ✅ created `#deploys-test`, sent + persisted |
|
||||||
|
| `apikey create/list/revoke` (CLI + broker WS) | `apps/cli/src/commands/apikey.ts`, broker dispatch | ✅ full lifecycle exercised |
|
||||||
|
| REST `/api/v1/*` (messages, topics, peers, history) | `packages/api/src/modules/mesh/v1-router.ts` + `api-key-auth.ts` | ✅ posted via curl, history round-trips |
|
||||||
|
| Bridge peer (SDK + CLI) | `packages/sdk/src/bridge.ts`, `apps/cli/src/commands/bridge.ts` | ⚠️ code only — never run end-to-end |
|
||||||
|
|
||||||
|
### Architectural commitments locked this session
|
||||||
|
- **CLI-first, MCP push-pipe** (1.5.0): MCP `tools/list = []`. Inbound peer messages still arrive as `experimental.claude/channel` notifications. The bundled skill is the sole CLI-discoverability surface for Claude.
|
||||||
|
- **Topics complement groups, don't replace them** (v0.2.0): mesh = trust boundary, group = identity tag, topic = conversation scope. Three orthogonal axes.
|
||||||
|
- **Humans use REST + apikey, not browser WS** (v0.2.0): the broker already plumbs `peer_type: "human"`. The real blocker was browser-side ed25519, which we sidestep by exposing REST. Web chat UI = thin client over `/v1/*` using dashboard session auth.
|
||||||
|
- **Spec lives at**: `.artifacts/specs/2026-05-02-architecture-north-star.md` (1.5.0) and `.artifacts/specs/2026-05-02-v0.2.0-scope.md` (v0.2.0 cut + design sketches).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Three pending sessions, ranked by leverage
|
||||||
|
|
||||||
|
### Session A — Ship v1.6.0 npm release (~30 min, highest leverage)
|
||||||
|
**Why first**: backend is feature-complete but unreleased. Users still get the no-topics 1.5.0.
|
||||||
|
|
||||||
|
Steps:
|
||||||
|
1. Bump `apps/cli/package.json` 1.5.0 → 1.6.0.
|
||||||
|
2. Update `apps/cli/README.md` migration note (mention topics, apikey, bridge).
|
||||||
|
3. Add `## v1.6.0` section to `docs/roadmap.md`.
|
||||||
|
4. Build + verify: `cd apps/cli && pnpm build && node dist/entrypoints/cli.js --version`.
|
||||||
|
5. `npm publish --tag latest --access public --no-git-checks --ignore-scripts`.
|
||||||
|
6. `git tag cli-v1.6.0 && git push github cli-v1.6.0` — workflow builds 5 binaries + auto-bumps Homebrew/winget tap.
|
||||||
|
7. Verify on a clean prefix: `PREFIX=/tmp/cm16 mkdir -p $PREFIX && npm install -g --prefix $PREFIX claudemesh-cli@1.6.0 && $PREFIX/bin/claudemesh --help | grep -E "topic|apikey|bridge"`.
|
||||||
|
|
||||||
|
### Session B — Migration drift fix (~1 day, highest pain reduction)
|
||||||
|
**Why second**: every schema change today requires manual `psql -f migration.sql` against prod. The drizzle `_journal.json` stops at idx 11, runtime migrator silently skips anything not in journal. Today's `0022_topics.sql` and `0023_api_keys.sql` were applied by hand. **Future migrations will keep needing this until fixed.**
|
||||||
|
|
||||||
|
Recommended approach:
|
||||||
|
1. Replace `drizzle-orm/postgres-js/migrator` in `apps/broker/src/migrate.ts` with a custom runner.
|
||||||
|
2. Scan `migrations/*.sql` lexicographically (already named `NNNN_*.sql`).
|
||||||
|
3. Track applied filenames in a new `mesh.__cmh_migrations` table (filename + sha256 + applied_at).
|
||||||
|
4. On startup: filter unapplied files, run them in transaction order under `pg_try_advisory_lock`. Fail loud on hash mismatch (catches edits after deploy).
|
||||||
|
5. Backfill the table with all 0000-0023 entries one-time so prod is consistent.
|
||||||
|
6. Drop the drizzle journal usage entirely (`migrations/meta/_journal.json` becomes dead state).
|
||||||
|
|
||||||
|
This unblocks every future feature touching DB.
|
||||||
|
|
||||||
|
### Session C — Web chat UI (~2-3 days, highest visibility)
|
||||||
|
**Why third**: the demo. Backend is ready; this is pure React + REST.
|
||||||
|
|
||||||
|
Path: `apps/web/src/app/[locale]/dashboard/(user)/meshes/[id]/topics/[name]/page.tsx` (new).
|
||||||
|
|
||||||
|
Components needed:
|
||||||
|
- Topic header (members count, settings button).
|
||||||
|
- Message stream — `GET /api/v1/topics/:name/messages?limit=50`. Poll every 5s for new (no WS yet — REST polling is fine for v0.2.0).
|
||||||
|
- Compose box — `POST /api/v1/messages` with `{topic, ciphertext, nonce}`.
|
||||||
|
- Members sidebar — `GET /api/v1/peers`.
|
||||||
|
- Apikey lifecycle: on first load, server-side issue an apikey for the dashboard user (using their existing NextAuth session) scoped to `read,send` on this topic. Stash in browser session storage.
|
||||||
|
|
||||||
|
Server-side helper for apikey issuance lives in `packages/api/src/modules/mesh/api-key-auth.ts` — refactor `verifyBearer` to also expose a `createApiKeyForUser(userId, meshId, scope)` helper for the dashboard handler.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Three less-urgent followups (don't block sessions A-C)
|
||||||
|
|
||||||
|
1. **Bridge end-to-end smoke test**: never actually run between two meshes. Needs second test mesh + bridge member onboarding ritual. Worth doing before any blog post / external demo.
|
||||||
|
2. **`/v1/peers` includes only WS-connected agents**, not humans (since humans are REST-only and never appear in `presence`). Decide: synthetic presence rows for active apikey sessions? Or document that `/v1/peers` is "agents online"?
|
||||||
|
3. **Topic ciphertext is plaintext base64** in the current implementation — no actual encryption. The schema names it `ciphertext` for forward-compat, but the code base64-encodes UTF-8. Real per-topic symmetric key derivation (HKDF from mesh root_key + topic_id) is a v0.3.0 item.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Production state worth knowing
|
||||||
|
|
||||||
|
- **Broker**: `wss://ic.claudemesh.com/ws`, deployed via Coolify on OVHcloud VPS. Auto-redeploys on push to `gitea-vps main`. Deploy ETA ~3 min.
|
||||||
|
- **Web**: `claudemesh.com`, Vercel auto-deploy on push to `github main`. Deploy ETA ~2 min.
|
||||||
|
- **Postgres**: container `eo1f5gydsgrg19b57e9s4zw7` on the VPS. SSH via `ssh ovh`, then `docker exec eo1f5gydsgrg19b57e9s4zw7 psql -U claudemesh -d claudemesh`.
|
||||||
|
- **Test mesh**: `openclaw` on the same broker has 5 active peers and one topic (`#deploys-test`).
|
||||||
|
- **Active apikey** (from earlier today's smoke): `cm_OC12dRti…` was revoked. None active right now.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Files most worth reading first in next session
|
||||||
|
|
||||||
|
1. `.artifacts/specs/2026-05-02-architecture-north-star.md` — the 7 architectural commitments.
|
||||||
|
2. `.artifacts/specs/2026-05-02-v0.2.0-scope.md` — design sketches for topics, REST, bridge.
|
||||||
|
3. `apps/cli/skills/claudemesh/SKILL.md` — the canonical CLI surface; ships in npm tarball.
|
||||||
|
4. This file.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Memory not yet captured
|
||||||
|
|
||||||
|
Worth adding to `~/.claude/projects/-Users-agutierrez-Desktop-claudemesh/memory/MEMORY.md` next session:
|
||||||
|
|
||||||
|
- **Drizzle journal drift is a recurring trap** — manual psql until session B lands. Save the exact apply ritual: `scp migrations/NNNN.sql ovh:/tmp/ && ssh ovh "docker cp /tmp/NNNN.sql <pg-container>:/tmp/ && docker exec <pg-container> psql -U claudemesh -d claudemesh -f /tmp/NNNN.sql"`.
|
||||||
|
- **`workspace:*` deps break `npm publish`** — keep SDK as devDependency in `apps/cli/package.json`; Bun bundles it into dist so runtime doesn't need it. Same trick for any other workspace-only build deps.
|
||||||
|
- **Commitlint hard-caps body lines at 100 chars** — use `git commit -F /tmp/cm-commit.txt` rather than `-m` heredocs. Heredocs that exceed the limit fail the husky hook silently.
|
||||||
Reference in New Issue
Block a user