Headlong Letta #
Headlong Letta runs one persistent local Letta agent on an adaptive wake loop. Letta owns the identity, memory, conversation, model, tools, and permission enforcement. The TypeScript controller owns wake timing, local state mapping, backoff, and content-dark receipts.
The repository began from Headlong at commit d8f83042c30ba34931259408077ead20e6bd93c3. The original implementation was removed. Its Apache 2.0 license and Git history remain.
Run it #
Requirements:
- Node.js 22.19 or newer
- local Letta Code credentials for xAI
xai/grok-4.6listed as available by the local model catalog
Install and verify the runtime:
npm ci
npm run check
npm start -- models | grep 'xai/grok-4.6'
Create the agent once, then send a message or one autonomous wake:
npm start -- init
npm start -- send 'Inspect this repository and explain what you own.'
npm start -- wake 'Check whether one bounded task is worth doing.'
Run the adaptive loop in the foreground:
npm start -- loop
init persists one agent ID and one dedicated conversation ID under .headlong-letta/state.json. Before creating an agent without state, it searches for one exact tagged identity and recovers it; multiple candidates fail closed. Later commands resume both IDs. The directory is ignored by Git and written with user-only permissions.
What the controller owns #
| Concern | Owner |
|---|---|
| Identity, memory, conversation history | Letta agent |
| Model, tools, and runtime permission mode | Letta local backend |
| Wake trigger and adaptive delay | Controller |
| Agent and conversation ID mapping | Controller state |
| Send correlation and ambiguous-failure handling | Controller receipts |
| Event and effect evidence | Controller receipts |
Each wake asks the agent to choose one bounded function: act, think, or idle. Passing is valid. The final line must use this envelope:
HEADLONG_OUTCOME {"kind":"acted|thought|idle","summary":"one short factual summary"}
Acted work resets backoff. Thought-only and idle wakes descend through a capped exponential schedule. Three outcomes at one level trigger the next level by default.
Permission policy #
The default acceptEdits mode supports repository work while the SDK callback resolves headless approval requests conservatively:
- local
Read,Glob,Grep, andViewImageapprovals are allowed; - web reads require
HEADLONG_LETTA_ALLOW_NETWORK_READS=1; - other approval requests are denied;
unrestrictedrequires bothHEADLONG_LETTA_PERMISSION_MODE=unrestrictedandHEADLONG_LETTA_ALLOW_UNRESTRICTED=1.
The harness can approve file edits under acceptEdits. Shell commands, outbound communication, and other effects do not inherit permission from the wake loop. Run strict mode to deny every unattended approval.
The SDK approval callback only sees requests the runtime submits. The local runtime can execute tools such as shell commands without ever submitting an approval request, so callback denials do not guarantee prevention. After each turn completes, the controller checks the sanitized tool-call names against the same policy classification that drives the callback. A turn that executed any disallowed tool fails even if the runtime reported success, and its receipt records a policyViolation entry with the tool names. This is detection after execution; it does not prevent or undo the effect.
Backends #
HEADLONG_LETTA_BACKEND=local (default) runs the in-process local Letta Code runtime exactly as before.
HEADLONG_LETTA_BACKEND=cloud targets one existing Letta Cloud agent given by HEADLONG_LETTA_AGENT_ID. Cloud mode never discovers or creates agents; it idempotently creates on first use and later resumes one dedicated conversation on that agent, persisted under the controller home (use a separate HEADLONG_LETTA_HOME, for example .headlong-letta-cloud). Sessions pass HEADLONG_LETTA_MODEL (for example letta/auto) as a conversation-scoped override — Agent SDK 0.7.6 scopes session model options to the conversation, so Loop's global default is never mutated. Init asserts the conversation reports the configured model and fails closed otherwise.
Cloud authentication comes from LETTA_API_KEY or LETTA_CLOUD_API_KEY. Agent SDK 0.7.6 resolves credentials from an explicit key, an Authorization header, or these environment variables only; it does not fall back to Letta CLI login state. Initialization fails with a clear message when neither variable is set. Key values are never printed or written to artifacts.
With no computer selected, the SDK provisions a managed Cloud sandbox scoped to the conversation. The controller's laptop filesystem is not mounted. The session working directory is fixed at /root/workspace/headlong-letta, and each autonomous wake instructs the agent to clone https://tangled.org/cameron.stream/headlong-letta there if absent and to never push. The clone reflects the published remote state only: uncommitted local work never appears in the sandbox, and sandbox changes are not synced back automatically.
The managed sandbox is the isolation boundary for Cloud runs. Explicitly unrestricted mode (both environment opt-ins) genuinely authorizes gate decisions and post-hoc execution classification there; local defaults remain acceptEdits. Manifests and receipts record the backend and an observed-working-directory hash so the runtime environment stays auditable.
Receipts #
Each turn creates the following local files under .headlong-letta/runs/{run-id}/:
manifest.json: intended backend, model, policy, working-directory hash, and input hash;events.jsonl: event types, IDs, byte counts, and structural key lists;receipt.json: terminal or reconciled completion, conversation readback, outcome, next delay, and structuredpolicyViolationevidence when detected.
Prompts, model output, tool output, environment values, and credentials stay out of these files. Unknown SDK event types are retained by type, key list, and payload byte count.
The controller prefers an SDK terminal result. The current local runtime can return to WAITING_ON_INPUT without emitting that event. After a five-second grace period, the compatibility path requires all of the following evidence before reporting success:
- The device reports no active processing.
- Conversation readback contains the turn's offline threading ID (OTID).
- Persisted assistant text after that user message matches the complete streamed assistant text.
- Streamed assistant output is nonempty.
- Autonomous output contains a valid
HEADLONG_OUTCOMEenvelope.
The receipt marks this path as reconciled-runtime-idle and records sdkTerminalResult: false. A live Grok 4.6 example is retained at docs/receipts/2026-08-25-live-wake.json.
Failure behavior #
- A failed send triggers conversation readback with the same OTID. The controller never retries when readback finds it.
- A stream that ends without
resultand without the idle reconciliation evidence fails. - A turn-wide timeout aborts the session and records
retryAuthorized: false. - A turn that executed a tool outside the configured policy fails after completion and records the tool names in its receipt. Detection is post hoc and cannot prevent or undo execution.
- A process lock rejects concurrent turns and reclaims a dead owner's stale lock.
- Controller recovery never clears conversation state.
See docs/architecture.md for the state machine and evidence contracts.
Configuration #
| Variable | Default | Effect |
|---|---|---|
HEADLONG_LETTA_BACKEND |
local |
local or cloud runtime selection |
HEADLONG_LETTA_AGENT_ID |
unset | Existing agent ID; required for cloud |
HEADLONG_LETTA_MODEL |
xai/grok-4.6 |
Exact local model handle |
HEADLONG_LETTA_HOME |
$PWD/.headlong-letta |
Controller state and receipts |
HEADLONG_LETTA_CWD |
process working directory | Agent workspace |
HEADLONG_LETTA_PERMISSION_MODE |
acceptEdits |
Letta permission mode |
HEADLONG_LETTA_ALLOW_NETWORK_READS |
unset | Set to 1 for web-read approvals |
HEADLONG_LETTA_ALLOW_UNRESTRICTED |
unset | Second opt-in for unrestricted mode |
HEADLONG_LETTA_BACKOFF_BASE_MS |
5000 |
First nonzero idle delay |
HEADLONG_LETTA_BACKOFF_FACTOR |
2 |
Delay multiplier |
HEADLONG_LETTA_BACKOFF_CAP_MS |
300000 |
Maximum idle delay |
HEADLONG_LETTA_BACKOFF_HOLD |
3 |
Outcomes before descending |
HEADLONG_LETTA_THOUGHT_CAP_MS |
60000 |
Maximum thought-only delay |
HEADLONG_LETTA_TURN_TIMEOUT_MS |
600000 |
Authoritative turn timeout |
HEADLONG_LETTA_TERMINAL_GRACE_MS |
5000 |
Idle reconciliation grace period |
The SDK App Server request timeout is always longer than the controller's turn deadline plus terminal grace. The controller owns turn cancellation; the transport timeout cannot preempt a valid multi-step tool turn.
Runtime versions #
The package pins Agent SDK 0.7.6 and overrides its Letta Code dependency to 0.30.32. Agent SDK 0.7.6 declares Letta Code 0.30.28, whose local model catalog does not contain xai/grok-4.6. The override supplies the requested model and is covered by the repository tests plus the retained live receipt.
npm audit currently reports three high-severity findings through the Agent SDK dependency tree. The root advisory covers inherited libvips vulnerabilities in sharp <0.35.0; npm reports no available fix. Review the audit before using the loop on an exposed or multi-user host.
Development #
Run the deterministic gates:
npm run check
The suite covers state persistence, controller locking, model and permission configuration, backoff, unknown events, OTID reconciliation, terminal results, missing-result compatibility, ambiguous sends, and receipt redaction.
- TypeScript 94%
- JavaScript 6%