Skip to content

[WIP] A2: wizard 'deploy a Letta swarm' + deploy-route Letta path (stacked on #169) — do not merge#170

Closed
juniperbevensee wants to merge 1 commit into
dev/juniperbevensee/letta-a1-adapter-extractionfrom
dev/juniperbevensee/letta-a2-wizard-deploy
Closed

[WIP] A2: wizard 'deploy a Letta swarm' + deploy-route Letta path (stacked on #169) — do not merge#170
juniperbevensee wants to merge 1 commit into
dev/juniperbevensee/letta-a1-adapter-extractionfrom
dev/juniperbevensee/letta-a2-wizard-deploy

Conversation

@juniperbevensee

Copy link
Copy Markdown
Collaborator

Slice A2 of Swarm Map v1 — the core fork deliverable (spec memory/specs/2026-07-19-swarm-map-v1-definition.md §2.A2; design 2026-07-18-letta-wizard-fork-design.md §3). Stacked on #169 (A1) — do not merge until launch sequence.

What

A Letta deploy inverts the Hermes layering: bring one shared Letta server up, then create each agent over REST — no per-agent container/port/data-dir/compose.

  • lib/services/letta-deploy-templates.ts (new): ensureLettaServer() (idempotent bring-up: pull → compose up -d with --env-file → poll GET /v1/agents), defaultAgentConfig(), deployLettaAgent() (ensure-server → name-clobber check → createAgent).
  • Deploy route: runtime === 'letta' branch after key resolution; skips the whole Hermes path; validation is runtime-aware.
  • Wizard: runtime toggle (Step 1), single model-handle (Step 2), Platforms/Keys degrade to Letta notes, summary + success branch. selectRuntime() resets Hermes-only state on switch.
  • docker.ts: start() gained an optional --env-file so server-wide keys flow without mutating process.env.

memfs over memory blocks (Letta team feedback)

Cameron @ Letta flagged (2026-07-21, on the airlock-demo post) that memory_blocks is "a very old style" and modern agents use memfs (git-backed context files). So defaultAgentConfig defaults agent_type: 'letta_v1_agent' and passes persona as system; the legacy memory-blocks path is an explicit opt-in for the airlock use-case pending its memfs remap. Decision logged in org memory. Exact modern payload is a Phase-4 live-validation item — the code is honest about that boundary.

Adversarial review — 9 findings addressed

An in-loop multi-dimension review pass (seam / server-key security / Letta-API fidelity / wizard-state / test-coverage), each finding verified by an independent skeptic. All 9 confirmed findings fixed:

# Sev Fix
1 major clobber check uses server-side ?name= filter (bare list is paginated → missed collisions)
2 major Signal post-deploy connect is Hermes-gated + reset on runtime switch (no bogus connect on Letta)
3 major stale existingKeyId no longer injects a Hermes registry key into the Letta server (reset + handleDeploy branch)
4 minor writeServerEnv chmods 0600 even on overwrite (writeFileSync mode is create-only)
5 minor Letta summary no longer lists Hermes surfaces (covered by runtime-switch reset)
6–9 minor added tests: createAgent-reject 502, listAgents-fail 502, persona→system, docker --env-file argv

Verification

  • 752/752 vitest (6 new); tsc --noEmit clean
  • eslint: only the pre-existing set-state-in-effect on the unchanged checkDocker effect
  • Draft/do-not-merge: the Letta create path is mocked; live validation is Phase 4 (needs a running Letta server).

🤖 Generated with Claude Code

… Letta path

Slice A2 of Swarm Map v1 (spec §2.A2 'the core fork deliverable'; design
2026-07-18-letta-wizard-fork-design.md §3). A Letta deploy inverts the Hermes
layering: bring ONE shared Letta server up, then create each agent over REST —
no per-agent container/port/data-dir/compose.

New: lib/services/letta-deploy-templates.ts
  - ensureLettaServer(): idempotent server bring-up (pull → compose up -d with
    --env-file → poll GET /v1/agents). Server-wide provider keys written 0600 to
    ~/.hermes-swarm-map/letta/.env, merged (never blanked) across deploys.
  - defaultAgentConfig(): the base CreateAgentConfig.
  - deployLettaAgent(): ensure-server → name-clobber check → createAgent.

Deploy route: a runtime==='letta' branch after key resolution that skips the
entire Hermes path; validation is now runtime-aware.

Wizard: runtime toggle (Step 1), single model-handle input (Step 2), Platforms/
Keys degrade to Letta notes, summary + success copy branch. selectRuntime()
resets Hermes-only state on switch so it can't leak into a Letta payload.

docker.ts: start() gained an optional --env-file (top-level compose option) so
server keys flow without mutating process.env.

## memfs over memory blocks (Letta team feedback, 2026-07-21)
Letta's team flagged that the demo's memory_blocks is 'a very old style' and
modern agents use memfs (git-backed context files). defaultAgentConfig now
defaults agent_type to 'letta_v1_agent' and passes persona as `system`; the
legacy memory-blocks path is an explicit opt-in (airlock use-case, pending its
memfs remap). Exact modern payload stays a Phase-4 live-validation item.

## Addressed 9 findings from an adversarial review pass
- clobber check now uses the server-side ?name= filter (bare list is paginated)
- runtime switch resets Hermes-only state; Signal post-deploy connect + key
  registry path are Hermes-gated (no stale key/surface leak into Letta)
- writeServerEnv chmods 0600 even on overwrite (writeFileSync mode is create-only)
- added tests: createAgent-reject 502, listAgents-fail 502, persona→system,
  docker --env-file argv, name-filter clobber query

752/752 tests (6 new), tsc clean. Draft/do-not-merge; Letta create path mocked —
live validation is Phase 4.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@juniperbevensee

Copy link
Copy Markdown
Collaborator Author

A-track landed as one clean linear chain via #172 (rebase cascade from #165's SHA rewrite made per-PR merges conflict on stale spike/seam ancestors). This slice's commit is on main. See memory/plans/2026-07-22-swarm-map-v1-track.md.

@juniperbevensee
juniperbevensee deleted the dev/juniperbevensee/letta-a2-wizard-deploy branch July 22, 2026 01:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant