@letta-ai/letta-code 0.34.25 → 0.34.27

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (156) hide show
  1. package/cursor-worker.js +168 -0
  2. package/dist/agent-presets.js +5 -68
  3. package/dist/agent-presets.js.map +2 -2
  4. package/dist/channels-slack.js +30 -24
  5. package/dist/channels-slack.js.map +3 -3
  6. package/dist/mcp-client.js +233 -75
  7. package/dist/mcp-client.js.map +9 -9
  8. package/dist/mcp-oauth.js +257 -89
  9. package/dist/mcp-oauth.js.map +12 -11
  10. package/dist/memory-confinement.js +109 -51
  11. package/dist/memory-confinement.js.map +9 -8
  12. package/dist/types/agent/mcp-originator-authority-file.d.ts +1 -0
  13. package/dist/types/agent/mcp-originator-authority-file.d.ts.map +1 -1
  14. package/dist/types/agent/memory-filesystem.d.ts +3 -3
  15. package/dist/types/agent/memory-filesystem.d.ts.map +1 -1
  16. package/dist/types/agent/memory-git.d.ts +2 -2
  17. package/dist/types/agent/memory-git.d.ts.map +1 -1
  18. package/dist/types/agent/skills.d.ts +3 -3
  19. package/dist/types/agent/skills.d.ts.map +1 -1
  20. package/dist/types/agent/subagents/index.d.ts +8 -0
  21. package/dist/types/agent/subagents/index.d.ts.map +1 -1
  22. package/dist/types/agent/subagents/manager.d.ts.map +1 -1
  23. package/dist/types/agent/subagents/memory-worker.d.ts +2 -8
  24. package/dist/types/agent/subagents/memory-worker.d.ts.map +1 -1
  25. package/dist/types/agent/subagents/subagent-launcher.d.ts.map +1 -1
  26. package/dist/types/backend/api/providers.d.ts +8 -2
  27. package/dist/types/backend/api/providers.d.ts.map +1 -1
  28. package/dist/types/backend/api/schedules.d.ts +16 -2
  29. package/dist/types/backend/api/schedules.d.ts.map +1 -1
  30. package/dist/types/backend/backend.d.ts +5 -2
  31. package/dist/types/backend/backend.d.ts.map +1 -1
  32. package/dist/types/backend/dev/fake-headless-backend.d.ts +2 -1
  33. package/dist/types/backend/dev/fake-headless-backend.d.ts.map +1 -1
  34. package/dist/types/backend/dev/pi-model-factory.d.ts.map +1 -1
  35. package/dist/types/backend/local/local-provider-auth-store.d.ts +2 -0
  36. package/dist/types/backend/local/local-provider-auth-store.d.ts.map +1 -1
  37. package/dist/types/backend/local/local-transcript-history.d.ts +10 -0
  38. package/dist/types/backend/local/local-transcript-history.d.ts.map +1 -0
  39. package/dist/types/backend/local/local-transcript.d.ts +6 -0
  40. package/dist/types/backend/local/local-transcript.d.ts.map +1 -1
  41. package/dist/types/channels/slack/attachment-primitives.d.ts +2 -1
  42. package/dist/types/channels/slack/attachment-primitives.d.ts.map +1 -1
  43. package/dist/types/channels/types.d.ts +1 -1
  44. package/dist/types/cli/helpers/chunk-log.d.ts.map +1 -1
  45. package/dist/types/cli/subcommands/mcp.d.ts +2 -2
  46. package/dist/types/cli/subcommands/mcp.d.ts.map +1 -1
  47. package/dist/types/cron/cron-file.d.ts.map +1 -1
  48. package/dist/types/cron/process-identity.d.ts.map +1 -1
  49. package/dist/types/cron/run-log.d.ts +1 -0
  50. package/dist/types/cron/run-log.d.ts.map +1 -1
  51. package/dist/types/headless-environment-response.d.ts +27 -0
  52. package/dist/types/headless-environment-response.d.ts.map +1 -1
  53. package/dist/types/hooks/loader.d.ts.map +1 -1
  54. package/dist/types/mods/paths.d.ts +3 -3
  55. package/dist/types/mods/paths.d.ts.map +1 -1
  56. package/dist/types/permissions/agent-memory-prefixes.d.ts.map +1 -1
  57. package/dist/types/permissions/analyzer.d.ts +1 -0
  58. package/dist/types/permissions/analyzer.d.ts.map +1 -1
  59. package/dist/types/permissions/cross-agent-guard.d.ts.map +1 -1
  60. package/dist/types/permissions/loader.d.ts +2 -1
  61. package/dist/types/permissions/loader.d.ts.map +1 -1
  62. package/dist/types/permissions/sandbox-policy.d.ts +9 -7
  63. package/dist/types/permissions/sandbox-policy.d.ts.map +1 -1
  64. package/dist/types/providers/byok-providers.d.ts +14 -0
  65. package/dist/types/providers/byok-providers.d.ts.map +1 -1
  66. package/dist/types/sandbox/bwrap.d.ts +2 -2
  67. package/dist/types/sandbox/bwrap.d.ts.map +1 -1
  68. package/dist/types/sandbox/policy.d.ts +20 -3
  69. package/dist/types/sandbox/policy.d.ts.map +1 -1
  70. package/dist/types/sandbox/seatbelt.d.ts +1 -1
  71. package/dist/types/sandbox/seatbelt.d.ts.map +1 -1
  72. package/dist/types/settings-manager.d.ts +4 -12
  73. package/dist/types/settings-manager.d.ts.map +1 -1
  74. package/dist/types/tools/commit-trailer.d.ts +27 -0
  75. package/dist/types/tools/commit-trailer.d.ts.map +1 -0
  76. package/dist/types/tools/impl/claude-stream-session.d.ts.map +1 -1
  77. package/dist/types/tools/impl/codex-app-server.d.ts +2 -0
  78. package/dist/types/tools/impl/codex-app-server.d.ts.map +1 -1
  79. package/dist/types/tools/impl/cursor-session.d.ts +28 -0
  80. package/dist/types/tools/impl/cursor-session.d.ts.map +1 -0
  81. package/dist/types/tools/impl/cursor-worker.d.ts +35 -0
  82. package/dist/types/tools/impl/cursor-worker.d.ts.map +1 -0
  83. package/dist/types/tools/impl/external-coding-agent-task.d.ts.map +1 -1
  84. package/dist/types/tools/impl/external-coding-agent.d.ts +1 -1
  85. package/dist/types/tools/impl/external-coding-agent.d.ts.map +1 -1
  86. package/dist/types/tools/impl/memory-task-lifecycle.d.ts +2 -2
  87. package/dist/types/tools/impl/memory-task-lifecycle.d.ts.map +1 -1
  88. package/dist/types/tools/impl/overflow.d.ts +1 -1
  89. package/dist/types/tools/impl/overflow.d.ts.map +1 -1
  90. package/dist/types/tools/impl/remote-external-coding-agent.d.ts.map +1 -1
  91. package/dist/types/tools/impl/ripgrep-manager.d.ts.map +1 -1
  92. package/dist/types/tools/impl/send-agent-message.d.ts.map +1 -1
  93. package/dist/types/tools/impl/shell-env.d.ts.map +1 -1
  94. package/dist/types/tools/impl/task.d.ts.map +1 -1
  95. package/dist/types/tools/impl/wake.d.ts.map +1 -1
  96. package/dist/types/tools/script-tool-scope.d.ts.map +1 -1
  97. package/dist/types/tools/tool-definitions.d.ts.map +1 -1
  98. package/dist/types/tools/workflow/sdk-spawner.d.ts.map +1 -1
  99. package/dist/types/utils/fs.d.ts +5 -1
  100. package/dist/types/utils/fs.d.ts.map +1 -1
  101. package/dist/types/utils/local-backend-paths.d.ts +1 -1
  102. package/dist/types/utils/local-backend-paths.d.ts.map +1 -1
  103. package/dist/types/utils/native-cli-env.d.ts +3 -0
  104. package/dist/types/utils/native-cli-env.d.ts.map +1 -0
  105. package/dist/types/utils/process-liveness.d.ts +9 -0
  106. package/dist/types/utils/process-liveness.d.ts.map +1 -1
  107. package/dist/types/utils/secrets.d.ts +1 -1
  108. package/dist/types/utils/secrets.d.ts.map +1 -1
  109. package/dist/types/utils/settings-path.d.ts +14 -0
  110. package/dist/types/utils/settings-path.d.ts.map +1 -0
  111. package/dist/types/utils/transcript-paths.d.ts +1 -1
  112. package/dist/types/websocket/listener/constants.d.ts +6 -0
  113. package/dist/types/websocket/listener/constants.d.ts.map +1 -1
  114. package/dist/types/websocket/listener/input-disposition-path.d.ts.map +1 -1
  115. package/dist/types/websocket/listener/interrupted-turn-storage.d.ts.map +1 -1
  116. package/dist/types/websocket/listener/org-credentials.d.ts.map +1 -1
  117. package/dist/types/websocket/listener/remote-settings.d.ts +2 -2
  118. package/dist/types/websocket/listener/remote-settings.d.ts.map +1 -1
  119. package/dist/types/websocket/listener/turn-finished-replay.d.ts +1 -0
  120. package/dist/types/websocket/listener/turn-finished-replay.d.ts.map +1 -1
  121. package/letta.js +5769 -4506
  122. package/npm-shrinkwrap.json +293 -115
  123. package/package.json +6 -3
  124. package/scripts/agent-watch/verify-pr-identity.test.ts +148 -0
  125. package/scripts/agent-watch/verify-pr-identity.ts +72 -14
  126. package/scripts/claude-watch/agent-watch.ts +8 -2
  127. package/scripts/claude-watch/release-source.test.ts +120 -0
  128. package/scripts/claude-watch/release-source.ts +79 -9
  129. package/scripts/codex-watch/agent-watch.ts +2 -2
  130. package/scripts/codex-watch/release-analysis.test.ts +112 -6
  131. package/scripts/codex-watch/release-analysis.ts +63 -6
  132. package/scripts/isolated-unit-tests.json +10 -0
  133. package/scripts/source-file-size-baseline.json +5 -4
  134. package/scripts/test-home-preload.ts +1 -0
  135. package/skills/acquiring-skills/SKILL.md +4 -4
  136. package/skills/creating-mods/SKILL.md +3 -3
  137. package/skills/creating-mods/references/analysis-mode.md +7 -5
  138. package/skills/creating-mods/references/architecture.md +2 -2
  139. package/skills/creating-mods/references/plan-mode.md +12 -11
  140. package/skills/creating-mods/references/providers.md +1 -1
  141. package/skills/creating-skills/scripts/init-skill.ts +4 -2
  142. package/skills/customizing-commands/SKILL.md +3 -3
  143. package/skills/customizing-statusline/SKILL.md +3 -3
  144. package/skills/customizing-statusline/references/api.md +3 -3
  145. package/skills/customizing-statusline/references/migration.md +2 -2
  146. package/skills/initializing-memory/SKILL.md +2 -2
  147. package/skills/managing-agent-webhooks/SKILL.md +23 -3
  148. package/skills/managing-agent-webhooks/scripts/manage-agent-webhooks.mjs +40 -11
  149. package/skills/self-configuration/SKILL.md +5 -5
  150. package/skills/self-configuration/scripts/add_permission.py +26 -5
  151. package/skills/self-configuration/scripts/show_config.py +17 -2
  152. package/skills/syncing-memory-filesystem/SKILL.md +2 -10
  153. package/skills/video-generation/SKILL.md +152 -0
  154. package/skills/workflow-authoring/SKILL.md +1 -1
  155. package/dist/types/agent/memory-worktree.d.ts +0 -83
  156. package/dist/types/agent/memory-worktree.d.ts.map +0 -1
@@ -1,13 +1,13 @@
1
1
  # Statusline Migration
2
2
 
3
- Use this reference when migrating legacy command statuslines, standalone `.sh` statusline scripts, or shell PS1 prompts into `~/.letta/mods/statusline.tsx`.
3
+ Use this reference when migrating legacy command statuslines, standalone `.sh` statusline scripts, or shell PS1 prompts into `${LETTA_CONFIG_DIR:-$HOME/.letta}/mods/statusline.tsx`.
4
4
 
5
5
  ## Legacy Letta command statusline
6
6
 
7
7
  Inspect these files for old config:
8
8
 
9
9
  ```text
10
- ~/.letta/settings.json
10
+ ${LETTA_CONFIG_DIR:-$HOME/.letta}/settings.json
11
11
  <project>/.letta/settings.json
12
12
  <project>/.letta/settings.local.json
13
13
  ```
@@ -7,7 +7,7 @@ description: Comprehensive guide for initializing or reorganizing agent memory.
7
7
 
8
8
  Your memory is projected to a filesystem at `$MEMORY_DIR`, so you can restructure it with ordinary file tools and git. This skill applies the [Context Constitution](https://github.com/letta-ai/context-constitution/blob/main/constitution/CONSTITUTION.md)'s Progressive Disclosure and Efficiency principles to the [MemFS v2 root-first design](https://github.com/letta-ai/letta-code/blob/main/src/agent/prompts/letta_root_memfs.md).
9
9
 
10
- **You own this task through completion**: research, ask, synthesize, write, commit, verify. Delegate research, but integrate the results yourself — launching a background task is not completion. If a memory worker you launched is still editing this checkout, wait for it, then re-read before editing.
10
+ **You own this task through completion**: research, ask, synthesize, write, commit, verify. Delegate research, but integrate the results yourself — launching a background task is not completion.
11
11
 
12
12
  ## Principles
13
13
 
@@ -159,7 +159,7 @@ You — not the subagents — decide what becomes memory, and you write it. Synt
159
159
 
160
160
  ```bash
161
161
  node <SKILL_DIR>/scripts/history-coverage.mjs --prepared /tmp/letta-init-history \
162
- --journal ~/.letta/workflows/executions/<id>/journal.jsonl \
162
+ --journal "${LETTA_CONFIG_DIR:-$HOME/.letta}/workflows/executions/<id>/journal.jsonl" \
163
163
  --retry-out /tmp/letta-init-history/retry.json
164
164
  ```
165
165
 
@@ -96,11 +96,13 @@ payload as a user message.
96
96
  unreadable receipt means deletion was accepted but remains unconfirmed; list
97
97
  webhooks before treating the capability URL as removed or retrying.
98
98
  - Normal update output additionally requires the returned webhook ID and
99
- `enabled` state to match the requested operation; normal rotate output
100
- requires the returned webhook ID to match. Canonical but contradictory 2xx
99
+ `enabled` state (or `target_device_id` for `update --computer`) to match the
100
+ requested operation; normal rotate output requires the returned webhook ID
101
+ to match. Canonical but contradictory 2xx
101
102
  records receive the same accepted/reconcile envelope and are never printed as
102
103
  ordinary success.
103
- - Normal create output also requires returned name and enabled state to match.
104
+ - Normal create output also requires returned name, enabled state, and
105
+ `target_device_id` to match.
104
106
  An explicitly supplied preprompt must round-trip exactly; when preprompt is
105
107
  omitted, the server-owned default is accepted only as a nonblank string, while
106
108
  missing, null, empty, whitespace-only, and non-string values are contradictory.
@@ -207,6 +209,24 @@ The caller sends `Authorization: Basic <base64("webhook:<security-key>")>`.
207
209
  Do not print that header or the key. The helper derives it internally for test
208
210
  requests when the same key is piped through stdin.
209
211
 
212
+ ### Run webhook turns on a connected computer
213
+
214
+ By default, webhook-triggered conversations run in the agent's Cloud sandbox.
215
+ To run them on a connected computer instead, get its device ID from
216
+ `letta computers list` and pass it with `--computer` on `create` or `update`:
217
+
218
+ ```bash
219
+ node <SKILL_DIR>/scripts/manage-agent-webhooks.mjs update \
220
+ --webhook-id webhook-agent-... \
221
+ --computer <deviceId>
222
+ ```
223
+
224
+ `list` shows the target as `target_device_id` (`null` means Cloud). If the
225
+ computer is offline when a request arrives, that delivery fails; it does not
226
+ fall back to Cloud. An unknown device ID returns `404 targetDeviceNotFound`.
227
+ Pass `--computer cloud` to `update` to clear the target and go back to the
228
+ Cloud sandbox.
229
+
210
230
  ### Test acceptance
211
231
 
212
232
  Public webhook:
@@ -15,6 +15,7 @@ const COMMANDS = new Set([
15
15
  "requests",
16
16
  "rotate",
17
17
  "test",
18
+ "update",
18
19
  ]);
19
20
  const BOOLEAN_FLAGS = new Set([
20
21
  "confirm",
@@ -28,6 +29,7 @@ const COMMAND_OPTIONS = new Map([
28
29
  [
29
30
  "create",
30
31
  new Set([
32
+ "computer",
31
33
  "credential-output",
32
34
  "disabled",
33
35
  "name",
@@ -53,12 +55,14 @@ const COMMAND_OPTIONS = new Map([
53
55
  "webhook-id",
54
56
  ]),
55
57
  ],
58
+ ["update", new Set(["computer", "webhook-id"])],
56
59
  ]);
57
60
 
58
61
  function usage() {
59
62
  console.error(`Usage:
60
63
  node manage-agent-webhooks.mjs list
61
- node manage-agent-webhooks.mjs create --name <name> (--public | --secure --credential-output <path> | --security-key-stdin) [--preprompt <text>] [--disabled]
64
+ node manage-agent-webhooks.mjs create --name <name> (--public | --secure --credential-output <path> | --security-key-stdin) [--preprompt <text>] [--disabled] [--computer <deviceId>]
65
+ node manage-agent-webhooks.mjs update --webhook-id <id> --computer <deviceId|cloud>
62
66
  node manage-agent-webhooks.mjs test --webhook-id <id> --confirm [--payload-file <path>] [--credential-file <path> | --security-key-stdin]
63
67
  node manage-agent-webhooks.mjs requests --webhook-id <id> [--limit <1-50>] [--include-body]
64
68
  node manage-agent-webhooks.mjs enable --webhook-id <id>
@@ -144,8 +148,10 @@ export function safeAgentWebhook(webhook) {
144
148
  for (const field of ["enabled", "requires_authorization_header"]) {
145
149
  if (typeof webhook[field] === "boolean") safe[field] = webhook[field];
146
150
  }
147
- if (typeof webhook.disabled_at === "string" || webhook.disabled_at === null) {
148
- safe.disabled_at = webhook.disabled_at;
151
+ for (const field of ["disabled_at", "target_device_id"]) {
152
+ if (typeof webhook[field] === "string" || webhook[field] === null) {
153
+ safe[field] = webhook[field];
154
+ }
149
155
  }
150
156
  return safe;
151
157
  }
@@ -753,6 +759,15 @@ function requireWebhookId(args) {
753
759
  return requireString(args["webhook-id"], "Pass --webhook-id");
754
760
  }
755
761
 
762
+ // "cloud" maps to null: run webhook turns in the agent's Cloud sandbox.
763
+ function targetDeviceIdFromArgs(args) {
764
+ const computer = requireString(
765
+ args.computer,
766
+ "--computer must be a device ID or cloud",
767
+ );
768
+ return computer === "cloud" ? null : computer;
769
+ }
770
+
756
771
  function requireConfirmation(args, action) {
757
772
  if (args.confirm !== true) {
758
773
  throw new Error(`${action} requires --confirm`);
@@ -827,6 +842,10 @@ async function runManagementCommand(params) {
827
842
  "--preprompt must contain a non-whitespace character",
828
843
  );
829
844
  }
845
+ if (params.args.computer !== undefined) {
846
+ const targetDeviceId = targetDeviceIdFromArgs(params.args);
847
+ if (targetDeviceId) body.target_device_id = targetDeviceId;
848
+ }
830
849
  if (securityKey) body.security_key = securityKey;
831
850
  const credentialReservation = usesGeneratedCredential
832
851
  ? await reserveCredentialFile(params.args["credential-output"])
@@ -914,6 +933,8 @@ async function runManagementCommand(params) {
914
933
  if (
915
934
  webhook.name !== body.name ||
916
935
  webhook.enabled !== body.enabled ||
936
+ (webhook.target_device_id ?? null) !==
937
+ (body.target_device_id ?? null) ||
917
938
  !prepromptMatches
918
939
  ) {
919
940
  throw new Error(
@@ -1048,14 +1069,22 @@ async function runManagementCommand(params) {
1048
1069
  return;
1049
1070
  }
1050
1071
 
1051
- if (params.command === "enable" || params.command === "disable") {
1072
+ if (
1073
+ params.command === "enable" ||
1074
+ params.command === "disable" ||
1075
+ params.command === "update"
1076
+ ) {
1052
1077
  if (params.command === "disable") {
1053
1078
  requireConfirmation(params.args, "Disabling a webhook");
1054
1079
  }
1080
+ const update =
1081
+ params.command === "update"
1082
+ ? { target_device_id: targetDeviceIdFromArgs(params.args) }
1083
+ : { enabled: params.command === "enable" };
1055
1084
  const mutation = await requestSideEffect(
1056
1085
  itemUrl,
1057
1086
  {
1058
- body: JSON.stringify({ enabled: params.command === "enable" }),
1087
+ body: JSON.stringify(update),
1059
1088
  headers: params.headers,
1060
1089
  method: "PATCH",
1061
1090
  },
@@ -1074,12 +1103,12 @@ async function runManagementCommand(params) {
1074
1103
  params.baseUrl,
1075
1104
  params.agentId,
1076
1105
  );
1077
- const expectedEnabled = params.command === "enable";
1078
- if (
1079
- webhook.id !== webhookId ||
1080
- typeof webhook.enabled !== "boolean" ||
1081
- webhook.enabled !== expectedEnabled
1082
- ) {
1106
+ const stateMatches =
1107
+ params.command === "update"
1108
+ ? webhook.target_device_id === update.target_device_id
1109
+ : typeof webhook.enabled === "boolean" &&
1110
+ webhook.enabled === update.enabled;
1111
+ if (webhook.id !== webhookId || !stateMatches) {
1083
1112
  throw new Error(
1084
1113
  "Update response does not match the requested webhook state",
1085
1114
  );
@@ -17,7 +17,7 @@ The important part is choosing the right layer. Do not smear a preference into d
17
17
  | Memory and identity | Facts worth retaining, style preferences, persona changes, project knowledge, reusable skills | Edit `$MEMORY_DIR` files and sync the memory repo |
18
18
  | Server agent fields | Agent default model (only on explicit request), context limit, system prompt, compaction, agent name, description | Patch `/v1/agents/{agent_id}` |
19
19
  | Server conversation fields | Model/context changes for the current conversation (the normal target) | Patch `/v1/conversations/{conversation_id}` |
20
- | Local settings | Permissions, environment variables, UI/runtime preferences, pinned agents, toolset overrides, reflection cadence | Edit `~/.letta/settings.json`, `./.letta/settings.json`, or `./.letta/settings.local.json` |
20
+ | Local settings | Permissions, environment variables, UI/runtime preferences, pinned agents, toolset overrides, reflection cadence | Edit `$LETTA_CONFIG_DIR/settings.json` when configured (otherwise `~/.letta/settings.json`), `./.letta/settings.json`, or `./.letta/settings.local.json` |
21
21
  | Mods | New deterministic tools, slash commands, providers, statusline behavior, or lightweight UI | Load `creating-mods`, `customizing-commands`, or `customizing-statusline` |
22
22
  | Skills | Reusable procedural knowledge or bundled scripts | Load `creating-skills` or `acquiring-skills` |
23
23
  | Channels | Slack/Discord/Telegram/WhatsApp/Signal accounts, pairing, routing, listener state | Use `letta channels` or channel commands |
@@ -110,7 +110,7 @@ Use the active layout shown by the prompt and memory files. Do not create a
110
110
  `system/` directory in a root-layout repository or move existing-layout memory
111
111
  to the root as part of an unrelated self-configuration request.
112
112
 
113
- A requested memory or identity change is memory as the main task: make the edit directly with ordinary file tools, preserve the active layout, stage only the files you changed by explicit path, commit in the same shell call, and verify the result before reporting success. If a memory worker you launched may still be running, read its output file first (it ends with `[Task completed]` or `[Task failed]`) and reread the files before editing what it was asked to change. Delegate to the background `memory` subagent only when the change is incidental to another task the user is waiting on.
113
+ Before editing memory, load the relevant skills: `maintaining-core-memory` for root/core files, `maintaining-deferred-memory` for deferred files, and `creating-skills` for skills. Then make the edit directly with ordinary file tools so the agent with the context applies the memory guidance. Preserve the active layout, stage only changed files by explicit path, commit in the same shell call, and verify the result before reporting success.
114
114
 
115
115
  Do not use API system-prompt replacement for ordinary learning. That can clobber the compiled prompt. Edit the memory files instead.
116
116
 
@@ -232,7 +232,7 @@ Settings scopes:
232
232
 
233
233
  | File | Scope | Typical contents |
234
234
  | --- | --- | --- |
235
- | `~/.letta/settings.json` | User/global | Permissions, env keys, experiments, UI/runtime preferences, agents[] entries |
235
+ | `$LETTA_CONFIG_DIR/settings.json` when configured; otherwise `~/.letta/settings.json` | User/global | Permissions, env keys, experiments, UI/runtime preferences, agents[] entries |
236
236
  | `./.letta/settings.json` | Project/shared | Project settings committed with the repo |
237
237
  | `./.letta/settings.local.json` | Project-local | Personal project overrides, usually gitignored |
238
238
 
@@ -347,7 +347,7 @@ Use skills when the user wants you to become good at a repeatable workflow. Sour
347
347
 
348
348
  1. Project skills: `.agents/skills/` with `.skills/` as legacy fallback
349
349
  2. Agent skills: `$MEMORY_DIR/skills/`
350
- 3. Global skills: `~/.letta/skills/`
350
+ 3. Global skills: `$LETTA_CONFIG_DIR/skills/` when configured; otherwise `~/.letta/skills/`
351
351
  4. Bundled skills
352
352
 
353
353
  Load `creating-skills` to create or edit a skill. Load `acquiring-skills` when the user asks for a capability you do not already have. Project, global, bundled, and agent-owned skills have different visibility; verify the target scope before changing skills another agent may load.
@@ -385,7 +385,7 @@ letta channels pair --channel <channel> --code <code> --agent <agent-id> --conve
385
385
  letta server --channels <channel>
386
386
  ```
387
387
 
388
- Channel state lives under `~/.letta/channels/<channel>/` (`config.yaml`, `accounts.json`, routing/pairing files, and channel runtimes). Account tokens may be plaintext in `file` mode or keyring placeholders in `keyring`/`auto` mode. Configure storage with `channelCredentialsStore` (`file`, `keyring`, `auto`) or `LETTA_CHANNEL_CREDENTIALS_STORE`; do not treat keyring placeholders as usable secrets and do not print tokens. Channel configuration and pairing can route external messages to other agents/conversations; verify IDs and get human consent for interactive authorization.
388
+ Channel state lives under `${LETTA_CONFIG_DIR:-$HOME/.letta}/channels/<channel>/` (`config.yaml`, `accounts.json`, routing/pairing files, and channel runtimes). Account tokens may be plaintext in `file` mode or keyring placeholders in `keyring`/`auto` mode. Configure storage with `channelCredentialsStore` (`file`, `keyring`, `auto`) or `LETTA_CHANNEL_CREDENTIALS_STORE`; do not treat keyring placeholders as usable secrets and do not print tokens. Channel configuration and pairing can route external messages to other agents/conversations; verify IDs and get human consent for interactive authorization.
389
389
 
390
390
  `letta channels configure <channel>` is an interactive TTY wizard. Do not launch it as unattended work or claim setup succeeded while it is waiting for input; hand the authorization/setup step to the user.
391
391
 
@@ -19,10 +19,27 @@ from pathlib import Path
19
19
  from typing import Any
20
20
 
21
21
 
22
+ def get_user_config_dir() -> Path:
23
+ """Resolve the product-selected global config directory."""
24
+ override = os.environ.get("LETTA_CONFIG_DIR", "").strip()
25
+ if override:
26
+ path = Path(override)
27
+ if not path.is_absolute():
28
+ raise ValueError("LETTA_CONFIG_DIR must be absolute")
29
+ return path
30
+ return Path.home() / ".letta"
31
+
32
+
22
33
  def get_settings_path(scope: str, working_directory: str) -> Path:
23
34
  """Get the settings file path for a given scope."""
24
35
  if scope == "user":
25
- return Path.home() / ".letta" / "settings.json"
36
+ return get_user_config_dir() / "settings.json"
37
+ if os.environ.get("LETTA_CONFIG_DIR", "").strip() and (
38
+ Path(working_directory).resolve() == Path.home().resolve()
39
+ ):
40
+ raise ValueError(
41
+ f"Cannot save {scope} permissions under HOME while LETTA_CONFIG_DIR is set"
42
+ )
26
43
  if scope == "project":
27
44
  return Path(working_directory) / ".letta" / "settings.json"
28
45
  if scope == "local":
@@ -48,10 +65,14 @@ def load_settings(path: Path) -> dict[str, Any]:
48
65
  return parsed
49
66
 
50
67
 
51
- def save_settings(path: Path, settings: dict[str, Any]) -> None:
52
- """Atomically save settings, preserving an existing file mode where practical."""
68
+ def save_settings(path: Path, settings: dict[str, Any], secure: bool = False) -> None:
69
+ """Atomically save settings, securing the global config when requested."""
53
70
  path.parent.mkdir(parents=True, exist_ok=True)
54
- mode = stat.S_IMODE(path.stat().st_mode) if path.exists() else None
71
+ if secure:
72
+ os.chmod(path.parent, 0o700)
73
+ mode = 0o600 if secure else (
74
+ stat.S_IMODE(path.stat().st_mode) if path.exists() else None
75
+ )
55
76
  temp_path: str | None = None
56
77
 
57
78
  try:
@@ -194,7 +215,7 @@ def main() -> None:
194
215
 
195
216
  if added:
196
217
  try:
197
- save_settings(settings_path, settings)
218
+ save_settings(settings_path, settings, secure=args.scope == "user")
198
219
  except OSError as exc:
199
220
  print(f"Could not save {settings_path}: {exc}", file=sys.stderr)
200
221
  sys.exit(1)
@@ -54,10 +54,25 @@ VERSION_TIMEOUT_SECONDS = 2
54
54
  MAX_VERSION_TEXT = 200
55
55
 
56
56
 
57
+ def get_user_config_dir() -> Path:
58
+ """Resolve the product-selected global config directory."""
59
+ override = os.environ.get("LETTA_CONFIG_DIR", "").strip()
60
+ if override:
61
+ path = Path(override)
62
+ if not path.is_absolute():
63
+ raise ValueError("LETTA_CONFIG_DIR must be absolute")
64
+ return path
65
+ return Path.home() / ".letta"
66
+
67
+
57
68
  def get_settings_paths(working_directory: str) -> list[tuple[str, Path]]:
58
69
  """Return (scope, path) in precedence order (lowest to highest)."""
59
- return [
60
- ("user", Path.home() / ".letta" / "settings.json"),
70
+ paths = [("user", get_user_config_dir() / "settings.json")]
71
+ if os.environ.get("LETTA_CONFIG_DIR", "").strip() and (
72
+ Path(working_directory).resolve() == Path.home().resolve()
73
+ ):
74
+ return paths
75
+ return paths + [
61
76
  ("project", Path(working_directory) / ".letta" / "settings.json"),
62
77
  ("local", Path(working_directory) / ".letta" / "settings.local.json"),
63
78
  ]
@@ -5,15 +5,7 @@ description: Diagnose and repair MemFS repository setup, remote sync, authentica
5
5
 
6
6
  # MemFS Repository Repair
7
7
 
8
- Use this skill only when the Git repository behind an agent's memory is not
9
- setting up or syncing correctly. For ordinary memory reads and edits, use the
10
- memory files without loading this skill. Delegate incidental upkeep during another
11
- task to the background `memory` subagent. When memory repair is the user's main
12
- request, diagnose and repair it directly, then verify the result before reporting
13
- success. If a memory worker you launched may still be running, wait for it: re-read
14
- its output file until it ends with `[Task completed]` or `[Task failed]` before
15
- editing memory files or changing Git state. While the harness reports a repair in
16
- progress, leave both alone as well; that worker edits `$MEMORY_DIR` in place.
8
+ Use this skill when the Git repository behind an agent's memory is not setting up or syncing correctly. Before editing memory, load the relevant skills: `maintaining-core-memory` for root/core files, `maintaining-deferred-memory` for deferred files, and `creating-skills` for skills. Then make the edit directly with ordinary file tools so the agent with the context applies the memory guidance. Stage only changed files by explicit path and commit in the same shell call. Verify the repair before reporting success. While the harness reports a repair in progress, leave memory files and Git state to that repair worker, which edits `$MEMORY_DIR` in place.
17
9
 
18
10
  ## Current Model
19
11
 
@@ -122,7 +114,7 @@ cloud-backed agent's pending commits after the turn.
122
114
  The harness first tries a fast-forward pull. When a remote push is rejected
123
115
  because the remote moved, post-turn sync tries `git pull --rebase` and retries
124
116
  the push. If that rebase conflicts, the harness launches a fresh background
125
- `memory` subagent to repair it. The primary conversation is not interrupted.
117
+ internal `memory` subagent to repair it. The primary conversation is not interrupted.
126
118
  The harness retries normal sync after the worker finishes. The instructions
127
119
  below are for explicit troubleshooting; routine repairs run in the background.
128
120
 
@@ -0,0 +1,152 @@
1
+ ---
2
+ name: video-generation
3
+ description: Generate videos from text prompts (and optional reference or frame images) using Letta's asynchronous video generation API. Use when the user asks to create, generate, or make a video or animation from a description, animate an existing image, or turn a prompt into a short video clip.
4
+ ---
5
+
6
+ # Video Generation
7
+
8
+ Generate videos via Letta's async `POST /v1/videos` using `curl` + `jq`. Requires `LETTA_BASE_URL` and `LETTA_API_KEY`, which the runtime provides. If either is unset, stop and ask the user to authenticate with Letta Cloud; do not ask for a video provider key.
9
+
10
+ This skill is adapted from OpenRouter's `openrouter-video` skill
11
+ ([OpenRouterTeam/skills](https://github.com/OpenRouterTeam/skills/blob/83827c3f3b1200bc3b609f4ab4ec3241c0cfb7ad/skills/openrouter-video/SKILL.md)).
12
+ Letta's endpoint forwards the request with Letta's key and charges the
13
+ organization's Letta credits for the cost of each completed video.
14
+
15
+ Build every URL relative to `${LETTA_BASE_URL%/}` and send `Authorization: Bearer $LETTA_API_KEY`. Do not hardcode `https://api.letta.com`: Desktop and remote runtimes may provide a proxy base URL, and the credential may only be valid through that URL.
16
+
17
+ ## The three steps
18
+
19
+ Video generation is async: submit → poll → download. A single request can't return the video because generation takes 30s–a few minutes. Tell the user the job was submitted so they know the delay is expected.
20
+
21
+ 1. `POST /v1/videos` → `{ id, polling_url, status: "pending" }` (`polling_url` is the absolute URL of step 2)
22
+ 2. `GET /v1/videos/{id}` every ~30s until `status` is `completed` (terminal failures: `failed`, `cancelled`, `expired` — surface the `error` field verbatim)
23
+ 3. `GET /v1/videos/{id}/content?index=0` **with the auth header** → MP4 bytes
24
+
25
+ A completed job also has `urls`: signed downloads that need no API key until `expires_at` (Unix seconds); anyone holding one can download the video, so prefer step 3.
26
+
27
+ ## Pick parameters from the models endpoint, don't guess
28
+
29
+ `resolution`, `aspect_ratio`, `duration`, and `frame_images[].frame_type` are per-model. Before the first submit for a new model (or whenever the user asks for something specific), fetch the model's capabilities and only send values from the returned sets:
30
+
31
+ ```bash
32
+ curl -sS "${LETTA_BASE_URL%/}/v1/videos/models" \
33
+ -H "Authorization: Bearer $LETTA_API_KEY" \
34
+ | jq '.data[] | select(.id == "MODEL_ID")'
35
+ ```
36
+
37
+ Fields on each model worth knowing: `supported_resolutions`, `supported_aspect_ratios`, `supported_sizes`, `supported_durations` (often discrete like `[4,6,8]`, not a range), `supported_frame_images` (which `frame_type` values are accepted), `generate_audio` and `seed` (capability bools), `pricing_skus`, and `allowed_passthrough_parameters`. An out-of-set value returns a 400, so validate client-side.
38
+
39
+ Models include `google/veo-3.1`, `bytedance/seedance-2.5`, `kwaivgi/kling-v3.0-pro`, `minimax/hailuo-3`, `minimax/hailuo-3-max`, and `heygen/avatar-iv` (a talking head from one photo); the models endpoint has the full list.
40
+
41
+ ## Full workflow (drop-in)
42
+
43
+ ```bash
44
+ #!/usr/bin/env bash
45
+ set -euo pipefail
46
+
47
+ PROMPT="a golden retriever playing fetch on a sunny beach"
48
+ MODEL="google/veo-3.1"
49
+ OUTPUT="video-$(date +%Y%m%d-%H%M%S).mp4"
50
+ base_url="${LETTA_BASE_URL%/}"
51
+
52
+ # Build payload — extend with resolution/aspect_ratio/duration/etc. as needed.
53
+ payload=$(jq -n --arg model "$MODEL" --arg prompt "$PROMPT" \
54
+ '{model: $model, prompt: $prompt}')
55
+
56
+ submit=$(curl -sS -X POST "$base_url/v1/videos" \
57
+ -H "Authorization: Bearer $LETTA_API_KEY" \
58
+ -H "Content-Type: application/json" \
59
+ -d "$payload")
60
+
61
+ job_id=$(echo "$submit" | jq -r '.id // empty')
62
+ if [ -z "$job_id" ]; then
63
+ echo "Submit failed: $(echo "$submit" | jq -r '.message // .')" >&2
64
+ exit 1
65
+ fi
66
+ echo "Submitted $job_id" >&2
67
+
68
+ while :; do
69
+ sleep 30
70
+ resp=$(curl -sS "$base_url/v1/videos/$job_id" -H "Authorization: Bearer $LETTA_API_KEY")
71
+ # Avoid the name `status` — zsh treats it as read-only.
72
+ st=$(echo "$resp" | jq -r '.status')
73
+ echo "Status: $st" >&2
74
+ case "$st" in
75
+ completed) break ;;
76
+ failed|cancelled|expired)
77
+ echo "Generation $st: $(echo "$resp" | jq -r '.error // "unknown"')" >&2
78
+ exit 1 ;;
79
+ esac
80
+ done
81
+
82
+ curl -sS -f "$base_url/v1/videos/$job_id/content?index=0" \
83
+ -H "Authorization: Bearer $LETTA_API_KEY" \
84
+ --output "$OUTPUT"
85
+
86
+ echo "$resp" | jq --arg out "$(realpath "$OUTPUT")" \
87
+ '{job_id: .id, video_saved: $out, billing}'
88
+ ```
89
+
90
+ Share the saved file the way your current surface supports: attach or upload it to the conversation or channel you are replying in. Keep credit amounts out of replies unless the user asks about cost; `billing.credits_charged` on the completed job has them.
91
+
92
+ ## Parameters
93
+
94
+ Required: `model`. `prompt` is required by every model except those that can generate from image input alone. Common optional fields:
95
+
96
+ - `duration` (int) — must be one of the model's `supported_durations`.
97
+ - `resolution` (string) / `aspect_ratio` (string) / `size` (string, `"WxH"`) — `size` is interchangeable with resolution + aspect_ratio.
98
+ - `generate_audio` (bool) — only meaningful if the model's `generate_audio` capability is true.
99
+ - `seed` (int) — honored only if the model's `seed` capability is true.
100
+ - `frame_images[]` — image-to-video; each entry is `{ type: "image_url", image_url: { url }, frame_type: "first_frame" | "last_frame" }`.
101
+ - `input_references[]` — reference-to-video (style guidance); image entries have the same shape, no `frame_type`. Audio and video references are `{ type: "audio_url", audio_url: { url } }` and `{ type: "video_url", video_url: { url } }`; only some models (such as `bytedance/seedance-2.5`) use them, and the rest ignore them. If both arrays are present, `frame_images` wins.
102
+ - `provider.options.<slug>.parameters.<key>` — provider passthrough, see below.
103
+
104
+ Image `url` can be a public `https://` URL or a local-file data URL: `MIME=image/png; B64=$(base64 < file.png | tr -d '\n'); url="data:${MIME};base64,${B64}"`. Audio and video references take URLs the same way.
105
+
106
+ ## Provider passthrough
107
+
108
+ Provider-specific params go under `provider.options.<slug>.parameters`. The allowed keys for a given model are listed (flat) in `allowed_passthrough_parameters` on the models endpoint — but the meaning, value range, and required combinations come from the *upstream provider's* API docs (Google Vertex, Alibaba Dashscope, Kwai, ByteDance Volc Engine, MiniMax, OpenAI, etc.). Read the upstream docs before using an unfamiliar key; casing conventions differ between providers (Google/OpenAI use camelCase, most others use snake_case).
109
+
110
+ Example:
111
+
112
+ ```json
113
+ {
114
+ "model": "google/veo-3.1",
115
+ "prompt": "a time-lapse of a flower blooming",
116
+ "provider": {
117
+ "options": {
118
+ "google-vertex": {
119
+ "parameters": {
120
+ "personGeneration": "allow",
121
+ "negativePrompt": "blurry, low quality"
122
+ }
123
+ }
124
+ }
125
+ }
126
+ }
127
+ ```
128
+
129
+ `heygen/avatar-iv` animates one photo into a lip-synced talking head: pass the photo as an image in `input_references` and describe the video in `prompt`. Its passthrough keys (slug `heygen`) include `voice_id`, `motion_prompt`, and `expressiveness`; take their values from HeyGen's API docs.
130
+
131
+ ```json
132
+ {
133
+ "model": "heygen/avatar-iv",
134
+ "prompt": "A friendly presenter welcomes viewers to the product tour",
135
+ "aspect_ratio": "9:16",
136
+ "input_references": [
137
+ { "type": "image_url", "image_url": { "url": "data:image/png;base64,..." } }
138
+ ]
139
+ }
140
+ ```
141
+
142
+ ## Chaining with other skills
143
+
144
+ - **Keyframes:** generate stills with the `image-generation` skill, then pass them as `frame_images` (`first_frame` / `last_frame`) or image `input_references` as data URLs.
145
+ - **Sound:** make a voiceover with the `speech-generation` skill or a soundtrack with the `music-generation` skill, then pass the audio as an `audio_url` input reference to a model that uses audio, or mix it onto the finished MP4 (for example with `ffmpeg`).
146
+
147
+ ## Notes
148
+
149
+ - **Billing**: the organization needs credits for an estimate before a job is submitted; once it completes, it is charged for the video's cost. Don't resubmit needlessly.
150
+ - **Errors**: `402` = insufficient credits (`credits_required` in body); `400`/`404`/`500` return `{ "message": "..." }` — surface it to the user.
151
+
152
+ Video generation is not ZDR-eligible because the provider must temporarily retain the output for the async download step.
@@ -256,7 +256,7 @@ quick checks.
256
256
 
257
257
  Every run persists its script, args, and a `journal.jsonl` with one line per
258
258
  completed subagent call (prompt, outcome, conversation id) under
259
- `~/.letta/workflows/executions/<id>/`; the tool result names the paths. Before
259
+ `${LETTA_CONFIG_DIR:-$HOME/.letta}/workflows/executions/<id>/`; the tool result names the paths. Before
260
260
  diagnosing why a workflow returned an empty or unexpected result, read that
261
261
  journal — it records each agent's actual return value and failure detail.
262
262
  A failed run is not resumable: fix the script and launch it again.
@@ -1,83 +0,0 @@
1
- export interface ReflectionMemoryWorktree {
2
- id: string;
3
- parentMemoryDir: string;
4
- worktreeBaseDir: string;
5
- worktreeDir: string;
6
- branchName: string;
7
- baseHead: string;
8
- gitCommonDir: string;
9
- }
10
- export interface CreateReflectionMemoryWorktreeOptions {
11
- parentMemoryDir: string;
12
- now?: Date;
13
- /** Directory and branch prefix; memory workers use "memory-worker". */
14
- label?: string;
15
- }
16
- export declare function createReflectionMemoryWorktree(options: CreateReflectionMemoryWorktreeOptions): Promise<ReflectionMemoryWorktree>;
17
- export interface ReflectionMemoryScope {
18
- primaryRoot: string;
19
- writableRoots: string[];
20
- readonlyRoots: string[];
21
- }
22
- export declare function buildReflectionMemoryScope(worktree: ReflectionMemoryWorktree): ReflectionMemoryScope;
23
- export declare function buildReflectionIntegrationMemoryScope(worktree: ReflectionMemoryWorktree): ReflectionMemoryScope;
24
- export type ReflectionMemoryWorktreeFinalizeStatus = "merged" | "no_changes" | "parent_dirty" | "merge_conflict" | "dirty_uncommitted" | "failed";
25
- export interface ReflectionMemoryWorktreeFinalizeResult {
26
- status: ReflectionMemoryWorktreeFinalizeStatus;
27
- parentMemoryDir: string;
28
- reflectionWorktreeDir: string;
29
- reflectionBranch: string;
30
- commitCount: number;
31
- head?: string;
32
- summary: string;
33
- error?: string;
34
- failurePhase?: "reflection" | "integration";
35
- }
36
- export declare function reflectionIntegrationConsumesTranscript(result: ReflectionMemoryWorktreeFinalizeResult): boolean;
37
- export declare function reflectionIntegrationShouldRecompile(result: ReflectionMemoryWorktreeFinalizeResult): boolean;
38
- export declare function reflectionMemoryParentHasChanges(parentMemoryDir: string): Promise<boolean>;
39
- export interface ReflectionMemoryWorktreeState {
40
- commitCount: number;
41
- dirty: boolean;
42
- head?: string;
43
- }
44
- export declare function inspectReflectionMemoryWorktree(worktree: ReflectionMemoryWorktree): Promise<ReflectionMemoryWorktreeState>;
45
- /** Finalize without taking the checkout lease; the caller must already hold it. */
46
- export declare function finalizeReflectionMemoryWorktreeUnlocked(worktree: ReflectionMemoryWorktree, options: ReflectionMemoryWorktreeFinalizeOptions): Promise<ReflectionMemoryWorktreeFinalizeResult>;
47
- export declare function finalizeReflectionMemoryWorktree(worktree: ReflectionMemoryWorktree, options: ReflectionMemoryWorktreeFinalizeOptions): Promise<ReflectionMemoryWorktreeFinalizeResult>;
48
- export type MemoryWorkerWorktreeOutcome = {
49
- status: "merged";
50
- commitCount: number;
51
- head: string;
52
- } | {
53
- status: "no_changes";
54
- } | {
55
- status: "discarded";
56
- } | {
57
- status: "merge_conflict";
58
- commitCount: number;
59
- branchName: string;
60
- } | {
61
- status: "failed";
62
- error: string;
63
- };
64
- /**
65
- * Bring a memory worker's worktree back into the parent checkout. The caller
66
- * must hold the checkout lease. Commits are merged (fast-forward when
67
- * possible); uncommitted edits in the worktree are dropped, as are all edits
68
- * when `discard` is set (a cancelled worker). A merge that conflicts with the
69
- * parent's own changes is aborted and the branch is kept so nothing is lost.
70
- * Unlike reflection, a dirty parent does not block the merge: Git refuses only
71
- * when the parent's uncommitted files overlap the worker's commits, and that
72
- * surfaces as a conflict here.
73
- */
74
- export declare function integrateMemoryWorkerWorktree(worktree: ReflectionMemoryWorktree, options?: {
75
- discard?: boolean;
76
- }): Promise<MemoryWorkerWorktreeOutcome>;
77
- export interface ReflectionMemoryWorktreeFinalizeOptions {
78
- shouldMerge: boolean;
79
- knownNoChanges?: boolean;
80
- failureSummary?: string;
81
- requireAlreadyMerged?: boolean;
82
- }
83
- //# sourceMappingURL=memory-worktree.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"memory-worktree.d.ts","sourceRoot":"","sources":["../../../src/agent/memory-worktree.ts"],"names":[],"mappings":"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"}