@letta-ai/dreams
v0.0.13
Published
Dreams CLI - shared organizational memory from coding-agent transcripts
Keywords
Readme
@letta-ai/dreams
CLI for Dream — Letta's shared organizational memory built from coding-agent transcripts.
Setup
Champion / first-time device (full setup; init snapshot encouraged):
npx @letta-ai/dreams@latest onboard --jsonMember / add another coding-agent source to an existing workspace (same local bootstrap; encourage init unless a prior init snapshot was uploaded on this device):
npx @letta-ai/dreams@latest connect --json
# alias:
npx @letta-ai/dreams@latest source add --jsonBoth onboard and connect:
- verify Node >= 22.13 through the bin preflight
- install the exact CLI version under
~/.dreams/cli/<version>/ - activate it through the stable launcher at
~/.dreams/bin/dreams - create or preserve the installation id in
~/.dreams/installation.json - install
~/.claude/skills/dreams-onboard/and~/.claude/skills/dreams-connect/(skills + shared init snapshot / hooks references) - initialize and migrate
~/.dreams/dreams.db - return a skill handoff (
status: "ready",mode: "onboard"|"connect") with absolutecli_path, mode-appropriate skill path, andlast_init_snapshot(local fact)
They do not check authentication. The dreams-onboard skill owns champion
sequencing (authenticate → detect sources → init snapshot → shared-memory
template generate/review/accept → approve directories + install consented hooks →
optional background history import). The dreams-connect skill owns
add-source sequencing and never generates or accepts the shared-memory
template. In connect mode, init follows device-local init_snapshot_policy
(stored under ~/.dreams): skip when this device uploaded init inside a 30-day
window. A new device has no local record and always encourages init; after
the window elapses, init is encouraged again. SessionStart hooks call
dreams wake; Stop hooks call dreams sync. Repeated onboard / connect
calls are safe and repair local setup only.
Commands
dreams onboard [--json]— install or repair local setup and hand off to champion / first-time setup (mode: "onboard").dreams connect [--json]— same local bootstrap; hand off to connect-source setup (mode: "connect"). Alias:dreams source add.dreams rollback [--json]— reactivate the previous completed CLI version.dreams status [--json]— installation, active and previous CLI versions, SQLite, setup skill, last init snapshot (if any), and authentication state.dreams auth login [--json]— OAuth device code sign-in (see Auth below).dreams auth status [--json]— authentication state; lists every discovered credential (env/keychain/file), which won and why, plus a hooks note that live sync inherits the harness process env; tokens are masked (at-let-…abcd), never printed.dreams auth logout [--json]— best-effort revoke of Dreams' refresh token, then clear stored credentials.dreams dev reset local [--confirm] [--json]— preview or remove only local SQLite and blob state.dreams dev reset identity [--confirm] [--json]— preview or remove local state, stored Dreams credentials, and the installation identity.dreams dev reset machine [--confirm] [--json]— full local wipe for rapid onboard retests: identity scope plus managed CLI/launcher, setup skill, and surgical removal of Dreams handlers from Claude/Codex hook configs. Still preserves Cloud data (delete the workspace separately) andLETTA_API_KEY.
Local state lives in ~/.dreams/. Requires Node >= 22.13, where built-in
node:sqlite no longer requires the --experimental-sqlite flag.
CLI upgrades and rollback
Installed CLI versions are immutable under ~/.dreams/cli/<version>/. The
atomic ~/.dreams/cli/activation.json record selects the active version and
retains one previous version. The stable launcher reads that record rather than
pointing directly at a version.
Run dreams rollback to reactivate the previous completed version. The launcher
also rolls back automatically when an active CLI cannot reach its startup
readiness marker, then retries the original command once. Normal command errors
after readiness, including invalid arguments, authentication failures, and
network failures, never trigger rollback.
Development reset
Development resets are preview-only until --confirm is provided. local
removes dreams.db, its SQLite sidecars, and ~/.dreams/blobs/; it preserves
credentials and the installation identity. identity removes those local files
plus Dreams' stored credentials and installation.json, so the next onboard
mints a new device identity. Both scopes preserve installed CLI versions, the
stable launcher, the setup skill, and every Cloud resource. Confirmed resets
hold the same local-state lock as onboarding, auth, source, and upload commands,
so they fail instead of deleting files another process is using. If
DREAMS_CREDENTIALS_BACKEND=file is forced, identity reset clears the file and
explicitly reports that the OS keychain was not checked.
Test-workspace cleanup is intentionally not available through this local CLI.
It is a separate internal Cloud operation with different credentials and data
cleanup semantics. dreams dev reset test-workspace fails without deleting
anything.
Local sources (Claude Code and Codex)
The CLI maintains a crash-safe local SQLite store (~/.dreams/dreams.db) that
discovers coding-agent transcripts and prepares immutable upload segments before
they are sent to Letta Cloud. Harness behavior is selected with
--source <type> (claude-code default; codex). One invocation always
targets a single source — it never processes all sources at once.
dreams source add [--json]— alias fordreams connect(member add-source handoff).dreams source detect [--source <type>] [--json]— detect a harness from filesystem facts only (~/.claudeor~/.codex; no transcript reads) and register an installation-scoped Cloud source in statusdetected. Idempotent; does not scan or upload.dreams source approve-dir <path> [--json](alias:approve-root) — approve a work directory. Sources are deny-by-default: no transcript bytes are queued until their working directory is under an approved folder (.dreamignorestill applies).dreams source scan [--source <type>] [--json]— discover sessions for the selected source (Claude:~/.claude/projects/...; Codex:~/.codex/sessions/YYYY/MM/DD/rollout-*.jsonl), read only complete new lines after the durable cursor, and enqueue deterministic upload segments. Repeated scans are idempotent.dreams source list [--json]— show the DB path, approved directories, sources, and the pending upload queue.dreams snapshots create --type <type> --file <path> --client-request-id <id> [--workspace-id <id>] [--json]— submit a skill-authored JSON snapshot (256 KiB UTF-8 object cap) toPOST /v1/dreams/workspaces/{workspaceId}/snapshots. Workspace defaults to the local binding fromsource detect.dreams template status [--workspace-id <id>] [--json]— show the current shared-memory template review state.dreams template generate [--feedback "..."] [--workspace-id <id>] [--json]— generate or regenerate the mutable shared-memory template (long-running).dreams template accept --sha256 <hex> [--workspace-id <id>] [--json]— accept a ready template and materialize shared memory.dreams hooks install [--source <type>] [--dry-run] [--json]— install or preview Claude Code / Codex live-sync hooks. SessionStart →wake, Stop →sync. Prefer--dry-runfor consent before writing.dreams wake [--source <type>] [--json]— SessionStart entrypoint: quiet managed CLI/skill repair, then force-kick the sync worker for pending live/backfill drain (no stdin session hint). Always exits 0 for hook safety.dreams sync [--source <type>] [--force] [--json]— Stop / live-turn scheduler for one source: records a durable sync trigger (optional stdinsession_id) and runs a detached worker that live-scans tracked sessions and uploads with a per-pass budget (~3h cadence unless--forceor retry-due).dreams sync pause|resume [--json]— global pause makes hook wakes no-ops; resume clears pause and requests one immediate sync (not per-source).dreams sync status [--source <type>] [--json]— per-source diagnostics (effective_state, cadence/retry, worker). Codex status also reports discovery health (discovery.status/ reason codes) when rollout formats drift.dreams backfill start --since <RFC3339> [--source <type>] [--json]— approve a frozen[since, until=now]historical window for one source and run one bounded local scan/queue pass (session frontier, newest unfinished sessions first; no upload). Policies are source-isolated. Re-running the same active--sinceis idempotent; a different active policy fails closed. Afterbackfill start, kick withdreams wake --source …so draining does not wait for the next session.
Local cursors track a queued_through_offset (advanced as segments are queued)
separately from an acked_offset (advanced only after durable Cloud
acceptance, in a later step).
Auth
dreams auth login runs Letta's OAuth 2.0 Device Code Flow against
https://app.letta.com (override with LETTA_AUTH_BASE_URL; the API host is
https://api.letta.com, override with LETTA_BASE_URL):
- The CLI requests a device + user code and prints a verification URL.
- The user approves in the browser; the CLI polls the token endpoint
(handling
authorization_pending,slow_down,access_denied,expired_token) until it receives an access token (at-let-…, ~30 days) and a refresh token (rt-let-…, 1 year). - In
--jsonmode,auth loginemits two JSON lines on stdout: first{"status":"awaiting_approval",…}(show the user the URL/code), then{"status":"authenticated",…}after approval.
Storage. Credentials go to the OS keychain via @napi-rs/keyring
(an optional dependency — the CLI keeps zero hard runtime deps), service
letta-dreams, accounts refresh-token and access-token. When the keychain
is unavailable, the CLI falls back to ~/.dreams/credentials.json, written
atomically with mode 0600 (a one-line stderr warning notes the fallback).
Tokens are never written to local setup state or logs, and status output always
masks them. DREAMS_CREDENTIALS_BACKEND=file|keychain forces a backend
(tests use file).
Precedence when resolving an auth header (getAuthHeader() in
src/auth/index.ts):
LETTA_API_KEYenv var — used verbatim, never refreshed, never stored.- Stored Dreams credentials — the access token is refreshed automatically when it is missing or expires within 5 minutes.
- Otherwise: a structured not-authenticated error (
dreams auth login).
dreams auth status --json reports that inventory explicitly: top-level
source / access_token remain the winner for this process; credentials[]
lists each backend with present, selected, and reason; active restates
the winner; hooks notes that coding-agent hooks inherit the harness
environment (a harness-set LETTA_API_KEY shadows stored OAuth).
Refresh rotation. Refreshes use refresh_token_mode: "new": the server
always returns a new refresh token that revokes the old one for this
(user, client, device). The CLI persists the rotated token immediately and
atomically before using the new access token, singleflights concurrent
in-process refreshes, and holds a lockfile (~/.dreams/auth.lock, stale
after 30s) so two dreams processes on one machine cannot interleave
rotate-then-persist. A refresh failing with invalid_grant (stale rotated
token) clears stored credentials.
Why Dreams does not reuse letta-code's keychain entries. Dreams shares
letta-code's public client id, but deliberately keeps its own credentials
(service letta-dreams vs letta-code) and its own device_id (the Dreams
installation_id). Rotation is scoped per (user, client, device): if both
CLIs shared one refresh token, each refresh by one tool would revoke the
token out from under the other (rotation collision). Separate device ids
guarantee the two token chains never collide, and dreams auth logout can
never revoke letta-code's session.
Development
npm install
npm run dev -- onboard --json # run from source via tsx
npm run typecheck
npm run build # compile to dist/
npm test # build + node:test suite (uses a temp HOME)Testing the npx bootstrap via tarball (no publish)
npm pack # produces letta-ai-dreams-0.0.3.tgz
cd "$(mktemp -d)"
npx -y -p /absolute/path/to/dreams/letta-ai-dreams-0.0.3.tgz dreams onboard(The -p <tarball> dreams form is required: a bare npx <tarball> treats the
path as a script to execute, not a package to install.)
onboard writes to ~/.dreams/ and installs
~/.claude/skills/dreams-onboard/ and ~/.claude/skills/dreams-connect/
(including the init snapshot template). Set HOME to a temporary directory for
a sandboxed run.
Deferred
- Default Dream schedule creation
- Broader Cloud-side template regeneration UX beyond the CLI review loop
