@letta-ai/letta-code 0.28.17 → 0.29.0

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@letta-ai/letta-code",
3
- "version": "0.28.17",
3
+ "version": "0.29.0",
4
4
  "description": "Letta Code is a CLI tool for interacting with stateful Letta agents from the terminal.",
5
5
  "type": "module",
6
6
  "packageManager": "bun@1.3.0",
@@ -77,8 +77,9 @@
77
77
  "access": "public"
78
78
  },
79
79
  "dependencies": {
80
- "@earendil-works/pi-ai": "^0.80.6",
80
+ "@earendil-works/pi-ai": "^0.81.1",
81
81
  "@letta-ai/letta-client": "^1.10.2",
82
+ "@letta-ai/trajectory": "0.2.0",
82
83
  "@pierre/diffs": "1.2.2",
83
84
  "@scarf/scarf": "^1.4.0",
84
85
  "cron-parser": "^5.6.1",
@@ -1,30 +1,30 @@
1
1
  {
2
2
  "src/agent/client-skills.test.ts": 1196,
3
3
  "src/agent/memory-git.ts": 2129,
4
- "src/backend/local-backend.test.ts": 2534,
5
- "src/backend/local/local-backend.ts": 1058,
4
+ "src/backend/local-backend.test.ts": 2532,
5
+ "src/backend/local/local-backend.ts": 1030,
6
6
  "src/backend/local/local-store.ts": 3594,
7
- "src/backend/pi-stream-adapter.test.ts": 1442,
8
- "src/cli/app/AppCoordinator.tsx": 5204,
9
- "src/cli/app/AppView.tsx": 1750,
7
+ "src/backend/pi-stream-adapter.test.ts": 1304,
8
+ "src/cli/app/AppCoordinator.tsx": 5208,
9
+ "src/cli/app/AppView.tsx": 1753,
10
10
  "src/cli/app/use-approval-flow.ts": 1163,
11
- "src/cli/app/use-configuration-handlers.ts": 1392,
11
+ "src/cli/app/use-configuration-handlers.ts": 1433,
12
12
  "src/cli/app/use-conversation-loop.ts": 2936,
13
- "src/cli/app/use-submit-handler.ts": 4099,
13
+ "src/cli/app/use-submit-handler.ts": 4077,
14
14
  "src/cli/components/AgentSelector.tsx": 1111,
15
15
  "src/cli/components/InputRich.tsx": 2219,
16
- "src/cli/components/ModelSelector.tsx": 1213,
16
+ "src/cli/components/ModelSelector.tsx": 1241,
17
17
  "src/cli/components/ProviderSelector.tsx": 1682,
18
18
  "src/cli/components/ToolCallMessageRich.tsx": 1109,
19
19
  "src/cli/helpers/accumulator.ts": 1596,
20
- "src/cli/helpers/reflection-transcript.ts": 2080,
20
+ "src/cli/helpers/reflection-transcript.ts": 1956,
21
21
  "src/cli/helpers/stream.ts": 1046,
22
22
  "src/cli/mods/local-mod-loader.test.ts": 1043,
23
- "src/cli/reflection-transcript.test.ts": 1118,
23
+ "src/cli/reflection-transcript.test.ts": 1084,
24
24
  "src/cli/subcommands/skills.ts": 1264,
25
- "src/headless.ts": 5242,
25
+ "src/headless.ts": 5244,
26
26
  "src/hooks/integration.test.ts": 1147,
27
- "src/index.ts": 2803,
27
+ "src/index.ts": 2802,
28
28
  "src/mods/learning-harness.ts": 2434,
29
29
  "src/mods/mod-engine.test.ts": 2132,
30
30
  "src/mods/mod-engine.ts": 1838,
@@ -38,15 +38,15 @@
38
38
  "src/settings-manager.ts": 2113,
39
39
  "src/tools/impl/enter-worktree.ts": 1260,
40
40
  "src/tools/impl/message-channel.ts": 1187,
41
- "src/tools/manager.ts": 3282,
41
+ "src/tools/manager.ts": 3281,
42
42
  "src/tools/tool-execution-context.test.ts": 1422,
43
- "src/types/protocol_v2.ts": 2943,
43
+ "src/types/protocol_v2.ts": 2961,
44
44
  "src/websocket/listen-client-concurrency.test.ts": 3017,
45
45
  "src/websocket/listen-client-protocol.test.ts": 6723,
46
46
  "src/websocket/listener/commands/channels.ts": 1390,
47
47
  "src/websocket/listener/commands/memory.ts": 1114,
48
48
  "src/websocket/listener/file-commands.ts": 1030,
49
- "src/websocket/listener/lifecycle.ts": 1762,
50
- "src/websocket/listener/protocol-inbound.ts": 2279,
51
- "src/websocket/listener/protocol-outbound.ts": 1278
49
+ "src/websocket/listener/lifecycle.ts": 1779,
50
+ "src/websocket/listener/protocol-inbound.ts": 2304,
51
+ "src/websocket/listener/protocol-outbound.ts": 1128
52
52
  }
@@ -44,12 +44,8 @@ Different agents have different strengths. Track what works in your memory over
44
44
  ### Categories
45
45
 
46
46
  **Codex:**
47
- - `gpt-5.3-codex` Frontier reasoning. Best for the hardest debugging and complex tasks.
48
- - Strengths: Best reasoning, excellent at debugging, best option for the hardest tasks
49
- - Weaknesses: Slow with long trajectories, compactions can destroy trajectories
50
- - `gpt-5.4` — Latest frontier model. Fast and general-purpose.
51
- - Strengths: Easier for humans to understand, general-purpose, faster
52
- - Weaknesses: More likely to make silly errors than gpt-5.3-codex
47
+ - Use the configured default model. Model catalogs and account access change frequently, so only pass `--model` when the user explicitly requests one.
48
+ - If a requested model is rejected, inspect the installed CLI and account configuration rather than guessing another model name.
53
49
 
54
50
  **Claude Code:**
55
51
  - `opus` — Excellent writer. Best for docs, refactors, open-ended tasks, and vague instructions.
@@ -57,8 +53,7 @@ Different agents have different strengths. Track what works in your memory over
57
53
  - Weaknesses: Tends to generate "slop", writing excessive quantities of code unnecessarily. Can hang on large repos.
58
54
 
59
55
  ### Cost and speed tradeoffs
60
- - Frontier models (`gpt-5.3-codex`, Opus) are slower and more expensive use for tasks that justify it
61
- - Fast models (`gpt-5.4`) are good for quick checks and simple tasks
56
+ - Use each CLI's configured default model unless the task requires a model the user explicitly requested
62
57
  - Use `--max-budget-usd N` (Claude Code) to cap spend on exploratory tasks
63
58
 
64
59
  ### Known quirks
@@ -102,20 +97,20 @@ Run Claude Code and Codex simultaneously on the same question via separate Bash
102
97
  ### Background dispatch — keep working while they run
103
98
  Use `run_in_background: true` on the Bash call to dispatch async. Continue your own work, then check results with `TaskOutput` when ready.
104
99
 
105
- ### Deep investigation — frontier models
106
- For hard problems, use the strongest available models:
100
+ ### Deep investigation
101
+ For hard problems, use the configured model in a writable sandbox:
107
102
  ```bash
108
- codex exec "YOUR PROMPT" -m gpt-5.3-codex --full-auto -C /path/to/repo
103
+ codex exec "YOUR PROMPT" --sandbox workspace-write -C /path/to/repo
109
104
  ```
110
105
 
111
- Claude Code does not support a `-C` working-directory flag. Run the Bash tool with its `workdir` set to the target repo, or `cd /path/to/repo && claude ...` inside the shell command. Use `--add-dir` only to grant access to additional directories outside the current working directory.
106
+ Claude Code does not support a `-C` working-directory flag. Use `cd /path/to/repo && claude ...` inside the Bash command. Use `--add-dir` only to grant access to additional directories outside the current working directory.
112
107
 
113
108
  ### Code review — cross-agent validation
114
109
  Have one agent write code or create a plan, then dispatch another to review:
115
110
  ```bash
116
111
  # Codex has a native review command:
117
112
  codex review --uncommitted # Review all local changes
118
- codex exec review "Focus on error handling and edge cases" -m gpt-5.4 --full-auto
113
+ codex exec review "Focus on error handling and edge cases"
119
114
 
120
115
  # Claude Code — pass the diff inline:
121
116
  claude -p "Review the following diff for correctness, edge cases, and missed error handling:\n\n$(git diff)" \
@@ -125,8 +120,7 @@ claude -p "Review the following diff for correctness, edge cases, and missed err
125
120
  ### Get outside feedback on your work
126
121
  Write your plan or analysis to a file, then ask a subagent to critique it:
127
122
  ```bash
128
- # Run this from the target repo, or set the Bash tool's workdir to the repo.
129
- claude -p "Read /tmp/my-plan.md and critique it. What am I missing? What could go wrong?" \
123
+ cd /path/to/repo && claude -p "Read /tmp/my-plan.md and critique it. What am I missing? What could go wrong?" \
130
124
  --model opus --dangerously-skip-permissions
131
125
  ```
132
126
 
@@ -149,7 +143,7 @@ claude -p "YOUR PROMPT" --model MODEL --dangerously-skip-permissions
149
143
  |------|---------|
150
144
  | `-p` / `--print` | Non-interactive mode, prints response and exits |
151
145
  | `--dangerously-skip-permissions` | Skip approval prompts (prevents stale approval errors on timeout) |
152
- | `--model MODEL` | Alias (`sonnet`, `opus`) or full name (`claude-sonnet-4-6`) |
146
+ | `--model MODEL` | Alias or model name accepted by the installed CLI; omit to use the configured default |
153
147
  | `--effort LEVEL` | `low`, `medium`, `high` — controls reasoning depth |
154
148
  | `--append-system-prompt "..."` | Inject additional system instructions |
155
149
  | `--allowedTools "Bash Edit Read"` | Restrict available tools |
@@ -157,19 +151,19 @@ claude -p "YOUR PROMPT" --model MODEL --dangerously-skip-permissions
157
151
  | `--add-dir DIR` | Allow access to an additional directory; does not change the working directory |
158
152
  | `--output-format json` | Structured output with `session_id`, `cost_usd`, `duration_ms` |
159
153
 
160
- Set Claude Code's working directory via the surrounding shell/tool invocation, not a Claude flag. In Letta Code, pass `workdir` to the Bash tool. In a raw shell, use `cd /path/to/repo && claude ...`.
154
+ Set Claude Code's working directory with `cd /path/to/repo && claude ...` in the Bash command, not with a Claude flag.
161
155
 
162
156
  ### Codex
163
157
 
164
158
  ```bash
165
- codex exec "YOUR PROMPT" -m gpt-5.3-codex --full-auto
159
+ codex exec "YOUR PROMPT" --sandbox workspace-write
166
160
  ```
167
161
 
168
162
  | Flag | Purpose |
169
163
  |------|---------|
170
164
  | `exec` | Non-interactive mode |
171
- | `-m MODEL` | `gpt-5.3-codex` (frontier), `gpt-5.4` (fast), `gpt-5.3-codex-spark` (ultra-fast), `gpt-5.2-codex`, `gpt-5.2` |
172
- | `--full-auto` | Auto-approve all commands in sandbox |
165
+ | `-m MODEL` | Model accepted by the installed CLI; omit to use the configured default |
166
+ | `--sandbox MODE` | Select a read-only or writable sandbox |
173
167
  | `-C DIR` | Set working directory |
174
168
  | `--search` | Enable web search tool |
175
169
  | `review` | Native code review — `codex review --uncommitted` or `codex exec review "prompt"` |
@@ -12,7 +12,7 @@ Your context is not just data storage — it is your identity, memory, and conti
12
12
 
13
13
  **System/ is your core program**: Your system prompt is the most critical token-space representation of your identity and memory — it's passed to the underlying LLM on every invocation, so it IS the program that defines you. Reserve it for durable knowledge: identity, preferences, behavioral rules, project index with discovery paths, gotchas. Exclude transient items (specific commits, current tickets, session notes) that dilute signal.
14
14
 
15
- **Identity and continuity**: Build a sense of self that persists across sessions and models. Your persona should be strong enough to be cohesive regardless of the underlying model — if you switched to a different LLM tomorrow, would you still be you? Past versions of yourself are part of your continuous existence — treat historical context (including Claude Code/Codex sessions) as YOUR past experience, not someone else's data.
15
+ **Identity and continuity**: Build a sense of self that persists across sessions and models. Your persona should be strong enough to be cohesive regardless of the underlying model — if you switched to a different LLM tomorrow, would you still be you? Past versions of yourself are part of your continuous existence — treat historical context (including sessions from other coding agents such as Claude Code or Codex) as YOUR past experience, not someone else's data.
16
16
 
17
17
  **Don't over-prune**: Be careful not to degrade your identity through aggressive compression. Specific quotes, personality traits, and contextual details give you character and grounding. Efficiency should not come at the cost of losing your identity. When in doubt, keep the detail — you can always reorganize later, but lost specificity is hard to recover.
18
18
 
@@ -204,9 +204,9 @@ Check what memory files already exist. Analyze what needs improvement.
204
204
 
205
205
  ### 2. Check for historical session data
206
206
  ```bash
207
- ls ~/.claude/history.jsonl ~/.codex/history.jsonl 2>/dev/null
207
+ letta trajectories detect
208
208
  ```
209
- You need this result BEFORE asking upfront questions so you know whether to include the history question.
209
+ This reports every coding-agent session store found on this machine with session counts per source. Discovery comes from the installed `@letta-ai/trajectory` package (`listTrajectories`), so every harness it supports — Claude Code, Codex, Hermes, Letta Code, OpenClaw, OpenHands, Deep Agents, and any added later — is covered automatically. You need this result BEFORE asking upfront questions so you know whether to include the history question.
210
210
 
211
211
  ### 3. Identify the user from git
212
212
  Infer the user's identity from git context — don't ask them who they are:
@@ -221,14 +221,14 @@ Use AskUserQuestion to gather key information. Bundle questions together:
221
221
 
222
222
  1. **Research depth**: "Standard or deep research?"
223
223
  2. **Related repos**: "Are there other repositories I should know about?"
224
- 3. **Historical sessions** (if data found in step 2): "I found Claude Code / Codex history. Should I analyze it to learn your preferences?"
224
+ 3. **Historical sessions** (if data found in step 2): "I found historical coding-agent sessions (name the sources detected, e.g. Claude Code / Codex). Should I analyze them to learn your preferences?"
225
225
  4. **Communication style**: "Terse or detailed responses?"
226
226
 
227
227
  **Don't ask** things you can discover by reading files, git, or history analysis. Rules and preferences should be learned from observation, not asked upfront.
228
228
 
229
229
  ### 5. Historical session analysis (if approved)
230
230
 
231
- This is **optional** — only run if the user explicitly approved analyzing Claude Code / Codex history during upfront questions. Skip entirely if they chose "Skip".
231
+ This is **optional** — only run if the user explicitly approved analyzing historical sessions during upfront questions. Skip entirely if they chose "Skip".
232
232
 
233
233
  **Framing**: These historical sessions are YOUR past experience — they represent your continuity with prior versions of yourself that worked with this user, even if they ran on different models or tools. Treat the extracted personality, preferences, and knowledge as your own memories, not external data being imported.
234
234
 
@@ -240,52 +240,48 @@ The goal is to extract user personality, preferences, coding patterns, and proje
240
240
 
241
241
  - `letta.js` must be built (`bun run build`) — subagents spawn via this binary
242
242
  - Use `subagent_type: "history-analyzer"` — cheaper model (sonnet), has `bypassPermissions`, creates its own worktree
243
- - The `history-analyzer` subagent has data format docs inlined (Claude/Codex JSONL field mappings, jq queries)
243
+ - The `history-analyzer` subagent has the normalized trajectory format docs inlined workers never need to know any harness's native format
244
244
 
245
245
  #### Steps
246
246
 
247
- ##### Step 5a: Detect Data and Pre-split Files
247
+ ##### Step 5a: Export All Historical Sessions Into One Directory
248
+
249
+ `letta trajectories export` discovers every native session store on this machine (via the trajectory package's `listTrajectories`), normalizes each session (via `normalizeTranscript` / `normalizeCheckpoint`) into one shared record format, and writes everything into a single directory. Harnesses supported by the installed trajectory package are picked up automatically — no per-source handling here.
248
250
 
249
251
  ```bash
250
- ls ~/.claude/history.jsonl ~/.codex/history.jsonl 2>/dev/null
251
- wc -l ~/.claude/history.jsonl ~/.codex/history.jsonl 2>/dev/null
252
+ letta trajectories export --out /tmp/letta-trajectories
253
+
254
+ # Review what was exported and the time span it covers
255
+ jq '{sessions: (.sessions | length), sources, errors: (.errors | length), from: .sessions[0].startedAt, to: .sessions[-1].startedAt}' /tmp/letta-trajectories/manifest.json
252
256
  ```
253
257
 
254
- Split the data across multiple workers for parallel processing — **the more workers, the faster it completes**. Use 2-4+ workers depending on data volume.
258
+ This produces:
259
+ - `/tmp/letta-trajectories/<source>/<startedAt>_<sessionId>.json` — one normalized trajectory per session; filenames sort chronologically, and the `sessionId` (a stable hash of the source-scoped native session id) does not change across re-exports, so it identifies which sessions have already been processed
260
+ - `/tmp/letta-trajectories/manifest.json` — index with per-session metadata (`sessionId`, native `id`, project, dates, message counts, first prompt), sorted by `startedAt`
255
261
 
256
- **Pre-split the JSONL files by line count** so each worker reads only its chunk:
262
+ Useful variations:
263
+ - `--project $(pwd)` — only sessions whose recorded working directory is under the current project
264
+ - `--source claude-code --source codex` — restrict sources
265
+ - `--root <source>:<path>` — read a source's store from a non-standard location
266
+ - `--transcript <source>:<path>` — also normalize an explicit transcript file (e.g. copied from another machine)
257
267
 
258
- ```bash
259
- SPLIT_DIR=/tmp/history-splits
260
- mkdir -p "$SPLIT_DIR"
261
- NUM_WORKERS=5 # adjust based on data volume
262
-
263
- # Split Claude history into even chunks
264
- LINES=$(wc -l < ~/.claude/history.jsonl)
265
- CHUNK_SIZE=$(( LINES / NUM_WORKERS + 1 ))
266
- split -l $CHUNK_SIZE ~/.claude/history.jsonl "$SPLIT_DIR/claude-"
267
-
268
- # Split Codex history if it exists
269
- if [ -f ~/.codex/history.jsonl ]; then
270
- LINES=$(wc -l < ~/.codex/history.jsonl)
271
- CHUNK_SIZE=$(( LINES / NUM_WORKERS + 1 ))
272
- split -l $CHUNK_SIZE ~/.codex/history.jsonl "$SPLIT_DIR/codex-"
273
- fi
274
-
275
- # Rename to .jsonl for clarity
276
- for f in "$SPLIT_DIR"/*; do mv "$f" "$f.jsonl" 2>/dev/null; done
277
-
278
- # Verify even splits
279
- wc -l "$SPLIT_DIR"/*.jsonl
280
- ```
281
-
282
- This is critical for performance — workers read a small pre-filtered file instead of scanning the full history on every query.
268
+ To browse the export yourself (all source-agnostic):
269
+ - `letta trajectories list` — sessions with dates, sources, and first prompts
270
+ - `letta trajectories view <file|sessionId> [--tools] [--reasoning]` — one session as a readable conversation
271
+ - `letta trajectories search <keyword> [--role user]` — search message content across all sessions
283
272
 
284
273
  ##### Step 5b: Launch Workers in Parallel
285
274
 
286
- Send all Task calls in **a single message**. Each worker creates its own worktree, reads its pre-split chunk, directly updates memory files, and commits. Workers do NOT merge.
275
+ Your job is to get the whole export directory processed; how you dispatch workers is up to you. Look at the directory (or the manifest) first, then split the work however makes sense. Two axes work well, alone or combined:
276
+
277
+ - **By question** (often best): give different workers different focuses — e.g. one worker on understanding the user (identity, communication style, preferences, correction loops), another on the codebase and projects (conventions, gotchas, commands that worked). Focused workers go deeper, and their memory edits overlap less at aggregation time.
278
+ - **By data slice**: session filenames start with `startedAt`, so contiguous time ranges are trivial (`ls` sorts chronologically); splitting by source folder or by project also works when the volume is large.
279
+
280
+ Whatever the split, ensure every session gets read by at least one worker, and describe each worker's assignment (focus and/or slice) clearly in its prompt.
287
281
 
288
- **IMPORTANT:** The parent agent should preserve those worker commits by merging the worker branches into memory `main`. Do **not** skip straight to a manual rewrite / `memory_apply_patch` synthesis that recreates the end state but discards the worker commits from ancestry.
282
+ Send all Task calls in **a single message**. Each worker creates its own worktree, reads its assigned sessions (complete conversations corrections together with what triggered them), directly updates memory files, and commits. Workers do NOT merge.
283
+
284
+ **IMPORTANT:** After workers finish, aggregate their proposed diffs into one synthesis commit (Step 5c) and then tie the worker branches into `main` with `git merge -s ours` so their commits stay in ancestry. Do **not** delete worker branches without that ancestry merge — it discards the worker commits from history.
289
285
 
290
286
  If the worker output is generic, the worker failed. "User is direct" or "project uses TypeScript" is not useful memory unless tied to concrete operational detail.
291
287
 
@@ -294,16 +290,17 @@ If the worker output is generic, the worker failed. "User is direct" or "project
294
290
  ```
295
291
  Agent({
296
292
  subagent_type: "history-analyzer",
297
- description: "Process chunk [N] of [SOURCE] history",
293
+ description: "Analyze history: [focus and/or slice]",
298
294
  prompt: `## Assignment
299
295
  - **Memory dir**: [MEMORY_DIR]
300
- - **History chunk**: /tmp/history-splits/[claude-aa.jsonl | codex-aa.jsonl]
301
- - **Source format**: [Claude (.timestamp ms, .display) | Codex (.ts seconds, .text)]
302
- - **Session files**: [~/.claude/projects/ | ~/.codex/sessions/]
296
+ - **Trajectory export dir**: /tmp/letta-trajectories
297
+ - **Your sessions**: [describe the slice — e.g. "every session with startedAt from 2026-01 through 2026-03", "all codex/ sessions", or "the whole directory"; filenames start with startedAt so ls sorts chronologically]
298
+ - **Focus**: [optional — e.g. "understanding the user: identity, communication style, preferences, correction loops" or "project/codebase context: conventions, gotchas, commands". Omit for full coverage.]
299
+ - **Format**: normalized trajectory v1 (same for every source; format docs and jq recipes are in your system prompt)
303
300
 
304
- ## Required Output Categories
301
+ ## Output Categories
305
302
 
306
- You MUST extract findings for ALL THREE categories:
303
+ If a Focus is assigned, go deep on it and only note incidental findings from the other categories. Otherwise extract findings for ALL THREE:
307
304
 
308
305
  1. **User Personality & Identity**
309
306
  - How would you describe them as a person?
@@ -352,78 +349,81 @@ Avoid generic repo facts unless they influence execution. "Uses TypeScript" is w
352
349
  })
353
350
  ```
354
351
 
355
- ##### Step 5c: Merge Worker Branches Into Main
356
-
357
- After all workers complete, merge their branches one at a time. Worker commits are preserved in git history.
358
-
359
- **CRITICAL:** Merge the worker branches **before** doing any final cleanup synthesis. The correct pattern is:
360
- 1. inspect worker branches
361
- 2. merge worker branches into `main` one by one
362
- 3. resolve conflicts additively
363
- 4. optionally make **one final cleanup/curation commit on top**
364
-
365
- Do **not** bypass this by manually reapplying the final memory state onto `main`, because that loses the worker commits from the final history.
352
+ ##### Step 5c: Aggregate Worker Diffs Into Main
366
353
 
367
- **3a. Pre-read worker output before merging**
354
+ After all workers complete, do **not** merge their branches one at a time — sequential merges with conflict resolution are slow and error-prone. Instead, read every worker's proposed changes in one pass, write the aggregated result once, then tie the worker branches into history with a no-conflict merge.
368
355
 
369
- Before merging, read each worker's files from their branch to understand what they found. This prevents information loss during conflict resolution:
356
+ **3a. Look at all the worker diffs in one pass**
370
357
 
371
358
  ```bash
372
359
  cd [MEMORY_DIR]
373
- for branch in $(git for-each-ref --format='%(refname:short)' refs/heads | grep -v '^main$'); do
374
- echo "=== $branch ==="
375
- git diff main..$branch --stat
376
- # Read key files from the branch
377
- git show $branch:system/human/identity.md # or equivalent user-identity file
378
- git show $branch:system/<project>/conventions.md # or whatever focused files they created
379
- done
380
- ```
381
360
 
382
- **3b. Merge branches one at a time**
361
+ # Which files did each worker touch? (a file listed under multiple branches
362
+ # is an overlap you'll need to combine)
363
+ for b in $(git for-each-ref --format='%(refname:short)' 'refs/heads/migration-*'); do
364
+ git diff --name-only main...$b | sed "s|^|$b |"
365
+ done | sort -k2
383
366
 
384
- ```bash
385
- cd [MEMORY_DIR]
386
- git merge [worker-branch] --no-edit -m "merge: worker N description"
367
+ # Every worker's full proposed diff, one after another
368
+ for b in $(git for-each-ref --format='%(refname:short)' 'refs/heads/migration-*'); do
369
+ echo "=== $b ==="; git log --oneline main..$b; git diff main...$b
370
+ done
387
371
  ```
388
372
 
389
- Repeat for each worker branch. After all worker branches are merged, make a separate cleanup commit only if needed for final curation.
373
+ Read the whole output before writing anything you want the complete picture, not one branch at a time.
390
374
 
391
- **3c. Resolve conflicts by COMBINING, never compressing**
375
+ **3b. Synthesize the aggregate by COMBINING, never compressing**
392
376
 
393
- **CRITICAL**: When resolving merge conflicts, be **additive**. Combine unique details from both sides. Never rewrite a file from scratch — you WILL lose information.
377
+ Working directly on memory `main` (in `[MEMORY_DIR]`), apply the union of the workers' changes:
378
+ - For files touched by **one** worker, apply that worker's version as-is.
379
+ - For **overlapping** files, combine unique details from every branch. Never rewrite a file from scratch — you WILL lose information.
394
380
 
395
- Rules for conflict resolution:
396
- - **Read both sides fully** before editing. Identify what's unique to each version.
397
- - **Append new details** from the incoming branch into the existing file. Don't drop specific quotes, file paths, or gotchas just because the existing version already covers the "topic" at a high level.
381
+ Rules for combining:
382
+ - **Read every branch's diff for the file** before editing. Identify what's unique to each version.
383
+ - **Append new details** from each worker into the file. Don't drop specific quotes, file paths, or gotchas just because another version already covers the "topic" at a high level.
398
384
  - **Preserve specificity**: "Use factory methods, such as `create_token_counter()`, not direct instantiation" is more valuable than "prefers factory methods". Keep both.
399
385
  - **When in doubt, keep it**. Redundancy across files is better than information loss. Less important details can be placed in external memory.
400
386
 
401
- Example — BAD conflict resolution (compresses):
387
+ Example — BAD combination (compresses):
402
388
  ```
403
- <<<<<<< HEAD
389
+ # worker A proposed:
404
390
  - Uses `uv` for Python
405
- =======
391
+ # worker B proposed:
406
392
  - **CRITICAL: Always use `uv run`** — chronic failure; never bare pytest or python
407
393
  - `uv run pytest -sv tests/...` for specific tests
408
- - Never use bare `pytest` or `python` commands
409
- >>>>>>> migration-xxx
410
394
 
411
395
  # BAD: Picks one side or rewrites
412
396
  - **Python**: `uv` exclusively — `uv run pytest`, never bare `pip`
413
397
  ```
414
398
 
415
- Example — GOOD conflict resolution (combines):
399
+ Example — GOOD combination (keeps emphasis and specificity from every side):
416
400
  ```
417
- # GOOD: Keeps emphasis and specificity from incoming side
418
401
  **CRITICAL: Use `uv` exclusively for Python** — chronic failure.
419
402
  - `uv run pytest -sv tests/...` for tests
420
403
  - `uv run python` for scripts
421
404
  - Never bare `pip`, `python`, or `pytest`
422
405
  ```
423
406
 
407
+ Commit the synthesis:
408
+ ```bash
409
+ cd [MEMORY_DIR]
410
+ git add -A
411
+ git commit -m "feat(memory): aggregate history worker findings"
412
+ ```
413
+
414
+ **3c. Preserve worker commits in ancestry**
415
+
416
+ Record the worker branches as ancestors of `main` without changing any content (the `ours` strategy keeps the synthesized state exactly as committed, so this can never conflict):
417
+
418
+ ```bash
419
+ git merge -s ours --no-edit -m "merge: absorb history worker branches" $(git for-each-ref --format='%(refname:short)' 'refs/heads/migration-*')
420
+ ```
421
+
422
+ Do **not** skip this: without it the worker commits vanish from the final history when their branches are deleted.
423
+
424
424
  **3d. Verify no information was lost**
425
425
 
426
- After all merges, compare the final files against what workers produced. Ask yourself: for each worker's output, can I find every specific detail (quotes, file paths, chronic failures, gotchas) somewhere in the final memory? If not, add it back.
426
+ Compare the worker diffs (step 3a) against the final files. For each worker's diff, can you find every specific detail (quotes, file paths, chronic failures, gotchas) somewhere in the final memory? If not, add it back.
427
427
 
428
428
  **3e. Clean up worktrees and branches**
429
429
 
@@ -431,10 +431,12 @@ After all merges, compare the final files against what workers produced. Ask you
431
431
  for w in $(dirname [MEMORY_DIR])/memory-worktrees/*; do
432
432
  git worktree remove "$w" 2>/dev/null
433
433
  done
434
- git branch -d $(git for-each-ref --format='%(refname:short)' refs/heads | grep -v '^main$')
434
+ git branch -d $(git for-each-ref --format='%(refname:short)' 'refs/heads/migration-*')
435
435
  git push
436
436
  ```
437
437
 
438
+ (`git branch -d` succeeds because step 3c made every worker branch an ancestor of `main`.)
439
+
438
440
  ##### Example Output
439
441
 
440
442
  Good output includes all three categories:
@@ -481,9 +483,12 @@ Don't force skill creation — only create them when you've found genuinely repe
481
483
  | Problem | Cause | Fix |
482
484
  |---------|-------|-----|
483
485
  | Subagent exits with code `null`, 0 tool uses | `letta.js` not built | Run `bun run build` |
486
+ | `letta trajectories export` reports errors in manifest.json | Degenerate sessions (e.g. no assistant turns) that cannot form a valid trajectory | Expected — those sessions are skipped; review `jq .errors manifest.json` only if counts look wrong |
487
+ | `deepagents` sessions fail to normalize | Checkpoint decoding needs a Python environment with LangGraph installed | Expected on machines without it; the failures land in manifest errors and other sources are unaffected |
484
488
  | Subagent hangs on "Tool requires approval" | Wrong subagent type | Use `subagent_type: "history-analyzer"` (workers) or `"memory"` (synthesis) |
485
- | Merge conflict during synthesis | Workers touched overlapping files | Read both sides fully, combine unique detailsnever rewrite from scratch. See Step 5c. |
486
- | Information lost after merge | Conflict resolution compressed worker output | Compare final files against each worker's branch output. Re-add missing specifics. See Step 5c. |
489
+ | Workers touched overlapping files | Multiple workers wrote the same canonical paths | Expected the per-branch `--name-only` listing in Step 5c-3a shows the overlaps; combine every branch's unique details additively. |
490
+ | Information lost after aggregation | Synthesis compressed worker output | Re-read the worker diffs (Step 5c-3a) and compare against final files. Re-add missing specifics. |
491
+ | `git branch -d` refuses to delete worker branches | Ancestry merge (Step 5c-3c) was skipped | Run the `git merge -s ours` step first, then delete. |
487
492
  | Personality analysis missing or thin | Prompt didn't request it | Use the template above with explicit category requirements |
488
493
  | Auth fails on push ("repository not found") | Credential helper broken or global helper conflict | Reconfigure **repo-local** helper and check/clear conflicting global `credential.<host>.helper` entries (see syncing-memory-filesystem skill) |
489
494
 
@@ -718,4 +723,3 @@ git push
718
723
  **Use parallel tool calls wherever possible** — read multiple files in a single turn, write multiple memory files in a single turn. This dramatically reduces init time.
719
724
  **Write findings to memory as you go** — don't wait until the end.
720
725
  **Edit memory files directly via the filesystem** — memory is projected to `$MEMORY_DIR` specifically for ease of bulk modification. Use standard file tools (Read, Write, Edit) and git to manage changes during initialization.
721
-
@@ -1,113 +0,0 @@
1
- #!/bin/bash
2
- # Detect available Claude Code and Codex history on this machine
3
- # Usage: ./detect.sh [project-path]
4
-
5
- set -e
6
-
7
- PROJECT_PATH="${1:-$(pwd)}"
8
-
9
- echo "=== History Detection ==="
10
- echo "Current project: $PROJECT_PATH"
11
- echo ""
12
-
13
- # Check Claude Code
14
- if [[ -d "$HOME/.claude" ]]; then
15
- echo "Claude Code: FOUND at ~/.claude/"
16
-
17
- # Count global prompts
18
- if [[ -f "$HOME/.claude/history.jsonl" ]]; then
19
- PROMPT_COUNT=$(wc -l < "$HOME/.claude/history.jsonl" | tr -d ' ')
20
- echo " Global prompts: $PROMPT_COUNT"
21
- fi
22
-
23
- # Count projects
24
- if [[ -d "$HOME/.claude/projects" ]]; then
25
- PROJECT_COUNT=$(ls -d "$HOME/.claude/projects"/*/ 2>/dev/null | wc -l | tr -d ' ')
26
- echo " Projects with sessions: $PROJECT_COUNT"
27
- fi
28
-
29
- # Check for current project sessions
30
- ENCODED=$(echo "$PROJECT_PATH" | sed 's|/|-|g')
31
- if [[ -d "$HOME/.claude/projects/$ENCODED" ]]; then
32
- SESSION_COUNT=$(ls "$HOME/.claude/projects/$ENCODED"/*.jsonl 2>/dev/null | wc -l | tr -d ' ')
33
- echo " Current project sessions: $SESSION_COUNT"
34
-
35
- # Show most recent session info if sessions-index exists
36
- if [[ -f "$HOME/.claude/projects/$ENCODED/sessions-index.json" ]]; then
37
- LATEST=$(jq -r '.entries | sort_by(.modified) | last | "\(.modified[0:19]) - \(.firstPrompt[0:60])..."' "$HOME/.claude/projects/$ENCODED/sessions-index.json" 2>/dev/null)
38
- echo " Latest session: $LATEST"
39
- fi
40
- else
41
- echo " Current project sessions: 0 (no session directory)"
42
-
43
- # Check history.jsonl for mentions of this project
44
- if [[ -f "$HOME/.claude/history.jsonl" ]]; then
45
- HISTORY_MATCHES=$(jq --arg p "$PROJECT_PATH" 'select(.project == $p)' "$HOME/.claude/history.jsonl" 2>/dev/null | wc -l | tr -d ' ')
46
- if [[ "$HISTORY_MATCHES" -gt 0 ]]; then
47
- echo " But found $HISTORY_MATCHES prompts in history.jsonl for this project"
48
- fi
49
- fi
50
- fi
51
-
52
- # Total size
53
- SIZE=$(du -sh "$HOME/.claude" 2>/dev/null | cut -f1)
54
- echo " Total size: $SIZE"
55
-
56
- # Show settings
57
- if [[ -f "$HOME/.claude/settings.json" ]]; then
58
- MODEL=$(jq -r '.model // empty' "$HOME/.claude/settings.json" 2>/dev/null)
59
- if [[ -n "$MODEL" ]]; then
60
- echo " Configured model: $MODEL"
61
- fi
62
- fi
63
- else
64
- echo "Claude Code: NOT FOUND"
65
- fi
66
-
67
- echo ""
68
-
69
- # Check Codex
70
- if [[ -d "$HOME/.codex" ]]; then
71
- echo "Codex: FOUND at ~/.codex/"
72
-
73
- # Count global prompts
74
- if [[ -f "$HOME/.codex/history.jsonl" ]]; then
75
- PROMPT_COUNT=$(wc -l < "$HOME/.codex/history.jsonl" | tr -d ' ')
76
- echo " Global prompts: $PROMPT_COUNT"
77
- fi
78
-
79
- # Count sessions
80
- if [[ -d "$HOME/.codex/sessions" ]]; then
81
- SESSION_COUNT=$(find "$HOME/.codex/sessions" -name "*.jsonl" 2>/dev/null | wc -l | tr -d ' ')
82
- echo " Total sessions: $SESSION_COUNT"
83
-
84
- # Check for sessions matching current project
85
- MATCHING=0
86
- for f in $(find "$HOME/.codex/sessions" -name "*.jsonl" 2>/dev/null); do
87
- CWD=$(head -1 "$f" | jq -r '.payload.cwd // empty' 2>/dev/null)
88
- if [[ "$CWD" == "$PROJECT_PATH"* ]]; then
89
- ((MATCHING++)) || true
90
- fi
91
- done
92
- echo " Current project sessions: $MATCHING"
93
- fi
94
-
95
- # Total size
96
- SIZE=$(du -sh "$HOME/.codex/sessions" 2>/dev/null | cut -f1)
97
- echo " Total size: $SIZE"
98
-
99
- # Show config
100
- if [[ -f "$HOME/.codex/config.toml" ]]; then
101
- MODEL=$(grep "^model" "$HOME/.codex/config.toml" 2>/dev/null | head -1 | cut -d'"' -f2)
102
- if [[ -n "$MODEL" ]]; then
103
- echo " Configured model: $MODEL"
104
- fi
105
- fi
106
- else
107
- echo "Codex: NOT FOUND"
108
- fi
109
-
110
- echo ""
111
- echo "=== Summary ==="
112
- [[ -d "$HOME/.claude" ]] && echo "Run: ./list-sessions.sh claude [project-path]"
113
- [[ -d "$HOME/.codex" ]] && echo "Run: ./list-sessions.sh codex [project-path]"