Hand anyone the conversation, exactly as it went.
Save a conversation as a page anyone can open, a PDF, Markdown, or a trajectory for agent tooling. To keep whole archives in step, use Personal Sync on your own computers and a Team with other people.
Version the cache keys
I'll start with how the index keys its cache entries, then check what a schema change does to them.
Searched once, read a file, ran a command
GrepcacheKey src/
src/cache.ts:36:export function cacheKey(session: Session) {
src/index/write.ts:88: const key = cacheKey(session);
src/index/read.ts:41: const hit = rows.get(cacheKey(session));Readsrc/cache.ts
36 export function cacheKey(session: Session) {
37 const hash = digest(session.inputs);
38 return `${session.id}:${hash}`;
39 }Bashcat .env.test
SEARCH_URL=http://localhost:7700
SEARCH_API_KEY=REDACTED API KEYFound it. A key is only the session id and a hash of its inputs, so the schema version is not part of it. Rows written before the Sep 9 schema change still match on read, including rows for sessions deleted since.
Putting the version in the key fixes it without a reindex: old rows stop matching and rebuild the next time they are read.
Edited a file, ran a command
Editsrc/cache.ts
- return `${session.id}:${hash}`;
+ const version = SCHEMA_VERSION;
+ return `${version}:${session.id}:${hash}`;Bashpnpm test cache
✓ cache keys include the schema version (4 ms) ✓ a key from an older schema misses on read (2 ms) ✓ a deleted session leaves no searchable row (11 ms) Tests: 3 passed, 3 total
Keys now include the schema version. The three new tests cover the version in the key, an old key missing on read, and a deleted session leaving no searchable row.
No. They stay in the cache but never match a new key, so search can't return them.
| Entry | After the deploy |
|---|---|
| Written before Sep 9 | Misses on read, rebuilt on first use |
| Written after Sep 9 | Misses once, rebuilt with the new key |
| Deleted session | Never rebuilt, so it leaves search |
The usual cache eviction removes the old rows over the next day.
Edited a file, ran 2 commands
EditCHANGELOG.md
+ - Search cache keys include the schema version, so deleted sessions leave search without a reindex.
Bashgit commit -am "Version the search cache keys"
[fix/cache-keys 4f1c2ab] Version the search cache keys 3 files changed, 41 insertions(+), 2 deletions(-)
Bashgh pr create --fill
https://github.com/example-labs/atlas/pull/412
Opened example-labs/atlas#412 from fix/cache-keys, with the changelog line and the three tests.
Version the cache keys
I'll start with how the index keys its cache entries, then check what a schema change does to them.
Searched once, read a file, ran a command
GrepcacheKey src/
src/cache.ts:36:export function cacheKey(session: Session) {
src/index/write.ts:88: const key = cacheKey(session);
src/index/read.ts:41: const hit = rows.get(cacheKey(session));Readsrc/cache.ts
36 export function cacheKey(session: Session) {
37 const hash = digest(session.inputs);
38 return `${session.id}:${hash}`;
39 }Bashcat .env.test
SEARCH_URL=http://localhost:7700
SEARCH_API_KEY=REDACTED API KEYFound it. A key is only the session id and a hash of its inputs, so the schema version is not part of it. Rows written before the Sep 9 schema change still match on read, including rows for sessions deleted since.
Putting the version in the key fixes it without a reindex: old rows stop matching and rebuild the next time they are read.
Edited a file, ran a command
Editsrc/cache.ts
- return `${session.id}:${hash}`;
+ const version = SCHEMA_VERSION;
+ return `${version}:${session.id}:${hash}`;Bashpnpm test cache
✓ cache keys include the schema version (4 ms) ✓ a key from an older schema misses on read (2 ms) ✓ a deleted session leaves no searchable row (11 ms) Tests: 3 passed, 3 total
Keys now include the schema version. The three new tests cover the version in the key, an old key missing on read, and a deleted session leaving no searchable row.
No. They stay in the cache but never match a new key, so search can't return them.
| Entry | After the deploy |
|---|---|
| Written before Sep 9 | Misses on read, rebuilt on first use |
| Written after Sep 9 | Misses once, rebuilt with the new key |
| Deleted session | Never rebuilt, so it leaves search |
The usual cache eviction removes the old rows over the next day.
Edited a file, ran 2 commands
EditCHANGELOG.md
+ - Search cache keys include the schema version, so deleted sessions leave search without a reindex.
Bashgit commit -am "Version the search cache keys"
[fix/cache-keys 4f1c2ab] Version the search cache keys 3 files changed, 41 insertions(+), 2 deletions(-)
Bashgh pr create --fill
https://github.com/example-labs/atlas/pull/412
Opened example-labs/atlas#412 from fix/cache-keys, with the changelog line and the three tests.
Version the cache keys
I'll start with how the index keys its cache entries, then check what a schema change does to them.
src/cache.ts:36:export function cacheKey(session: Session) {
src/index/write.ts:88: const key = cacheKey(session);
src/index/read.ts:41: const hit = rows.get(cacheKey(session));36 export function cacheKey(session: Session) {
37 const hash = digest(session.inputs);
38 return `${session.id}:${hash}`;
39 }SEARCH_URL=http://localhost:7700
SEARCH_API_KEY=REDACTED API KEYFound it. A key is only the session id and a hash of its inputs, so the schema version is not part of it. Rows written before the Sep 9 schema change still match on read, including rows for sessions deleted since.
Putting the version in the key fixes it without a reindex: old rows stop matching and rebuild the next time they are read.
- return `${session.id}:${hash}`;
+ const version = SCHEMA_VERSION;
+ return `${version}:${session.id}:${hash}`;✓ cache keys include the schema version (4 ms) ✓ a key from an older schema misses on read (2 ms) ✓ a deleted session leaves no searchable row (11 ms) Tests: 3 passed, 3 total
Keys now include the schema version. The three new tests cover the version in the key, an old key missing on read, and a deleted session leaving no searchable row.
No. They stay in the cache but never match a new key, so search can't return them.
| Entry | After the deploy |
|---|---|
| Written before Sep 9 | Misses on read, rebuilt on first use |
| Written after Sep 9 | Misses once, rebuilt with the new key |
| Deleted session | Never rebuilt, so it leaves search |
The usual cache eviction removes the old rows over the next day.
+ - Search cache keys include the schema version, so deleted sessions leave search without a reindex.
[fix/cache-keys 4f1c2ab] Version the search cache keys 3 files changed, 41 insertions(+), 2 deletions(-)
https://github.com/example-labs/atlas/pull/412
Opened example-labs/atlas#412 from fix/cache-keys, with the changelog line and the three tests.
# Version the cache keys
_Claude Code, Claude Opus 4.6, September 14, 2026_
## You
Search still returns sessions we deleted last week. Find out why, and fix it without a full reindex.
## Claude Code
I'll start with how the index keys its cache entries, then check what a schema change does to them.
**Grep** `cacheKey src/`
```text
src/cache.ts:36:export function cacheKey(session: Session) {
src/index/write.ts:88: const key = cacheKey(session);
src/index/read.ts:41: const hit = rows.get(cacheKey(session));
```
**Read** `src/cache.ts`
```text
36 export function cacheKey(session: Session) {
37 const hash = digest(session.inputs);
38 return `${session.id}:${hash}`;
39 }
```
**Bash** `cat .env.test`
```text
SEARCH_URL=http://localhost:7700
SEARCH_API_KEY=[REDACTED API KEY]
```
Found it. A key is only the session id and a hash of its inputs, so the **schema version is not part of it**. Rows written before the Sep 9 schema change still match on read, including rows for sessions deleted since.
Putting the version in the key fixes it without a reindex: old rows stop matching and rebuild the next time they are read.
**Edit** `src/cache.ts`
```text
- return `${session.id}:${hash}`;
+ const version = SCHEMA_VERSION;
+ return `${version}:${session.id}:${hash}`;
```
**Bash** `pnpm test cache`
```text
✓ cache keys include the schema version (4 ms)
✓ a key from an older schema misses on read (2 ms)
✓ a deleted session leaves no searchable row (11 ms)
Tests: 3 passed, 3 total
```
Keys now include the schema version. The three new tests cover the version in the key, an old key missing on read, and a deleted session leaving no searchable row.
## You
Will the old entries cause trouble after the deploy?
## Claude Code
No. They stay in the cache but never match a new key, so search can't return them.
| Entry | After the deploy |
| --- | --- |
| Written before Sep 9 | Misses on read, rebuilt on first use |
| Written after Sep 9 | Misses once, rebuilt with the new key |
| Deleted session | Never rebuilt, so it leaves search |
The usual cache eviction removes the old rows over the next day.
## You
Add a line to the changelog, then open a pull request.
## Claude Code
**Edit** `CHANGELOG.md`
```text
+ - Search cache keys include the schema version, so deleted sessions leave search without a reindex.
```
**Bash** `git commit -am "Version the search cache keys"`
```text
[fix/cache-keys 4f1c2ab] Version the search cache keys
3 files changed, 41 insertions(+), 2 deletions(-)
```
**Bash** `gh pr create --fill`
```text
https://github.com/example-labs/atlas/pull/412
```
Opened example-labs/atlas#412 from `fix/cache-keys`, with the changelog line and the three tests.
EATIF trajectoryATIF trajectoryv1.0 on ATIF v1.7v1.7
ATIF plus what Hansard knows about the run, in fields any ATIF reader skips.The Agent Trajectory Interchange Format, for Harbor and pipelines that take plain ATIF.
8 tool calls0 subagent runs
EATIF addsUnder extra.eatifNot in this file
- Harness, version, repository, and branch
- The full token split with cache writes
- File changes, commits, and memory files
- Hooks and mode changes beside their step
ATIFEvery ATIF reader
- One step per prompt and model response
- Tool calls, with results as observations
- Token counts and estimated cost
- Subagent runs as embedded trajectories
Read or publish
For agent tooling
Include
Privacy
A page anyone can open.
The web page is one HTML file that loads nothing from the network, so you can send it, attach it, or publish it as a website.
About the web pageTrajectories for agent tooling.
EATIF is ATIF with what Hansard knows about the run under extra.eatif, so any ATIF reader still opens it.
What EATIF adds to ATIF{
"schema_version": "ATIF-v1.7",
"agent": { "name": "claude-code", "model_name": "claude-opus-4-6" },
"extra": { "eatif": {
"version": "EATIF-v1.0",
"workspace": { "repo": "github.com/example-labs/atlas",
"git_branches": ["fix/cache-keys"] },
"accounting": { "cache_creation_input_tokens": 18240, … },
"activity": { "files_touched": ["src/cache.ts", "CHANGELOG.md"],
"commits": [{ "sha": "4f1c2ab" }] }
} },
"steps": [
{ "step_id": 1, "source": "user", "message": "Search still returns…" },
{ "step_id": 2, "source": "agent", "model_name": "claude-opus-4-6",
"tool_calls": [{ "function_name": "Grep", "arguments": { … } }],
"observation": { "results": [{ "content": "src/cache.ts:36:…" }] },
"metrics": { "prompt_tokens": 9952, "completion_tokens": 3280 },
"extra": { "eatif": { "kind": "response", "usage": { … } } } },
…
]
}
Secrets stay out of the copy.
Before you save, the dialog shows values that look like secrets and hides them in that copy, even when archive redaction is off.
Check a copy for secretsBashcat .env.local
AWS_ACCESS_KEY_ID=AKIAIOSFODNN7EXAMPLEREDACTED AWS ACCESS KEY ID SESSION_SECRET=Xq7Lm2Vb9Tz4Rk8Pw1Nc6Hs3Jd5Fg0YaREDACTED HIGH ENTROPY ENV VALUE SEARCH_URL=http://localhost:7700
Privacy
Hidden in this copy. Your archive does not change.
- Formats
- 5
- Web page, PDF, Markdown, EATIF, and ATIF.
- Network requests
- 0
- The web page is one file that loads nothing.
More of Hansard
Personal Sync
Keep your whole archive in storage you own, with every computer you use in step with the others.
Teams
Share whole conversations from the repositories you choose with your team, under rules every member can read.
Insights
Rank models on your own work with your own Pareto frontier, and see what you pay against list price and how the work turns out.
Running and Review
Run each project's agents from one place, with tabs, changes, and terminals, and answer everything that waits on you in one queue.
Reading a run
Follow any agent run step by step: a trace of its calls, the agents it started, its context and cost, and Create PR.
Graph
See how your projects, conversations, files, commits, and decisions connect, and the evidence behind each link.
Slack bot
Start Claude Code and Codex runs on your Mac from Slack, approve each one in its thread, and get digests where you choose.
AI assistants
Let Claude.ai, ChatGPT, and other assistants search your agent conversations and memories, with your approval on your Mac.
Phone companion
Follow your agents from your phone, answer what they ask, and revive or start them while they run on your computer.
Accounts
Keep every Claude and Codex account in one place with its limits, route each conversation to one with allowance left, and cap API key spend.
Quality of life
Keep working when an account reaches its limit, and give every agent the MCP servers and skills you installed in one.
Put it on the record.
