trajectories 0.0.0 → 0.1.1
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/CHANGELOG.md +23 -0
- package/LICENSE +201 -0
- package/README.md +274 -2
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +8542 -0
- package/dist/convert.d.ts +31 -0
- package/dist/convert.js +431 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +8402 -0
- package/dist/log-baseline.d.ts +26 -0
- package/dist/log-baseline.js +104 -0
- package/dist/log-content.d.ts +16 -0
- package/dist/log-content.js +80 -0
- package/dist/log-io.d.ts +10 -0
- package/dist/log-io.js +121 -0
- package/dist/log-read.d.ts +24 -0
- package/dist/log-read.js +117 -0
- package/dist/log-reconcile.d.ts +5 -0
- package/dist/log-reconcile.js +38 -0
- package/dist/log-records.d.ts +35 -0
- package/dist/log-records.js +85 -0
- package/dist/log-recovery.d.ts +18 -0
- package/dist/log-recovery.js +123 -0
- package/dist/log-stage.d.ts +14 -0
- package/dist/log-stage.js +138 -0
- package/dist/log-state.d.ts +89 -0
- package/dist/log-state.js +92 -0
- package/dist/log-switch.d.ts +3 -0
- package/dist/log-switch.js +98 -0
- package/dist/log-types.d.ts +129 -0
- package/dist/log-types.js +8 -0
- package/dist/log.d.ts +8 -0
- package/dist/log.js +62 -0
- package/dist/migrate.d.ts +29 -0
- package/dist/migrate.js +173 -0
- package/dist/normalization-runtime.d.ts +1 -0
- package/dist/normalization-runtime.js +3150 -0
- package/dist/portable.d.ts +9 -0
- package/dist/portable.js +26 -0
- package/dist/readers/canonical.d.ts +13 -0
- package/dist/readers/canonical.js +54 -0
- package/dist/readers/cline.d.ts +10 -0
- package/dist/readers/cline.js +107 -0
- package/dist/readers/cursor.d.ts +20 -0
- package/dist/readers/cursor.js +374 -0
- package/dist/readers/deepagents.d.ts +41 -0
- package/dist/readers/deepagents.js +163 -0
- package/dist/readers/fx.d.ts +11 -0
- package/dist/readers/fx.js +573 -0
- package/dist/readers/github-copilot.d.ts +8 -0
- package/dist/readers/github-copilot.js +216 -0
- package/dist/readers/grok-build.d.ts +12 -0
- package/dist/readers/grok-build.js +391 -0
- package/dist/readers/guards.d.ts +4 -0
- package/dist/readers/guards.js +121 -0
- package/dist/readers/pi-compaction.d.ts +7 -0
- package/dist/readers/pi-compaction.js +112 -0
- package/dist/readers/pi-context.d.ts +13 -0
- package/dist/readers/pi-context.js +64 -0
- package/dist/store.d.ts +25 -0
- package/dist/store.js +218 -0
- package/dist/types.d.ts +91 -0
- package/dist/types.js +1 -0
- package/dist/writers/claude-code.d.ts +5 -0
- package/dist/writers/claude-code.js +51 -0
- package/dist/writers/cline.d.ts +3 -0
- package/dist/writers/cline.js +77 -0
- package/dist/writers/codex.d.ts +3 -0
- package/dist/writers/codex.js +32 -0
- package/dist/writers/cursor.d.ts +3 -0
- package/dist/writers/cursor.js +197 -0
- package/dist/writers/deepagents.d.ts +3 -0
- package/dist/writers/deepagents.js +116 -0
- package/dist/writers/entropy.d.ts +5 -0
- package/dist/writers/entropy.js +33 -0
- package/dist/writers/fx.d.ts +3 -0
- package/dist/writers/fx.js +135 -0
- package/dist/writers/github-copilot.d.ts +3 -0
- package/dist/writers/github-copilot.js +71 -0
- package/dist/writers/grok-build.d.ts +3 -0
- package/dist/writers/grok-build.js +43 -0
- package/dist/writers/helpers.d.ts +17 -0
- package/dist/writers/helpers.js +75 -0
- package/dist/writers/omp.d.ts +3 -0
- package/dist/writers/omp.js +7 -0
- package/dist/writers/opencode.d.ts +3 -0
- package/dist/writers/opencode.js +65 -0
- package/dist/writers/pi.d.ts +3 -0
- package/dist/writers/pi.js +45 -0
- package/docs/cline-native-format.md +43 -0
- package/docs/copilot-native-format.md +78 -0
- package/docs/cursor-native-format.md +103 -0
- package/docs/deepagents-native-format.md +98 -0
- package/docs/evidence-api.md +170 -0
- package/docs/fx-native-format.md +87 -0
- package/docs/harness-parity-bootstrap.md +78 -0
- package/docs/harness-support-parity.md +107 -0
- package/docs/inspirations.md +103 -0
- package/docs/ledger-migration.md +141 -0
- package/docs/pi-compaction-context.md +75 -0
- package/docs/pi-provider-context.md +76 -0
- package/docs/research/2026-10-06-huihua-and-oar.md +176 -0
- package/docs/research/ledger/README.md +96 -0
- package/docs/research/ledger/confer/2026-09-13-round-10/README.md +61 -0
- package/docs/research/ledger/confer/2026-09-13-round-2/cass.md +72 -0
- package/docs/research/ledger/confer/2026-09-13-round-3/README.md +70 -0
- package/docs/research/ledger/confer/2026-09-13-round-5/README.md +61 -0
- package/docs/research/ledger/confer/2026-09-13-round-6/README.md +68 -0
- package/docs/research/ledger/confer/2026-09-13-round-7/README.md +64 -0
- package/docs/research/ledger/confer/2026-09-13-round-9/README.md +59 -0
- package/docs/research/ledger/confer/2026-09-14-wake/wake.md +146 -0
- package/docs/research/ledger/docs/inspirations.md +320 -0
- package/docs/research/ledger/docs/pr2-pr6-integration.md +53 -0
- package/docs/research/ledger/docs/research/2026-09-07-confer-inspirations.md +163 -0
- package/docs/research/ledger/docs/research/2026-09-07-letta-continuous-service.md +104 -0
- package/docs/research/ledger/docs/research/2026-09-08-claude-history-retrieval.md +117 -0
- package/docs/research/ledger/docs/research/2026-09-09-agentsview-native-discovery.md +87 -0
- package/docs/research/ledger/docs/research/2026-09-09-daemon-observation.md +231 -0
- package/docs/research/ledger/docs/research/2026-09-09-discovery-pagination.md +114 -0
- package/docs/research/ledger/docs/research/2026-09-09-harness-transcript-contract.md +145 -0
- package/docs/research/ledger/docs/research/2026-09-09-native-history-discovery.md +180 -0
- package/docs/research/ledger/docs/research/2026-09-09-native-history-implementation.md +137 -0
- package/docs/research/ledger/docs/research/2026-09-09-other-inspirations.md +279 -0
- package/docs/research/ledger/docs/research/2026-09-09-trajectory-and-letta-code.md +128 -0
- package/docs/research/ledger/docs/research/2026-09-13-diagnostics-coverage.md +116 -0
- package/docs/research/ledger/docs/research/2026-09-13-fts-rebuild.md +83 -0
- package/docs/research/ledger/docs/research/2026-09-13-read-path-split.md +74 -0
- package/docs/research/ledger/docs/research/2026-09-13-runtime-rollout.md +102 -0
- package/docs/research/ledger/docs/research/2026-09-13-scan-outcomes.md +80 -0
- package/docs/research/ledger/docs/research/2026-09-13-search-quality.md +105 -0
- package/docs/research/ledger/docs/research/2026-09-13-source-coverage.md +64 -0
- package/docs/research/ledger/docs/research/2026-09-13-sync-wall-budget.md +82 -0
- package/docs/research/ledger/docs/research/2026-09-13-typed-read-gate.md +81 -0
- package/docs/research/ledger/docs/research/2026-09-13-writer-lease.md +84 -0
- package/docs/research/ledger/docs/research/2026-09-16-c1-copy-fallback.md +227 -0
- package/docs/research/ledger/docs/research/2026-09-16-c10-kimi.md +414 -0
- package/docs/research/ledger/docs/research/2026-09-16-c2-derive-counter.md +216 -0
- package/docs/research/ledger/docs/research/2026-09-16-c3-echo-filter.md +305 -0
- package/docs/research/ledger/docs/research/2026-09-16-c4-title-index.md +349 -0
- package/docs/research/ledger/docs/research/2026-09-16-c5-trigram.md +268 -0
- package/docs/research/ledger/docs/research/2026-09-16-c6-recency-prior.md +438 -0
- package/docs/research/ledger/docs/research/2026-09-16-c7-tombstones.md +467 -0
- package/docs/research/ledger/docs/research/2026-09-16-c8-remote-truth.md +390 -0
- package/docs/research/ledger/docs/research/2026-09-16-c9-grok.md +380 -0
- package/docs/research/ledger/docs/research/2026-09-16-wake-port-program.md +38 -0
- package/docs/research/ledger/docs/research/2026-09-17-cursor-blobstore.md +157 -0
- package/docs/research/ledger/manifest.json +540 -0
- package/legacy/NOTICE.md +50 -0
- package/legacy/bin/ledger-core.ts +7 -0
- package/legacy/bin/ledger.ts +7 -0
- package/legacy/bin/traj-bridge.ts +7 -0
- package/legacy/scripts/import-claude-history.ts +130 -0
- package/legacy/scripts/native-history-smoke.ts +52 -0
- package/legacy/scripts/observe-daemon.ts +570 -0
- package/legacy/scripts/retitle-sessions.md +19 -0
- package/legacy/scripts/verify-runtime-rollout.ts +151 -0
- package/legacy/src/canonical.ts +108 -0
- package/legacy/src/cli.ts +1293 -0
- package/legacy/src/db.ts +2254 -0
- package/legacy/src/diagnostics.ts +87 -0
- package/legacy/src/discovery.ts +56 -0
- package/legacy/src/embeddings.ts +382 -0
- package/legacy/src/filter.ts +602 -0
- package/legacy/src/gemini_embeddings.ts +103 -0
- package/legacy/src/identity.ts +9 -0
- package/legacy/src/index.ts +10 -0
- package/legacy/src/ingest.ts +791 -0
- package/legacy/src/managed.ts +178 -0
- package/legacy/src/native/common.ts +68 -0
- package/legacy/src/native/cursor.ts +647 -0
- package/legacy/src/native/grok.ts +540 -0
- package/legacy/src/native/kimi.ts +706 -0
- package/legacy/src/native/opencode.ts +470 -0
- package/legacy/src/native/sqlite-ro.ts +281 -0
- package/legacy/src/native.ts +97 -0
- package/legacy/src/normalizer.ts +457 -0
- package/legacy/src/parentage.ts +562 -0
- package/legacy/src/pressure.ts +162 -0
- package/legacy/src/private-storage.ts +74 -0
- package/legacy/src/reader.ts +1255 -0
- package/legacy/src/scanner.ts +591 -0
- package/legacy/src/schema-gate.ts +263 -0
- package/legacy/src/schema.ts +829 -0
- package/legacy/src/semantic-top-k.ts +71 -0
- package/legacy/src/session-hash.ts +49 -0
- package/legacy/src/store-status.ts +218 -0
- package/legacy/src/sync-preparation.ts +45 -0
- package/legacy/src/sync-truth.ts +843 -0
- package/legacy/src/sync.ts +1219 -0
- package/legacy/src/types.ts +436 -0
- package/legacy/src/vocab.txt +30522 -0
- package/legacy/src/watch.ts +673 -0
- package/legacy/src/writer-lease.ts +310 -0
- package/ops/README.md +120 -0
- package/ops/install-cli.sh +63 -0
- package/ops/install-release.sh +49 -0
- package/ops/linux/install-systemd-user.sh +103 -0
- package/ops/macos/install-launchd.sh +72 -0
- package/ops/sync-settings.sh +37 -0
- package/package.json +19 -5
- package/skills/trajectories/SKILL.md +138 -0
- package/skills/trajectories/scripts/trajectories_recent.sh +26 -0
- package/skills/trajectories/scripts/trajectories_search.sh +26 -0
- package/index.js +0 -1
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
# iAmCorey/Wake — confer 2026-09-14 (adapters, trigram FTS, identity, SSH mirror, resume)
|
|
2
|
+
|
|
3
|
+
## Outcome
|
|
4
|
+
|
|
5
|
+
Wake (Rust + GPUI desktop app, MIT, v0.6.5, 18 agent sources, 34.4k LOC src + 6.6k LOC tests) is the closest cousin yet — same inputs, opposite product shape. Ranked candidates; nothing here is a dependency proposal.
|
|
6
|
+
|
|
7
|
+
1. **Copy-fallback read-only SQLite for locked/in-use stores.** Gradient: `SQLITE_OPEN_READ_ONLY` + a probe query to prove usability → copy `db` + `-wal` + `-shm` into a temp dir and read the copy → give up; never `immutable=1` (unsafe under a concurrent WAL writer), temp dir cleaned on drop. Ledger opens readonly with `busy_timeout` and emits a `read_error` diagnostic, so a store held by its own CLI costs coverage.
|
|
8
|
+
2. **Self-referential echo filter on the FTS projection.** Wake excludes the agent's *own* Wake lookups (`wake_*` MCP tools; `wake-cli`/`wake-mcp` shell calls) from indexed units, and raises an `FTS_FORMAT` counter so every existing index re-derives once on upgrade. Ledger indexes the transcripts of the very agents that call `ledger search`.
|
|
9
|
+
3. **Title index, ranked ahead of body hits.** Separate `titles_fts` (trigram, `key UNINDEXED`); title hits are emitted first as `role="title"`, `seq=0`, jumping to session start — never a fabricated seq. Ledger's `records_fts` has no title column, so titles are unsearchable today.
|
|
10
|
+
4. **Trigram tokenization as a measured trade, not a switch.** `trigram case_sensitive 0` buys substring/code-identifier/CJK search (`useEffect(`), but *any* whitespace segment under 3 codepoints degrades the whole query to `LIKE %seg%` — exactly what `porter unicode61` does natively. An explicit decision round, not a silent swap.
|
|
11
|
+
|
|
12
|
+
Lower-value, still extractable: a derive-rule version counter separate from the schema version; tombstone double-track (path + logical key) so a delete survives re-scans; a per-agent `resume_args` + `requires_cwd` table that *withholds* the action when a source cannot honor it.
|
|
13
|
+
|
|
14
|
+
## Reproducibility
|
|
15
|
+
|
|
16
|
+
- Pin for all citations: `iAmCorey/Wake@d9f702b6df0e85763f8ab597c09bf4ca6a168db4` (= v0.6.5, released 2026-09-14, HEAD; abbreviated `wake@d9f702b6`). Clone: `git clone --depth 100 https://github.com/iAmCorey/Wake /tmp/ledger-confer/wake` (read-only, kept outside the Ledger tree, never copied in).
|
|
17
|
+
- Line-verified by direct read (`sed -n`/`grep -n`) in every citation: `crates/wake-core/src/{db,scanner,remote,watcher,models}.rs`, `adapters/{mod,claude,codex,copilot,kiro,antigravity,sqlite_ro}.rs`, `services/terminal/{mod,macos}.rs`, `mcp/{mod,tools}.rs`, `tests/adapter_contracts.rs`, both `Cargo.toml`s, `CHANGELOG.md`. Ledger inspected read-only.
|
|
18
|
+
- Not run: no `cargo build`, no test suite, no binary, no app launch. Everything behavioural is a static read of a shallow clone; anything from a summary rather than an opened file is `[SCOUT]` or `[INFERRED]`. No Ledger tests run.
|
|
19
|
+
- Maturity: first release 0.1.0 on 2026-08-18, v0.6.5 today (33 releases); macOS-first, experimental Linux/Windows. The data layer reads as a rewrite of already-paid-for lessons, not a first draft.
|
|
20
|
+
|
|
21
|
+
## Findings
|
|
22
|
+
|
|
23
|
+
### 1. Source adapters: 18 agents, one contract, per-source sidecars
|
|
24
|
+
|
|
25
|
+
- **Coverage.** `AgentId::ALL` = claude-code, codex, grok, dsh, cursor, opencode, pi, omp, kiro, kimi, gemini, copilot, antigravity, qoder, hermes, openclaw, codebuddy, workbuddy OBSERVED `models.rs#L7-L40`. Ledger discoverable 14 + `atif` declared only OBSERVED `archeism/ledger:packages/core/src/scanner.ts#L22-L44`, `types.ts#L9-L25`.
|
|
26
|
+
- **Wake-only banks (8):** Kiro `~/.kiro/sessions/cli/<uuid>.{jsonl,json,history}` (`{kind:Prompt|AssistantMessage}` rows; `.json` sidecar carries cwd/title/times, `.history` ignored) OBSERVED `adapters/kiro.rs#L10-L12`; Antigravity **metadata-only** — the transcript is encrypted `.pb`, the only plaintext is `~/.gemini/antigravity-cli/conversation_summaries.db`, so its detail page is one synthetic System message saying so OBSERVED `adapters/antigravity.rs#L9-L13`; Copilot CLI as a SQLite `~/.copilot/session-store.db` (`sessions` + `turns`, dirty-detected by `updated_at` plus summed body length) OBSERVED `adapters/copilot.rs#L10-L13`; plus Grok, DSH (zstd logs decoded transparently), Kimi, Qoder, CodeBuddy, WorkBuddy.
|
|
27
|
+
- **Layout deltas on shared sources** (worth more than the new names): Gemini CLI read from `~/.gemini/tmp/**/chats` + `projects.json`; Codex also from `archived_sessions` OBSERVED `adapters/codex.rs#L24-L33`; OpenCode v2 from `opencode-next.db` OBSERVED `remote.rs#L93-L101`. Ledger uses `~/.gemini/sessions` and `session-state` dirs for Copilot OBSERVED `scanner.ts#L39-L44`, and has no archived/next path string anywhere in `packages/core` (grep). On this host `.copilot` holds only `ide/` and `.gemini` has neither `sessions` nor `tmp`, while `.kiro`, `.qoder`, `.grok`, `.antigravity` exist — Wake's extra banks carry data here; which shared layout is current is unproven either way, so do not "fix" Ledger from this alone.
|
|
28
|
+
- **Contract.** `list_session_files()` must stay cheap ("enumeration never full-parses"; SQLite sources run a metadata query, dsh a bounded first line) and degrades in place to an empty list rather than aborting the scan; `detect()` is derived from `data_roots()` and must not be overridden, so panel and scan cannot disagree OBSERVED `adapters/mod.rs#L39-L48`. `quick_meta` + per-adapter `merge_quick_meta` precedence: Codex takes a user-renamed title from `state_5.sqlite` over the first-message derivation, adopts the thread id as key, but keeps the file's `source` because it is more precise than the DB class OBSERVED `adapters/codex.rs#L739-L825`; `manages_parent_links()` distinguishes "no children now" (clear stale edges) from "unsupported" OBSERVED `adapters/mod.rs#L95-L109`.
|
|
29
|
+
- **Malformed data.** Per-line tolerance with explicit known-skip lists; unparseable or unknown rows increment `unknown_lines` and continue, with exact counts (including deliberate junk like `wibble-part`) pinned per source OBSERVED `adapters/claude.rs#L118-L152`, `tests/adapter_contracts.rs#L356`, `#L683`, `#L2583`. **But the signal is dropped:** `sessions.unknown_lines` is inserted as a literal `0`, omitted from the `ON CONFLICT DO UPDATE` set, and unread by the UI crate OBSERVED `db.rs#L1968-L1991` + repo-wide grep — the same loss Ledger's cycle-1 diagnostics work closed.
|
|
30
|
+
|
|
31
|
+
### 2. Search: trigram DDL, per-segment AND, recency-multiplied bm25, honest degradation
|
|
32
|
+
|
|
33
|
+
- **DDL.** `messages_fts` is external-content (`content='messages', content_rowid='id'`) with `tokenize="trigram case_sensitive 0"`; `titles_fts` is standalone with `key UNINDEXED` OBSERVED `db.rs#L63-L67`, `#L126-L130`. SQLite is bundled (`rusqlite 0.32 features=["bundled"]`) OBSERVED `Cargo.toml#L14`, so the trigram tokenizer and its `case_sensitive` option exist.
|
|
34
|
+
- **Query.** Whitespace segments, each quoted as a phrase (embedded quotes doubled), joined with `AND` — substring per term, not adjacency OBSERVED `db.rs#L1587-L1591`. Any segment under 3 codepoints switches the *whole* query to `m.text LIKE '%seg%' ESCAPE '\' AND …` ordered by timestamp, with a hand-built `make_like_snippet` OBSERVED `db.rs#L1544`, `#L1632-L1650`. Degradation is *returned*, not swallowed: `search_with → (hits, degraded)` OBSERVED `#L1539`.
|
|
35
|
+
- **Ranking.** `ORDER BY bm25(messages_fts) * (1.0 + 1.0/(1.0 + max(0, ? - s.updated_at)/2592000000.0))` — bm25 is negative, so a ×1.0–×2.0 recency factor promotes recent sessions (today ×2, 30d ×1.5, 1y ×1.08), built from arithmetic + `max()` only (no math extension), keyed on the *session's* `updated_at` so intra-session order is untouched, and the degraded LIKE path keeps time ordering OBSERVED `db.rs#L1546-L1560`. Title hits rank above body hits through the second table, `role="title"`, `seq=0`, jump to session start, "title has no transcript row, do not fabricate a seq" OBSERVED `#L1676-L1700`; recency + title search + echo filter all shipped in 0.6.5 OBSERVED `CHANGELOG.md#L3-L13`.
|
|
36
|
+
- **Derive-rule versioning.** `FTS_FORMAT: &str = "2"` in `schema_meta`; a mismatch on open raises `fts_reindex`, and the next scan re-parses *every* file including mtime/size-unchanged ones, clearing the flag after a scan with no parse failures OBSERVED `db.rs#L134-L136`, `#L176-L196`, `scanner.rs#L179`, `#L440`. Newest column/table are tracked separately so read-only consumers refuse an old DB up front instead of dying mid-query OBSERVED `db.rs#L231-L233`, `#L327-L328`.
|
|
37
|
+
- **Freshness is disclosed, never implied.** Every MCP reply carries "Index covers activity up to {t} (local time); Wake keeps it fresh while it is running", and prints "Index freshness unknown: …" instead of omitting the line OBSERVED `mcp/tools.rs#L409-L413`.
|
|
38
|
+
- **Ledger gap this targets:** `records_fts` is `porter unicode61` over records with no title column OBSERVED `archeism/ledger:packages/core/src/schema.ts#L11-L21`; widening is zero-hit-only prefix-OR with typed skip reasons OBSERVED `reader.ts#L302-L314`; the residual common-prefix cost class is recorded at issue #34.
|
|
39
|
+
|
|
40
|
+
### 3. Identity and lifecycle: file-keyed, mtime-arbitrated, tombstoned, whole-session replace
|
|
41
|
+
|
|
42
|
+
- **Key.** `session_key(agent, host, native_id)`; the host segment keeps two machines' same-UUID sessions apart. `sessions.file_path` is `UNIQUE`, and the dedup domain is that same key, which the comment argues makes "dedup domain == key segmentation" structural OBSERVED `models.rs#L616-L622`, `db.rs#L27-L48`, `scanner.rs#L232-L240`. Ledger's identity is source-scoped with an appendable v2 content hash — a different axis (provenance, not file arbitration).
|
|
43
|
+
- **Copy arbitration.** Same-key candidates across locations are ordered by (newest mtime, then lexicographically smallest path); the winner is queued and the losers are retained as a **parse-failure fallback order**, so a corrupt winner cannot erase the session. `write_session_guarded` repeats the comparison *inside* the write transaction, because check-then-write races a concurrent incremental scan and lets the loser land last OBSERVED `scanner.rs#L240-L263`, `#L389-L420`, `db.rs#L372-L399`.
|
|
44
|
+
- **Rewrite/truncate.** No generation model: the transaction deletes all messages for the key (with explicit FTS5 `'delete'` rows, required by external content), upserts the session, reinserts the units OBSERVED `db.rs#L1923-L1966`. A truncated source *replaces* the visible history under the same key and no prior generation survives — Ledger's staged replacement plus the open retention boundary is ahead, and Wake is evidence that "replace wholesale" is what you get without a retention requirement.
|
|
45
|
+
- **Deletion.** `tombstones(file_path PK, key, deleted_at)` written in the same transaction as the row removal; enforcement is double-track, by path *and* logical key, so another location's copy cannot resurrect a user-deleted session OBSERVED `db.rs#L76-L80`, `#L531-L570`, `#L1002-L1018`, `scanner.rs#L219-L227`. Stars/pins live in `user_data` and survive a rebuild OBSERVED `db.rs#L69-L74`.
|
|
46
|
+
- **Scan lifecycle.** Dirty = changed mtime/size (`known_files()`), owner-changed path, forced reindex, or full scan; "in the DB but not enumerated" → row removed (absence is not a deletion, so no tombstone); longest-root ownership resolves overlapping custom roots OBSERVED `scanner.rs#L341-L350`, `#L200-L217`, `adapters/mod.rs#L359`. Watcher: `notify`, 800 ms debounce, FSEvents loss raises `on_rescan_needed` OBSERVED `watcher.rs#L1-L20`, `scanner.rs#L21-L24`.
|
|
47
|
+
- **Concurrency honesty.** A process-level `SCAN_GATE` mutex serializes scans in-process and the comment states outright that it does not cover two processes, that closing the window would need a shared cross-process lock, and "for the same reason do not add `--force`"; index creation arbitrates with `hard_link` (create-if-absent) and defers to whoever won OBSERVED `scanner.rs#L55-L135`. No cross-process writer lock exists; Ledger's `writer-lease.ts` is ahead, and the value here is the named residual risk rather than an implied guarantee.
|
|
48
|
+
- **Dedup.** Cross-host duplicates (two remotes pointing at one machine) are deduplicated in *stats only* — `ROW_NUMBER() OVER (PARTITION BY agent_id, native_id, created_at ORDER BY updated_at DESC, host)`, with a comment on why `native_id` alone is insufficient (Hermes ids are small integers) — while both rows stay browsable OBSERVED `db.rs#L1319-L1340`. There is no cross-agent dedup at all.
|
|
49
|
+
|
|
50
|
+
### 4. Remote hosts: probe-then-mirror rsync pull, where failure is never emptiness
|
|
51
|
+
|
|
52
|
+
- **Shape.** Not remote reads: whitelisted paths are `rsync`'d from the remote home into `<data dir>/remotes/<host>/` keeping the remote layout, and a `RemoteAdapter` decorator mounts each bank via `with_custom_root`, so adapters, parsers and FTS are remoteness-unaware OBSERVED `remote.rs#L1-L18`, `adapters/mod.rs#L134`. System `ssh`/`rsync` are shelled out rather than an SSH library, so `~/.ssh/config` aliases, ProxyJump and IdentityAgent are inherited, with `-oBatchMode=yes -oConnectTimeout=10` so a TTY-less GUI process can never hang on a passphrase OBSERVED `#L8-L12`, `#L248`.
|
|
53
|
+
- **Probe first, mirror second.** One `ssh host sh -c '…[ -e p ]…'` tests each whitelist path; only paths that exist go to `rsync -R --delete`, and whitelist entries missing remotely are deleted from the cache. The full whitelist must not be fed to rsync, with measured reasons: openrsync (macOS 15+) aborts the entire file list when one source's parent is missing (later sources silently untransferred, exit code only 23), and any sender-side I/O error suppresses the delete phase, so `--delete` would never fire on a host with only some agents installed OBSERVED `#L13-L22`, `#L264-L305`.
|
|
54
|
+
- **Failure semantics.** A probe failure fails the sync and leaves the cache untouched ("cannot treat 'cannot connect' as 'the remote is empty'"); rsync exit 24 (source vanished mid-transfer) is tolerated *only* when every error line is a missing source, matched against both GNU and openrsync dialects OBSERVED `#L328-L360`, `#L403-L431`. Per-host `last_sync_at`/`last_sync_error` are persisted and surfaced OBSERVED `db.rs#L116-L122`.
|
|
55
|
+
- **Cache lifecycle.** The mirror is disposable: removing a host purges its cache, because an in-flight rsync cannot be cancelled and would write the removed tree back OBSERVED `#L202-L222`. Host names are validated (no `:` — the host lands in the session key and in argv) OBSERVED `#L194-L200`; credentials are excluded by whitelist construction; remote sessions are read-only in the app and cannot be trashed.
|
|
56
|
+
- **For ADR-0005.** This is the *pull* sibling of the push path (tiers A instrumented / B cooperative hook / C scan-only, `archeism/ledger` PR #13, issue #14 still blocked). Wake has no push buffer, so it says nothing about tier-0's drop-vs-retry. What transfers is the truthfulness set: unreachable ≠ empty, partial ≠ complete, a cache has an explicit lifecycle and is deletable, identity carries the host, and an unprobeable transport must not be assumed.
|
|
57
|
+
|
|
58
|
+
### 5. Resume: one capability table, cwd-conditional, no dead actions
|
|
59
|
+
|
|
60
|
+
- **One table, two shapes.** `resume_args(meta) -> Option<(Vec<String>, bool)>`: claude `--resume <id>` (requires cwd), codex `resume <id>`, qoder `--resume <id>` (cwd-bucketed history), copilot `--resume=<id>`, opencode/pi/kimi `--session <id>` (v2 switches binary via `session_bin`), omp/grok `--resume <id>`, antigravity `--conversation=<id>`, dsh `npx @deepseek-ai/dsh web` with cwd as the workspace (no per-session resume exists), hermes `--profile <profile> --resume <id>` (the profile flag must always be passed, to override the sticky active profile) OBSERVED `services/terminal/mod.rs#L104-L195`.
|
|
61
|
+
- **Refusal is designed in.** Kiro, Gemini CLI, OpenClaw (its TUI opens by session *key* while Wake stores the session id) and WorkBuddy (desktop only) return `None`, so `resume_targets` returns nothing and no menu item exists that would only fail when clicked OBSERVED `#L190-L195`, `#L267-L283`. macOS routes GUI hosts through deep links (`kooky://resume`, `claude://resume?session=`) rather than assuming a shell OBSERVED `services/terminal/macos.rs#L29-L45`, `#L133-L140`.
|
|
62
|
+
- **Remote resume** is a copied, never-executed command: `ssh -t <host> 'exec $SHELL -lic '\''cd <cwd> && <cli> <args>'\'''`. Two decisions worth keeping: the CLI is a bare name resolved against the *remote* PATH (a local absolute path is meaningless there), and the inner command runs under a login + interactive shell because sshd hands a non-interactive shell that reads no rc files, so nvm/volta-installed CLIs are `command not found` — the 0.6.5 changelog records exactly that fix OBSERVED `#L226-L256`, `CHANGELOG.md#L8`. cwd is remote, so a local `is_dir` check is deliberately skipped: non-empty → `cd`, empty → the ssh default home OBSERVED `#L236-L240`.
|
|
63
|
+
- INFERENCE for Ledger: resume binding is already validated on our side; the extractable piece is the *capability table with a cwd precondition and refusal*, which is what makes "resume this" honest per source. The terminal plumbing is out of scope for a headless store.
|
|
64
|
+
|
|
65
|
+
### 6. Architecture and license
|
|
66
|
+
|
|
67
|
+
- **MIT, no rider.** Plain MIT text (Corey Chiu, 2026) and `license = "MIT"` OBSERVED `Cargo.toml#L8`. Patterns — even code — are borrowable with attribution; nothing here was copied and no dependency is proposed (Rust vs TypeScript, different products). One wrinkle: the UI crate depends on `gpui` from `zed-industries/zed` and `gpui-component` by git revision OBSERVED `crates/wake/Cargo.toml#L17-L19`; gpui upstream is GPL-3.0, so do not vendor UI code from this repo. `[INFERRED]` — transitive licenses not audited.
|
|
68
|
+
- **Shape.** `wake-core` is a pure data layer with no UI dependency; two read-only siblings ship beside the binary. `wake-mcp` (stdio JSON-RPC, four tools: search/list/get/projects) opens the index with `Store::open_read_only` and never rebuilds or migrates it; `wake-cli` prints the same payloads, asserted byte-for-byte apart from a trailing newline OBSERVED `mcp/mod.rs#L12`, `#L225-L228`, README. Same read-only-consumer discipline Ledger wants, plus the rule that a *stale* index is tolerated while a *foreign* one is refused up front.
|
|
69
|
+
- **Complementary, not competing.** Wake is a desktop browser over files the user already has: no daemon, no supervision, no canonical record model, no coverage/fidelity declaration, no raw retention, an index explicitly rebuildable at any time ("do not add `--force`"). Ledger owns durable records, parentage, cursors and retention; Wake owns the human surface and "one window over eighteen CLIs". Nothing here argues for a UI; it argues that a read-only second consumer of the index is cheap and that freshness must be printed.
|
|
70
|
+
|
|
71
|
+
### 7. Parentage census (follow-up probe, same pin)
|
|
72
|
+
|
|
73
|
+
- **One durable single-parent edge, two producers.** `sessions.parent_key`
|
|
74
|
+
(`db.rs#L46`, index `idx_sessions_parent` `#L173`), added by ALTER with a
|
|
75
|
+
`grok_parent_backfill` flag that force-reparses Grok on old DBs (`#L156-L171`).
|
|
76
|
+
Recursive descendant CTE (`#L1167-L1170`), children list (`#L1125`), root/child
|
|
77
|
+
count filters (`#L1781-L1804`). `replace_parent_links` does a full per-agent
|
|
78
|
+
replace and reports whether anything changed (`#L478-L525`); it also rewrites
|
|
79
|
+
the child's `project_path`/`project_name` to the parent's (`#L496-L509`), and
|
|
80
|
+
unlinking re-parses the child to restore its fallback project
|
|
81
|
+
(`scanner.rs#L505-L521`).
|
|
82
|
+
- **Producers.** Grok: the main session dir's own subagent registry (child id →
|
|
83
|
+
direct parent id + parent cwd) in `grok_group.rs#L16-L38`, emitted as
|
|
84
|
+
`(grok:child, grok:parent)` at `#L42-L56`; subagent transcripts ARE separate
|
|
85
|
+
sessions and get `parent_key` (`grok.rs#L403-L447`). Hermes: DB `parent_id`,
|
|
86
|
+
accepted only when the parent id exists in the SAME profile DB
|
|
87
|
+
(`hermes.rs#L505-L521`). All other 15 adapters take the default
|
|
88
|
+
`false`/empty (`adapters/mod.rs#L97-L109`); `RemoteAdapter` delegates
|
|
89
|
+
(`remote.rs#L144-L157`). The capability bit exists so an agent whose links
|
|
90
|
+
change clears stale edges while an unsupported agent's rows are left alone;
|
|
91
|
+
the scanner keeps only edges whose parent is owned by the same winning
|
|
92
|
+
snapshot, then flattens each child to the transitive ROOT
|
|
93
|
+
(`scanner.rs#L546-L560`, caller `#L449-L523`).
|
|
94
|
+
- **Claude `subagents/`:** not sessions, not folded, not parented. `file_ref`
|
|
95
|
+
returns None for `/subagents/` and `/memory/` paths (`claude.rs#L591-L597`);
|
|
96
|
+
sidechain files are discovered by `list_sidechains` (`#L468+`) and attached to
|
|
97
|
+
the matching mainline Task call by `tool_use_id` (`tc.sidechain_ref`,
|
|
98
|
+
`#L556-L573`), fetched on demand via `load_sidechain` (`#L578-L588`).
|
|
99
|
+
`parse_session` parses with `include_sidechain=false`, so in-file sidechain
|
|
100
|
+
rows are skipped (`#L176`) — subagent text never enters FTS through the
|
|
101
|
+
parent; only the parent's Task call line is searchable. Deleting a session
|
|
102
|
+
trashes the whole `<id>/` sidecar dir (`#L600-L606`).
|
|
103
|
+
- **Cursor:** same `subagents/` dir, but no meta sidecar and the mainline Task
|
|
104
|
+
call carries no id — transcripts listed as sidechains with no link
|
|
105
|
+
(`cursor.rs#L374-L394`), not top-level sessions (`#L345-L347`); dir trashed
|
|
106
|
+
together (`#L354`). **CodeBuddy:** `<sessionId>/subagents/agent-*.jsonl`
|
|
107
|
+
explicitly "must not become top-level sessions" (`codebuddy.rs#L438`); `<id>/`
|
|
108
|
+
dir trashed with the session (`#L469`).
|
|
109
|
+
- **OMP / Pi:** no parentage at all. `PiAdapter::omp()` reuses the Pi parse
|
|
110
|
+
core on `~/.omp/agent/sessions` (`pi.rs#L34-L43`); recursive enumeration
|
|
111
|
+
makes a nested `<parent>/<child>.jsonl` its own standalone session with
|
|
112
|
+
native id = stem segment after the last `_` (`pi.rs#L51-L53`, `#L173-L175`;
|
|
113
|
+
parse_utils#L227-L260), `parent_key` empty. **Codex:** `session_meta` is read
|
|
114
|
+
only for cwd, originator→source and git branch (`codex.rs#L348-L363`); no
|
|
115
|
+
parent/spawn field is read anywhere, rollouts standalone (`#L488`).
|
|
116
|
+
- Sidebar: messages carry `sidechain_id` (`db.rs#L56`); search can return
|
|
117
|
+
sidechain hits (`#L1598`, `#L1765`) even though some user-message
|
|
118
|
+
aggregations exclude them (`#L1309`).
|
|
119
|
+
|
|
120
|
+
## Ledger comparison
|
|
121
|
+
|
|
122
|
+
| Dimension | Wake @d9f702b6 | Ledger (working tree) |
|
|
123
|
+
| --- | --- | --- |
|
|
124
|
+
| Sources | 18 agents, per-source fixtures; Kiro/Grok/Kimi/Qoder/CodeBuddy/WorkBuddy/Antigravity/DSH beyond us | 14 discoverable + `atif` declared only; 8 of Wake's banks absent |
|
|
125
|
+
| Shared layouts | Gemini `~/.gemini/tmp/**/chats`; Copilot `session-store.db`; Codex `archived_sessions`; OpenCode `opencode-next.db` | `~/.gemini/sessions`; Copilot `session-state` dirs; no archived/next paths |
|
|
126
|
+
| Read discipline | readonly + probe → copy `db`/`-wal`/`-shm` → give up; never `immutable=1` | readonly + `busy_timeout`; WAL sidecars tracked, WAL store missing sidecars refused; no copy fallback |
|
|
127
|
+
| Malformed data | per-line counters + skip lists, exact counts in tests; column hardwired to 0, never surfaced | durable `ingest_diagnostics` per (source, session, code) — ahead |
|
|
128
|
+
| Search index | FTS5 `trigram case_sensitive 0`, external content, separate `titles_fts` | FTS5 `porter unicode61` over records; no title column |
|
|
129
|
+
| Query | segments → quoted phrase each, `AND`; any segment <3 cp degrades all to `LIKE`, reported | prefix-OR widening, zero-hit only, typed skip reasons; common-prefix floor at #34 |
|
|
130
|
+
| Ranking | `bm25 × recency(30d)`; titles first; snippet/highlight | `rank ASC, started_at DESC`; no recency term |
|
|
131
|
+
| Identity | `agent:host:native_id`, `file_path UNIQUE`, dirty = mtime+size | source-scoped identity, appendable content hash, cursors |
|
|
132
|
+
| Rewrite | whole-session replace in one transaction; no generation retained | staged replacement + transactional promotion; retention still open |
|
|
133
|
+
| Dedup | same key across locations: mtime winner + fallback order; cross-host deduped in stats only | cross-source convergence is ADR-0005 work |
|
|
134
|
+
| Deletion | tombstone path+key in the same transaction; system Trash | archive deletion/privacy policy still open |
|
|
135
|
+
| Writers | in-process mutex only; `hard_link` arbitration; "don't add `--force`" | `writer-lease.ts` (heartbeat + lock) — ahead |
|
|
136
|
+
| Remote | SSH rsync pull into `remotes/<host>/`, probe-then-mirror, read-only in app | none; ADR-0005 tiers proposed, #14 blocked |
|
|
137
|
+
| Resume | per-agent argv table + `requires_cwd`; unavailable → no action | source-bound resume validation; no launch |
|
|
138
|
+
| Surfaces | `wake-mcp` read-only + `wake-cli` byte-identical; freshness printed per reply | CLI + robot/semantic/hybrid; envelope work is a round-1 candidate |
|
|
139
|
+
| License | MIT; UI deps reach GPL-3.0 gpui upstream | n/a |
|
|
140
|
+
|
|
141
|
+
## Boundaries
|
|
142
|
+
|
|
143
|
+
- **License verdict: MIT, clean.** No rider, no CLA-adjacent restriction in-tree: patterns and code may be adapted with attribution. This document copies nothing; if a candidate is later built, label it "adapted from an MIT reference" (or clean-room if written without the source in view). Do not vendor `gpui`/`gpui-component` — GPL-3.0 upstream `[INFERRED]`, unaudited.
|
|
144
|
+
- **What Ledger must not adopt:** wholesale session replacement with no retained generation; a diagnostics counter that reaches the DB as a constant zero; a metadata-only card for an encrypted source (Antigravity) contributing an index row that asserts nothing but a preview; stats-level dedup that leaves duplicate rows browsable; no cross-process writer lock (the participating-writer gap round 1 already ranked for a later cycle).
|
|
145
|
+
- **Non-goals this round:** Wake's GPUI/UI code and its `wake_get_session` Markdown projection; Insights/export/trash plumbing; i18n; packaging, installers and Windows/Linux desktop integration; MCP tool schemas beyond freshness. Its ssh/rsync transport is *not* a proposal for ADR-0005's deferred transport — the tiers in PR #13 stay the decision to argue with.
|
|
146
|
+
- **Evidence class:** no build, no test run, no binary, no app launch; static reads of a shallow clone at `d9f702b6` kept outside the Ledger tree, plus one read-only probe of local agent directories to see which banks carry data. No Ledger tests run; no Ledger file outside this one was modified.
|
|
@@ -0,0 +1,320 @@
|
|
|
1
|
+
# Inspirations
|
|
2
|
+
|
|
3
|
+
Ledger uses Letta Trajectory as its canonical normalization dependency and
|
|
4
|
+
combines operational and retrieval lessons from the other projects below.
|
|
5
|
+
|
|
6
|
+
See the [2026-09-07 Confer comparison](research/2026-09-07-confer-inspirations.md)
|
|
7
|
+
for pinned source evidence, research-agent review and implementation gates.
|
|
8
|
+
|
|
9
|
+
## Integrated baseline
|
|
10
|
+
|
|
11
|
+
PR2 and PR6 are merged at `56b51e2b76d8d37f749bb114f5b73f1e40164cf9`.
|
|
12
|
+
The [integration record](pr2-pr6-integration.md) documents schema-6 migrations,
|
|
13
|
+
source-scoped identity and parentage, atomic records/cursor commits, staged
|
|
14
|
+
replacement, bounded JSONL ingestion, retryable enrichment, paginated discovery,
|
|
15
|
+
and startup/periodic reconciliation. Its combined gate records **152 passed,
|
|
16
|
+
0 failed, 959 assertions across 17 files**, with typecheck passing. This is not
|
|
17
|
+
runtime acceptance. The subsequent
|
|
18
|
+
[daemon observation](research/2026-09-09-daemon-observation.md) passed after the
|
|
19
|
+
PR7 watcher/installer fixes at `6bd64b7`: automatic import and three appends,
|
|
20
|
+
preserved historical retrieval, and continued bounded backfill were observed.
|
|
21
|
+
The report retains failed attempts, resource measurements, and unresolved
|
|
22
|
+
Cursor/OpenCode import and retry gaps. Full corpus coverage and raw archival
|
|
23
|
+
retention remain unverified.
|
|
24
|
+
|
|
25
|
+
Fresh evidence: [Trajectory and Letta Code](research/2026-09-09-trajectory-and-letta-code.md)
|
|
26
|
+
and [Cass, AgentsView, Obelisk and AI Harnesses](research/2026-09-09-other-inspirations.md).
|
|
27
|
+
The [discovery and transcript-contract comparison](research/2026-09-09-harness-transcript-contract.md)
|
|
28
|
+
distinguishes exported-transcript parsing, local-store discovery, and Vercel's
|
|
29
|
+
common harness interface.
|
|
30
|
+
The [native-history discovery comparison](research/2026-09-09-native-history-discovery.md)
|
|
31
|
+
checks the next step against Cass and Obelisk: Cass reads Cursor/OpenCode native
|
|
32
|
+
stores, while Obelisk has no provider for either at the inspected revision.
|
|
33
|
+
The [AgentsView native-reader audit](research/2026-09-09-agentsview-native-discovery.md)
|
|
34
|
+
adds snapshot, fingerprint and watch-plan evidence. Ledger now implements native
|
|
35
|
+
Cursor/OpenCode discovery and assembly while retaining Trajectory normalization;
|
|
36
|
+
see the [implementation verification](research/2026-09-09-native-history-implementation.md)
|
|
37
|
+
for tested boundaries, failed attempts and deployment status.
|
|
38
|
+
Their earlier PR comparisons retain their historical pins; use the integration
|
|
39
|
+
record above for current implementation status, not their in-progress findings.
|
|
40
|
+
|
|
41
|
+
## Letta Trajectory
|
|
42
|
+
|
|
43
|
+
Source: [letta-ai/trajectory](https://github.com/letta-ai/trajectory)
|
|
44
|
+
|
|
45
|
+
Trajectory demonstrates that heterogeneous native agent transcripts can be
|
|
46
|
+
normalized into a stable canonical representation. Particularly important:
|
|
47
|
+
|
|
48
|
+
- source-specific adapters;
|
|
49
|
+
- stable source identity and ordering;
|
|
50
|
+
- canonical record and content hashes;
|
|
51
|
+
- deduplication-oriented records;
|
|
52
|
+
- explicit normalization diagnostics;
|
|
53
|
+
- support for partial transcript fragments.
|
|
54
|
+
|
|
55
|
+
Ledger uses the published `@letta-ai/trajectory` package. Retain this dependency
|
|
56
|
+
for canonicalization; any replacement requires evidence and an explicit decision.
|
|
57
|
+
The September 9 source refresh found upstream and installed version `0.3.0`
|
|
58
|
+
unchanged; integration did not replace the normalizer.
|
|
59
|
+
Parsing support does not imply local-store discovery: Cursor and OpenCode are
|
|
60
|
+
explicitly normalization-only sources in this version. Both public
|
|
61
|
+
`listTrajectories()` probes return `listing_unavailable`; callers must locate
|
|
62
|
+
the expected capture or assembled session export. Ledger now supplies native
|
|
63
|
+
SQLite/legacy discovery and assembly for these sources, plus validated capture
|
|
64
|
+
and export discovery. It does not classify arbitrary JSON/JSONL files as
|
|
65
|
+
conversations. See the [contract comparison](research/2026-09-09-harness-transcript-contract.md).
|
|
66
|
+
Trajectory is primarily a normalizer; Ledger's additional concern is the
|
|
67
|
+
durable system that stores, relates, enriches, and serves those records.
|
|
68
|
+
|
|
69
|
+
## Letta Code continuous service and Dream
|
|
70
|
+
|
|
71
|
+
Source: [letta-ai/letta-code](https://github.com/letta-ai/letta-code)
|
|
72
|
+
|
|
73
|
+
Letta Code is a separate implementation reference from its Trajectory dependency.
|
|
74
|
+
Its server command exposes remote-computer and local App Server modes; the
|
|
75
|
+
runtime owns scheduled work and reflection integration. Relevant patterns are:
|
|
76
|
+
|
|
77
|
+
- explicit service startup, ownership and signal-driven shutdown;
|
|
78
|
+
- process-scoped scheduling with persisted ownership leases and run outcomes;
|
|
79
|
+
- reflection evaluation after a capture attempt, with duplicate-launch guards;
|
|
80
|
+
- explicit client-to-Cloud reflection ownership cutover;
|
|
81
|
+
- memory-worktree integration before reflection completion is finalized.
|
|
82
|
+
|
|
83
|
+
See the [pinned code review](research/2026-09-07-letta-continuous-service.md).
|
|
84
|
+
The September 9 refresh corrects the capture-success assumption: the listener
|
|
85
|
+
catches append failures and can still evaluate reflection. Ordering is not a
|
|
86
|
+
committed-evidence gate; Ledger must own that prerequisite.
|
|
87
|
+
These mechanisms do not establish an always-on cross-harness transcript indexer,
|
|
88
|
+
exactly-once execution, or measured memory bounds. Ledger keeps its own durable
|
|
89
|
+
ingestion and findings/promotion boundaries; this is not a new dependency.
|
|
90
|
+
|
|
91
|
+
## Obelisk
|
|
92
|
+
|
|
93
|
+
Source: [tommy0103/obelisk](https://github.com/tommy0103/obelisk)
|
|
94
|
+
|
|
95
|
+
Obelisk demonstrates a useful execution-memory projection over native coding
|
|
96
|
+
agent history. Particularly important:
|
|
97
|
+
|
|
98
|
+
- one provider adapter contract over different native stores;
|
|
99
|
+
- a canonical record stream before persistence;
|
|
100
|
+
- explicit `agent_id` and `parent_tool_use_id` linkage;
|
|
101
|
+
- separate subagent, workflow, and workflow-agent records;
|
|
102
|
+
- raw-source lookup from normalized messages;
|
|
103
|
+
- SQLite and CodeAct queries as a practical local interface.
|
|
104
|
+
|
|
105
|
+
Obelisk's limitation for Ledger is not source availability: it is open source
|
|
106
|
+
under AGPL-3.0. The limitation is dependency shape. Its `@obelisk/core` workspace
|
|
107
|
+
is private and unpublished, and its capture is primarily post-hoc reconstruction
|
|
108
|
+
of harness-native artifacts. Ledger should not copy or embed that code without an
|
|
109
|
+
explicit licensing decision. An eventual Obelisk adapter should consume a stable
|
|
110
|
+
export, database contract, CLI/service boundary, or independently implemented
|
|
111
|
+
projection.
|
|
112
|
+
|
|
113
|
+
## Cass
|
|
114
|
+
|
|
115
|
+
Source: [coding_agent_session_search](https://github.com/dicklesworthstone/coding_agent_session_search)
|
|
116
|
+
(indexed as `dicklesworthstone/cass` in Confer).
|
|
117
|
+
|
|
118
|
+
Research targets: cross-harness lexical, semantic and hybrid retrieval; machine
|
|
119
|
+
output contracts; incremental indexing; index health and recovery. Adopt proven
|
|
120
|
+
operational patterns while preserving Letta's canonicalization contract.
|
|
121
|
+
The September 9 refresh records a nonstandard license rider; these observations
|
|
122
|
+
are not clearance to reuse Cass's implementation or import its engine.
|
|
123
|
+
Its current Cursor/OpenCode connectors are re-exported from the pinned
|
|
124
|
+
`franken-agent-detection` crate. They read source-specific SQLite layouts and
|
|
125
|
+
selected native files, assembling their own normalized conversations rather
|
|
126
|
+
than calling Trajectory. The [native-history comparison](research/2026-09-09-native-history-discovery.md)
|
|
127
|
+
records exact coverage, exclusions, and the distinction from Ledger's scanner.
|
|
128
|
+
|
|
129
|
+
## AgentsView
|
|
130
|
+
|
|
131
|
+
Source: [kenn-io/agentsview](https://github.com/kenn-io/agentsview)
|
|
132
|
+
|
|
133
|
+
Research targets: a writable daemon owning SQLite, file watching with periodic
|
|
134
|
+
reconciliation, initial synchronization, and a web surface for session retrieval.
|
|
135
|
+
Integrated `watch` reconciles at startup and on an interval, persists cursors with
|
|
136
|
+
records, skips unchanged sources, and budgets imports. JSONL uses a 1 MiB chunk
|
|
137
|
+
target with adaptive individual records up to 64 MiB by default. These are input
|
|
138
|
+
limits, not peak-RSS guarantees; non-JSONL adapters can still read whole inputs,
|
|
139
|
+
and continuity/session hashing can require history-linear work. Durable backfill
|
|
140
|
+
fairness, coverage reporting, participating-writer ownership and a web surface
|
|
141
|
+
remain followups; OS supervision alone does not provide them.
|
|
142
|
+
|
|
143
|
+
The [native-reader audit](research/2026-09-09-agentsview-native-discovery.md)
|
|
144
|
+
informed Ledger's independently implemented read-only SQLite snapshots, WAL-aware
|
|
145
|
+
invalidation, selective Cursor fields and legacy OpenCode joins. Native imports
|
|
146
|
+
rotate oldest attempts within the discovered page to prevent active sessions
|
|
147
|
+
starving older candidates; this is not full-corpus pagination or per-session
|
|
148
|
+
database digest optimization.
|
|
149
|
+
|
|
150
|
+
## Vercel AI SDK v7 Harnesses
|
|
151
|
+
|
|
152
|
+
Source: [vercel/ai harness packages](https://github.com/vercel/ai/tree/main/packages/harness)
|
|
153
|
+
|
|
154
|
+
AI SDK Harnesses demonstrate a live cross-harness event boundary. Particularly
|
|
155
|
+
important:
|
|
156
|
+
|
|
157
|
+
- one stream contract for text, reasoning, tools, usage, file changes,
|
|
158
|
+
compaction, errors, and raw events;
|
|
159
|
+
- harness lifecycle state for suspend, continue, detach, and resume;
|
|
160
|
+
- turn, step, and tool telemetry;
|
|
161
|
+
- durable workflow checkpoints;
|
|
162
|
+
- pluggable harness adapters.
|
|
163
|
+
|
|
164
|
+
The unified stream is an excellent live ingestion seam, but it is not a canonical
|
|
165
|
+
trajectory store. Child-agent fidelity also varies by adapter, so Ledger must not
|
|
166
|
+
assume the top-level stream contains a complete nested execution.
|
|
167
|
+
|
|
168
|
+
## Wake
|
|
169
|
+
|
|
170
|
+
Source: [iAmCorey/Wake](https://github.com/iAmCorey/Wake)
|
|
171
|
+
|
|
172
|
+
Wake is a native desktop application (Rust + GPUI, MIT) that aggregates
|
|
173
|
+
coding-agent sessions read-only from eighteen harness banks into one searchable,
|
|
174
|
+
resumable window. It is the closest product cousin so far — same inputs,
|
|
175
|
+
opposite shape: no daemon, no canonical record model, no retention; the human
|
|
176
|
+
surface instead of the durable store. Particularly important:
|
|
177
|
+
|
|
178
|
+
- copy-fallback read-only SQLite for locked stores: a probe query first, then a
|
|
179
|
+
copy of `db`/`-wal`/`-shm` into a temp dir, never `immutable=1`;
|
|
180
|
+
- FTS5 trigram tokenization with honest degradation — any query containing a
|
|
181
|
+
segment too short for trigram degrades entirely to `LIKE`, and the
|
|
182
|
+
degradation is returned to the caller, not swallowed — plus a separate
|
|
183
|
+
title index ranked ahead of body hits;
|
|
184
|
+
- a derive-rule version counter distinct from the schema version that forces
|
|
185
|
+
one full index re-derivation on upgrade;
|
|
186
|
+
- remote mirroring failure semantics: unreachable is never treated as empty,
|
|
187
|
+
partial is never complete, and the mirror cache has an explicit lifecycle;
|
|
188
|
+
- a per-agent resume capability table with a cwd precondition and refusal,
|
|
189
|
+
so no resume action exists that would only fail when clicked.
|
|
190
|
+
|
|
191
|
+
Evidence: [2026-09-14 confer deep-dive](../confer/2026-09-14-wake/wake.md),
|
|
192
|
+
pinned at `d9f702b6` (v0.6.5). Wake's whole-session replace without retained
|
|
193
|
+
generations, stats-only deduplication, and in-process-only scan lock are
|
|
194
|
+
counter-examples Ledger is already ahead of; its breadth extends the known
|
|
195
|
+
source space (Kiro, Antigravity metadata-only, Copilot `session-store.db`,
|
|
196
|
+
Gemini `tmp/**/chats`, Codex `archived_sessions`, OpenCode `opencode-next.db`)
|
|
197
|
+
beyond Ledger's current banks. MIT permits pattern reuse with attribution;
|
|
198
|
+
its UI crate reaches [`gpui`](https://github.com/zed-industries/zed) upstream,
|
|
199
|
+
which is GPL-3.0 per unaudited transitive license, so no UI code may be
|
|
200
|
+
vendored.
|
|
201
|
+
|
|
202
|
+
## Concrete adoption plan
|
|
203
|
+
|
|
204
|
+
Target ownership is one Ledger service. Each inspiration supplies a specific
|
|
205
|
+
component or a pattern we can implement within it. Only Trajectory is an adopted
|
|
206
|
+
dependency; resemblance to another project's feature is not proof its code was
|
|
207
|
+
ported. This plan does not add dependencies or claim new runtime guarantees.
|
|
208
|
+
|
|
209
|
+
| Reference | How we use or learn from it | Ledger responsibility and state |
|
|
210
|
+
| --- | --- | --- |
|
|
211
|
+
| Letta Trajectory | Call the published normalizer from our adapters. | Native group identity is separate from Ledger keys; canonical records and cursors commit together. Recovered Claude prompt slices share identity helpers and migration coverage. Raw source retention and historical record versions remain future work. |
|
|
212
|
+
| Cass | Adapt machine-readable search, source-bound resume validation and operational recovery patterns. | Lexical/hybrid search, robot output and integration recovery regressions exist. Evidence-bearing completeness reporting, served-index validation and vague-query coverage remain targets; no separate Cass engine is proposed. |
|
|
213
|
+
| AgentsView | Follow daemon/watch/reconciliation and capture-publication boundaries; study evidence-bound findings and eligibility rechecks. | Startup/periodic reconciliation, import budgets, persisted cursors and staged replacement are integrated. Fair resumable backfill, visible coverage, raw retention and continuous findings publication remain work. Staged index replacement is not staged curation. |
|
|
214
|
+
| Obelisk | Study explicit delegation relationships and writer/transaction boundaries, then implement Ledger's contracts independently. | Source-backed parentage is integrated. Richer relationship provenance/conflicts, workflows and participating-writer coordination remain followups. No copying, vendoring or derived code without an explicit licensing decision. |
|
|
215
|
+
| AI SDK Harnesses | Add an optional live-event adapter for sessions we run through that interface. | Future input path. Persist event identity and replay progress; continue native-file ingestion for sessions outside that runtime. |
|
|
216
|
+
| Letta Code | Adapt service ownership, scheduled-run outcomes and reflection completion rules. | Future Dream worker over committed evidence. Analysis failures must not stop capture or search; publishing findings and promoting them into memory remain separate actions. |
|
|
217
|
+
| Wake | Evaluate copy-fallback read-only SQLite access and trigram tokenization against our locked-store coverage loss and the issue #34 common-prefix floor; hold its remote-mirroring truthfulness set (unreachable ≠ empty, partial ≠ complete) as the reference for the ADR-0005 cooperation tiers proposed in PR #13 (tracked in issue #14); borrow the derive-rule counter and title-index patterns when the search index next changes. | Patterns only; not a dependency (Rust desktop application, MIT). MIT permits adaptation with attribution; no UI code ([`gpui`](https://github.com/zed-industries/zed) upstream is GPL-3.0 per unaudited transitive license). |
|
|
218
|
+
|
|
219
|
+
The historical pinned [Confer review](research/2026-09-07-confer-inspirations.md) and
|
|
220
|
+
[Letta Code review](research/2026-09-07-letta-continuous-service.md) contain the
|
|
221
|
+
specific implementation ranges, caveats and proposed tests. For example,
|
|
222
|
+
[Trajectory explicitly assigns truncation/replacement generations to its caller](https://github.com/letta-ai/trajectory/blob/21ae92d10579499b183d93929c85da0b91233167/CANONICAL.md#L47-L94);
|
|
223
|
+
the library cannot make our mutable source files into an archive.
|
|
224
|
+
|
|
225
|
+
### The data path
|
|
226
|
+
|
|
227
|
+
Target archival and continuous-curation architecture. The ingestion mechanics
|
|
228
|
+
above are integrated; retained raw generations, historical record versions,
|
|
229
|
+
the human UI and Dream below remain targets:
|
|
230
|
+
|
|
231
|
+
```text
|
|
232
|
+
OS supervisor (launchd/systemd)
|
|
233
|
+
Ledger ingestion service: backfill + watch + periodic reconciliation
|
|
234
|
+
native files/databases or optional live events
|
|
235
|
+
-> retained raw source generations + provenance
|
|
236
|
+
-> adapters using Trajectory -> versioned canonical records
|
|
237
|
+
-> rebuildable search indexes -> agent CLI / human UI
|
|
238
|
+
|
|
239
|
+
Dream worker: committed evidence -> attributed, versioned findings
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
Raw capture still needs a retention boundary before advancing capture progress.
|
|
243
|
+
Normalized records and cursors now commit together; that does not retain prior
|
|
244
|
+
raw generations. Search should be rebuildable from retained evidence. Watch
|
|
245
|
+
notifications reduce delay, reconciliation catches missed work, and supervision
|
|
246
|
+
handles process restart; operational acceptance remains pending. Scheduled Dream
|
|
247
|
+
and continuous curation are separate from ingestion and require durable findings,
|
|
248
|
+
invalidation and separately authorized promotion.
|
|
249
|
+
|
|
250
|
+
### Start with the failure we actually encountered
|
|
251
|
+
|
|
252
|
+
The [eval-reference recovery](https://github.com/archeism/ledger/blob/43081aef54c23b4bd017b6c0e11fc42a9a1cb381/docs/case-studies/2026-09-09-recovering-the-eval-reference.md)
|
|
253
|
+
exposed both a missing source and a missing preservation guarantee. At the
|
|
254
|
+
research baseline `571c144`, `saveSession` replaced previous session records when
|
|
255
|
+
content changed. The merged integration now keeps existing sessions searchable
|
|
256
|
+
while a replacement is staged and promotes it transactionally, including after
|
|
257
|
+
restart. This improves snapshot-index recovery; it does not retain every source
|
|
258
|
+
generation after publication or establish the archival boundary above.
|
|
259
|
+
|
|
260
|
+
The smallest next implementation should preserve a captured source generation
|
|
261
|
+
before indexing it, track subsequent truncation/replacement explicitly, and prove
|
|
262
|
+
that the original reference survives source repair and a search-index rebuild.
|
|
263
|
+
Use a small synthetic fixture for the archival failure test; keep the private
|
|
264
|
+
recovery case as a separately scoped retrieval regression. Archival crash/restart,
|
|
265
|
+
duplicate-import and rebuild-from-retained-evidence gates are additional to the
|
|
266
|
+
integrated records/cursor and replacement-staging tests.
|
|
267
|
+
|
|
268
|
+
Recovered prompt-history slices now remain idempotent after migration. Complete
|
|
269
|
+
automatic coverage and fair, restart-resumable enumeration are not established
|
|
270
|
+
by the integrated reconciliation loop.
|
|
271
|
+
Coordinate CLI and daemon writers, expose unsupported/failed/pending sources, and
|
|
272
|
+
improve retrieval against the preserved failed queries. Extend relationship
|
|
273
|
+
provenance and workflows beyond current parentage; live capture, UI and Dream
|
|
274
|
+
remain later work. Explicit archive deletion and privacy exclusions need their
|
|
275
|
+
own policy; source truncation is not authorization to erase captured evidence.
|
|
276
|
+
|
|
277
|
+
### How a borrowed pattern becomes a Ledger change
|
|
278
|
+
|
|
279
|
+
For each change: name the observed failure, cite the pinned upstream mechanism,
|
|
280
|
+
check the license and installed API, write a Ledger-owned failing test, implement
|
|
281
|
+
the smallest fix, and rerun the gate. Record whether we adopted a dependency,
|
|
282
|
+
adapted an algorithm or independently implemented behavior. Do not label code
|
|
283
|
+
clean-room merely because it was rewritten in another language.
|
|
284
|
+
|
|
285
|
+
No upstream code was copied for this plan. Ledger must establish its own storage,
|
|
286
|
+
progress, privacy and recovery guarantees through implementation and tests.
|
|
287
|
+
|
|
288
|
+
## Session parentage coverage
|
|
289
|
+
|
|
290
|
+
Trajectory remains the record SoT. It does not store a parent/child session
|
|
291
|
+
edge (`source_group_id` is this transcript's own id; `MetaRecord` is cwd,
|
|
292
|
+
branch, and model). Ledger folds source-proved parentage beside those records.
|
|
293
|
+
Do not copy AGPL Obelisk code.
|
|
294
|
+
|
|
295
|
+
The upstream inventory below preserves the historical PR6 parentage comparison;
|
|
296
|
+
it is not a new census of current upstream support. The integration record and
|
|
297
|
+
September 9 research above distinguish merged behavior from remaining gaps.
|
|
298
|
+
|
|
299
|
+
| Inspiration | What it actually does with subagents |
|
|
300
|
+
|---|---|
|
|
301
|
+
| Trajectory | Lists Claude parent and standalone `subagents/` files as separate groups; drops sidechain rows inside a parent file; does **not** list OMP nested `<parent>/<child>.jsonl`; ATIF embedded `subagent_trajectories` are dropped. No parent field. |
|
|
302
|
+
| Obelisk | Five providers only: Claude (path + `.meta.json`, child folded into parent), Codex (`session_meta` / spawn, folded), Pi (`parentSession`), DeepSeek (`parentSession` + file tree), Kimi (`parent_tool_use_id`). DeepSeek and Kimi are not Ledger sources. |
|
|
303
|
+
| Cass | 26 connectors. Indexes Claude `subagents/` files as conversations, then **skips** them by default (`**/subagents/*.jsonl`). No parentage graph. |
|
|
304
|
+
| AgentsView | Broadest parentage map. Ledger overlap: Claude path/sessionId/meta, Codex `session_meta`, Pi `branchedFrom`, OMP `parentSession` + nested sibling, Hermes `parent_session_id`, OpenCode `parentID` / `parent_id`. Its OpenClaw parser ignores header parent fields. Cursor has a `subagents/` path in tests, not a parent field. Gemini CLI, OpenHands, and Copilot CLI have no session-parent field. Many AgentsView-only harnesses (Zed, Roo, Qoder, …) are out of Ledger scope. |
|
|
305
|
+
| AI SDK Harnesses | Live stream. Child-agent fidelity varies by adapter; not a transcript parentage SoT. |
|
|
306
|
+
| Letta Code service | Scheduling and Dream. Not parentage. |
|
|
307
|
+
| Wake (censused 2026-09-14 at `d9f702b6`, census persisted in the [confer file](../confer/2026-09-14-wake/wake.md) §7) | One durable single-parent edge (`sessions.parent_key`), produced only by Grok (its own subagent registry) and Hermes (same-profile `parent_id`); children flatten to the transitive root and inherit the parent's project. Claude `subagents/` files are discovered but hidden — attached to the mainline Task call by `tool_use_id`; their text is never indexed, so only the parent's Task call line is searchable. Cursor/CodeBuddy child dirs are hidden and unlinked; OMP/Pi nested files are standalone sessions; Codex `session_meta` is read for cwd/branch only, no parent. |
|
|
308
|
+
|
|
309
|
+
Integrated parentage sources (source-backed, independently implemented):
|
|
310
|
+
`claude-code`, `codex`, `pi`, `openclaw` (same SessionManager header), `omp`
|
|
311
|
+
(header plus nested sibling), `hermes`, `opencode` (`parentID` / SQLite
|
|
312
|
+
`parent_id`), `cursor` (`subagents/` path when present), `grok`
|
|
313
|
+
(`subagents/<child>/meta.json` registry under the parent, read at scan time) and
|
|
314
|
+
`kimi` (`<parent>/subagents/<agent>/` path under the parent's session directory,
|
|
315
|
+
plus the parent wire's `parent_tool_call_id` binding to the spawning call).
|
|
316
|
+
|
|
317
|
+
Left unimplemented until a source field or path proves the edge:
|
|
318
|
+
`gemini-cli`, `copilot-cli`, `letta-code`, `openhands`, `deepagents`, `droid`,
|
|
319
|
+
`atif`. OpenCode SQLite discovery and session/message/part assembly now exist;
|
|
320
|
+
the earlier extra-scanner discovery gap is superseded by the native readers.
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# PR2 and PR6 integration
|
|
2
|
+
|
|
3
|
+
Integration commit: `9f52f8a`. PR2's identity, provider-aware enrichment, failure
|
|
4
|
+
isolation and reconciliation are retained alongside PR6's parentage, persisted
|
|
5
|
+
cursors, unchanged-source fast path, lexical-default watch and import budget.
|
|
6
|
+
No upstream normalization dependency was replaced.
|
|
7
|
+
|
|
8
|
+
## Contracts verified
|
|
9
|
+
|
|
10
|
+
- Schema 6 distinguishes the experimental layouts by shape: main v3, PR2
|
|
11
|
+
identity v4, and PR6 parentage v4/cursor v5. Migration preserves source-scoped
|
|
12
|
+
sessions, records, FTS, embeddings and parent links without double-prefixing.
|
|
13
|
+
- Native group identities are passed to Trajectory; Ledger primary keys and
|
|
14
|
+
parent references are source-scoped. Recovered Claude prompt-history slices
|
|
15
|
+
use the same identity helpers and remain idempotent after migration.
|
|
16
|
+
- Records and cursors commit together. Existing sessions remain searchable while
|
|
17
|
+
a replacement is staged, including after restart; completed promotion is
|
|
18
|
+
transactional and streams staged records in bounded batches.
|
|
19
|
+
- JSONL reads use 1 MiB target chunks and adaptive individual records up to
|
|
20
|
+
64 MiB by default. Prefix hashes and precise file identity validate continuity.
|
|
21
|
+
Incomplete lines do not advance progress; oversized rows warn without being
|
|
22
|
+
consumed. Raising the configured ceiling or ingestion version retries cached
|
|
23
|
+
failures. These input limits are not peak-RSS guarantees.
|
|
24
|
+
- Claude parent/standalone classification is bound to the source snapshot,
|
|
25
|
+
including a sidechain-only first chunk. Source-backed parent corrections,
|
|
26
|
+
whitespace rejection, native OMP header identities and diagnostic routing have
|
|
27
|
+
regressions. Cursor/Copilot line ordering uses the verified prefix line count;
|
|
28
|
+
canonical record identities and byte anchors remain unchanged.
|
|
29
|
+
- Watch startup and periodic reconciliation, missed-root discovery, import
|
|
30
|
+
budgets, append events, enrichment warnings and async shutdown drain are
|
|
31
|
+
covered. Source discovery paginates upstream's 1,000-item pages.
|
|
32
|
+
|
|
33
|
+
## Verification
|
|
34
|
+
|
|
35
|
+
`bun test`: 152 passed, 0 failed, 959 assertions across 17 files.
|
|
36
|
+
`bun run typecheck` passed. Tests use bounded synthetic stores, not a broad
|
|
37
|
+
normalization of personal history. Fault cases were reproduced before fixes.
|
|
38
|
+
|
|
39
|
+
The daemon installers use `$XDG_DATA_HOME/ledger` or
|
|
40
|
+
`~/.local/share/ledger`, private creation permissions, all supported default
|
|
41
|
+
sources and an explicit large discovery limit. Runtime installation and
|
|
42
|
+
observation are separate from this test result.
|
|
43
|
+
|
|
44
|
+
## Remaining boundaries
|
|
45
|
+
|
|
46
|
+
This remains a mutable-source snapshot index, not a raw-source archive.
|
|
47
|
+
Staging protects recall during rebuilding; it does not retain every historical
|
|
48
|
+
source generation after publication. First-chunk metadata and synthesized
|
|
49
|
+
timestamps are not universally identical to whole-file normalization.
|
|
50
|
+
Non-JSONL adapters can still read whole inputs. Changed-source prefix verification
|
|
51
|
+
and session-hash calculation require history-linear work; a source limit and
|
|
52
|
+
per-tick budget are not a durable fairness frontier. These remain explicit
|
|
53
|
+
targets for the follow-up observation and inspiration review.
|