[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
Conversation
… 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>
Collaborator
Author
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Slice A2 of Swarm Map v1 — the core fork deliverable (spec
memory/specs/2026-07-19-swarm-map-v1-definition.md§2.A2; design2026-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 -dwith--env-file→ pollGET /v1/agents),defaultAgentConfig(),deployLettaAgent()(ensure-server → name-clobber check →createAgent).runtime === 'letta'branch after key resolution; skips the whole Hermes path; validation is runtime-aware.selectRuntime()resets Hermes-only state on switch.docker.ts:start()gained an optional--env-fileso server-wide keys flow without mutatingprocess.env.memfs over memory blocks (Letta team feedback)
Cameron @ Letta flagged (2026-07-21, on the airlock-demo post) that
memory_blocksis "a very old style" and modern agents use memfs (git-backed context files). SodefaultAgentConfigdefaultsagent_type: 'letta_v1_agent'and passes persona assystem; 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:
?name=filter (bare list is paginated → missed collisions)existingKeyIdno longer injects a Hermes registry key into the Letta server (reset + handleDeploy branch)writeServerEnvchmods 0600 even on overwrite (writeFileSync mode is create-only)--env-fileargvVerification
tsc --noEmitcleanset-state-in-effecton the unchangedcheckDockereffect🤖 Generated with Claude Code