sealkeep 0.11.2 → 0.11.4
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/ARCHITECTURE.md +20 -0
- package/CHANGELOG.md +146 -0
- package/README.md +117 -3
- package/dist/site/index.html +23 -1
- package/dist/site.zip +0 -0
- package/dist/src/adapters.js +12 -5
- package/dist/src/agent-context.js +169 -18
- package/dist/src/agent-memory.d.ts +52 -0
- package/dist/src/agent-memory.js +128 -0
- package/dist/src/cli.js +64 -4
- package/dist/src/daemon.d.ts +3 -0
- package/dist/src/daemon.js +52 -7
- package/dist/src/doctor.js +23 -0
- package/dist/src/fork.d.ts +78 -0
- package/dist/src/fork.js +197 -0
- package/dist/src/heartbeat.js +19 -1
- package/dist/src/local-api.js +10 -0
- package/dist/src/machine-settings.d.ts +30 -1
- package/dist/src/machine-settings.js +40 -0
- package/dist/src/mcp.js +9 -0
- package/dist/src/meter.d.ts +75 -0
- package/dist/src/meter.js +241 -0
- package/dist/src/search.d.ts +2 -1
- package/dist/src/search.js +60 -21
- package/dist/src/team-presence.js +15 -3
- package/dist/src/vault.d.ts +14 -0
- package/dist/src/vault.js +16 -0
- package/package.json +2 -2
- package/web/app.js +21 -0
- package/web/index.html +21 -0
package/ARCHITECTURE.md
CHANGED
|
@@ -88,6 +88,26 @@ Automatic context has a deliberately split latency contract:
|
|
|
88
88
|
later safe boundary. Provider latency therefore changes freshness, never the
|
|
89
89
|
latency of the current prompt or tool result.
|
|
90
90
|
|
|
91
|
+
What that prepared context is then *used* for changed deliberately. Anything a
|
|
92
|
+
hook adds to a conversation is re-read by the model on every later step of the
|
|
93
|
+
session, so an unrequested block is not paid for once — it is rent for the rest
|
|
94
|
+
of the session. Measured on one real session: 129 automatic injections, about
|
|
95
|
+
465 tokens each, roughly 60,000 tokens of permanent weight nobody asked for.
|
|
96
|
+
|
|
97
|
+
So recall is pull, not push. `formatNotice` emits one line at the start of a
|
|
98
|
+
session saying preserved history exists and how to search it, and nothing
|
|
99
|
+
afterwards; the agent reaches for the index over MCP when a question actually
|
|
100
|
+
needs it. Teammate events still pass through, because a teammate line is a
|
|
101
|
+
person addressing the session rather than recall addressing itself. The old
|
|
102
|
+
behaviour remains available behind `recallPushEnabled` — `SEALKEEP_RECALL_PUSH=1`
|
|
103
|
+
or a `runtime/recall-push` marker in the data directory — which is also what the
|
|
104
|
+
tests that assert recall *content* switch on.
|
|
105
|
+
|
|
106
|
+
`sealkeep meter` is the other half of the same idea. It reads local session
|
|
107
|
+
files only, with no key and no network, and reports what each live session costs
|
|
108
|
+
per step, what share of that is re-read history, and what the same work would
|
|
109
|
+
cost from a fresh session carrying a small context pack.
|
|
110
|
+
|
|
91
111
|
Autopilot has a similarly explicit deletion boundary. A fresh installation
|
|
92
112
|
preserves, indexes, and uploads, while `local-settings.json` records
|
|
93
113
|
`reclaimEnabled: false`; neither the generated service unit nor the running
|
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,152 @@
|
|
|
3
3
|
Notable changes, by published version. Sealkeep is pre-1.0: minor versions
|
|
4
4
|
may change behavior, and say so here when they do.
|
|
5
5
|
|
|
6
|
+
## 0.11.4 — 2026-09-23 — history stays findable
|
|
7
|
+
|
|
8
|
+
- **An archive can no longer be dropped from search because one sidecar could
|
|
9
|
+
not be read.** The build treats an id missing from the archive ledger as
|
|
10
|
+
deleted and retires it, which in segments mode is permanent: the id vanishes
|
|
11
|
+
from every later lookup and no build indexes it again. But the ledger scan
|
|
12
|
+
skips any sidecar it cannot parse — a partial write being replaced, one
|
|
13
|
+
transient read error — and that scan is cached per directory, so the damage
|
|
14
|
+
only surfaces when something else changes the directory: a seal arriving
|
|
15
|
+
while a build runs, which is what a busy machine does all day. On one real
|
|
16
|
+
vault ten archives had been retired with nothing superseding them, and two
|
|
17
|
+
sessions were genuinely unfindable — words in one returned no hits from it
|
|
18
|
+
while matching hundreds of other sessions. Absence now counts as deletion
|
|
19
|
+
only when the scan read every sidecar.
|
|
20
|
+
|
|
21
|
+
A vault that already lost archives this way recovers with `sealkeep index
|
|
22
|
+
drop` followed by `sealkeep index build`, which clears every retirement and
|
|
23
|
+
indexes the archives again. Repairing it automatically was tried and dropped:
|
|
24
|
+
a retirement also travels between your machines, so a build that lifted one
|
|
25
|
+
could undo a removal another machine meant, and the suite caught that.
|
|
26
|
+
|
|
27
|
+
- **The team check no longer runs on every seal.** 0.11.3 gave the lane its own
|
|
28
|
+
backing-off cadence, but a tick still asked it for a pass, and a tick is
|
|
29
|
+
scheduled whenever the queue has work — so cloud traffic still followed local
|
|
30
|
+
sealing. Measured on a busy machine: passes 4-6 seconds apart while a backlog
|
|
31
|
+
drained, against the 6-to-120-second schedule the lane had chosen. Nothing is
|
|
32
|
+
lost by waiting for that schedule; a pass this machine's own sealing triggers
|
|
33
|
+
cannot learn anything sooner than one the clock triggers.
|
|
34
|
+
|
|
35
|
+
## 0.11.3 — 2026-09-23 — the context tax, and a vault that catches up
|
|
36
|
+
|
|
37
|
+
- **The team check stops asking the cloud every three seconds.** The daemon
|
|
38
|
+
asked the same four questions twenty times a minute whether or not anything
|
|
39
|
+
had happened, and fetched the team space list three times per pass. Measured
|
|
40
|
+
against a stub plane, an idle daemon made 56 requests in 30 seconds, 55 of
|
|
41
|
+
them from this one loop: about 4.8 million a month per always-on machine,
|
|
42
|
+
with every machine drawing on one shared Cloud allowance. The list is now
|
|
43
|
+
fetched once, and a pass that finds nothing doubles the wait up to two
|
|
44
|
+
minutes; a pass that changes something brings the next one straight back.
|
|
45
|
+
Idle, that is 4 requests every 2 minutes, around 86,000 a month. Pushing
|
|
46
|
+
changes over realtime instead is the next step.
|
|
47
|
+
|
|
48
|
+
- **Automatic uploads finish on a large vault.** Choosing where an archive
|
|
49
|
+
belongs walks every link of its chain and may ask the account whether a copy
|
|
50
|
+
already matches. That is real work that moves no bytes, and the upload
|
|
51
|
+
pass's two-minute idle deadline only counted bytes, so on a vault of 5,062
|
|
52
|
+
archives the first byte came at 168 seconds and every pass was stopped
|
|
53
|
+
before it began: no automatic upload ran for days while every surface
|
|
54
|
+
reported the service healthy. Preparation now counts as progress; a stalled
|
|
55
|
+
transfer still trips the deadline, because it reports no bytes either.
|
|
56
|
+
|
|
57
|
+
- **The start of a long session becomes searchable.** The index build skipped
|
|
58
|
+
every earlier snapshot of a growing session, assuming the newest one would be
|
|
59
|
+
walked and cover them. A snapshot indexed as it was sealed is never walked,
|
|
60
|
+
and covers only the bytes it added, so everything sealed before it was never
|
|
61
|
+
indexed at all. On one real vault that was 400 snapshots across 76 sessions:
|
|
62
|
+
words found only in their early part came back in 0 of 20 searches, words
|
|
63
|
+
from the covered tail in 10. The build now schedules the newest snapshot that
|
|
64
|
+
still needs indexing, and walking its chain covers the rest.
|
|
65
|
+
|
|
66
|
+
- **`sealkeep index build` says what it did.** It printed the index's running
|
|
67
|
+
total as if it were the result — "Indexed 4509 archives" after a run that
|
|
68
|
+
indexed one, while the 410 that doctor had sent the user to fix stayed as
|
|
69
|
+
they were. It now reports what this run covered, says "Already up to date"
|
|
70
|
+
when there was nothing, and names what is still missing. It no longer claims
|
|
71
|
+
the index is never uploaded: it is synced to your account, as ciphertext.
|
|
72
|
+
|
|
73
|
+
- **The daemon's "is the index finished" check can pass.** It counted
|
|
74
|
+
superseded snapshots, which are never indexed on their own by design, so on
|
|
75
|
+
any vault that had ever superseded one it retried `index_incomplete` forever,
|
|
76
|
+
and disk reclaim waits for that check. It now uses the same definition as
|
|
77
|
+
`sealkeep index status` and doctor.
|
|
78
|
+
|
|
79
|
+
- **Settings for what reaches your agent, and what this machine will spend.**
|
|
80
|
+
The local Settings page gains four controls, all with the numbers behind
|
|
81
|
+
them stated plainly rather than hidden: hand preserved history to an agent
|
|
82
|
+
when a session starts (on, with what it costs spelled out), let agents search
|
|
83
|
+
this vault themselves (on, the local MCP server), a background CPU ceiling,
|
|
84
|
+
and a background memory ceiling. Both ceilings only ever make Sealkeep
|
|
85
|
+
gentler than the automatic value, never greedier, and each has a floor below
|
|
86
|
+
which work would stall rather than pace. Turning recall off still leaves
|
|
87
|
+
preserved history written as notes the agent reads for itself.
|
|
88
|
+
|
|
89
|
+
- **The agent-facing hook gets four seconds instead of two.** It unlocks the
|
|
90
|
+
keystore and decrypts a prepared file, measured at about 1.25 s on a modest
|
|
91
|
+
server; a live run went over two seconds and the agent discarded the output
|
|
92
|
+
with "hook timed out after 2s", so recall silently did nothing and nobody was
|
|
93
|
+
told. Four still fails open long before a person notices.
|
|
94
|
+
|
|
95
|
+
- **`sealkeep doctor` reports whether preserved history can reach the agent.**
|
|
96
|
+
A new `agent-memory-notes` check says whether Claude keeps a memory directory
|
|
97
|
+
for this project and how many preserved sessions have been written there.
|
|
98
|
+
|
|
99
|
+
- **Recall is written where the agent believes it.** Tested end to end on a
|
|
100
|
+
server, on two models: history pushed into the prompt by a hook was delivered
|
|
101
|
+
perfectly and then refused, in the agent's own words as "unverified/possibly
|
|
102
|
+
injected". Wording was not the cause — the same text pasted into a plain
|
|
103
|
+
session was believed. What an agent trusts is its own memory directory. So a
|
|
104
|
+
session start now writes preserved sessions there as ordinary notes, with
|
|
105
|
+
plain provenance (when the work happened, in this project) and no language
|
|
106
|
+
that reads as an injection; a note signed "recalled by Sealkeep" was read and
|
|
107
|
+
then discounted for exactly that reason. Notes are namespaced, additive, and
|
|
108
|
+
never touch a person's own notes or index lines. After the change the same
|
|
109
|
+
agent answered from memory, called Sealkeep itself for the detail, and got it
|
|
110
|
+
right.
|
|
111
|
+
|
|
112
|
+
- **Recall never quotes a conversation back to itself.** A long session is
|
|
113
|
+
sealed while it is still running, so the newest preserved session was the one
|
|
114
|
+
you were in: an agent was shown its own earlier "I don't know" above a genuine
|
|
115
|
+
finding, judged the evidence contradictory, and used neither. Automatic recall
|
|
116
|
+
now excludes the current transcript and anything sealed since this
|
|
117
|
+
conversation began. `SEALKEEP_RECALL_DAYS` bounds how far back it looks, off
|
|
118
|
+
by default because a decision from a month ago is worth being reminded of.
|
|
119
|
+
|
|
120
|
+
- **`sealkeep fork`** is the way out of an expensive session. Resuming a long
|
|
121
|
+
conversation sends its whole transcript with every request; one real evening,
|
|
122
|
+
two questions on a resumed session cost 41 million tokens, of which about
|
|
123
|
+
220,000 were the work. `fork` prices carrying on against starting fresh,
|
|
124
|
+
distils the session into a small pack — where the work got to, what was being
|
|
125
|
+
asked for, which files were open — and prints the command to start a new
|
|
126
|
+
session with it. Crucially it verifies first that the session is sealed and
|
|
127
|
+
indexed, and refuses to suggest walking away when it is not: the promise that
|
|
128
|
+
the history is one search away only holds if the history can actually be
|
|
129
|
+
searched.
|
|
130
|
+
|
|
131
|
+
- **Recall never tells a session the same thing twice.** Preserved context was
|
|
132
|
+
re-sent after every prompt and every Bash, Edit and Write, and 80% of it had
|
|
133
|
+
already been given to that same conversation: the identical preamble 140
|
|
134
|
+
times, the same list of preserved sessions over and over. Because everything
|
|
135
|
+
already in a conversation is re-read on every later request, that repetition
|
|
136
|
+
cost 81.6 million tokens on one measured session. Recall still runs at every
|
|
137
|
+
boundary and still searches against the current prompt; it now remembers what
|
|
138
|
+
this conversation has been told and sends only what is new, says the framing
|
|
139
|
+
once, and treats a passage as already-seen whichever section it arrives in.
|
|
140
|
+
The record is per conversation, so a new session is still told where the work
|
|
141
|
+
is up to. `SEALKEEP_RECALL_PUSH=0` restricts recall to session start only.
|
|
142
|
+
|
|
143
|
+
- **`sealkeep meter`** reports what your live agent sessions cost per step, how
|
|
144
|
+
much of that is re-read history, and what the same work would cost from a
|
|
145
|
+
fresh session carrying a small context pack. It reads local session files
|
|
146
|
+
only: no recovery phrase, no key, no network, nothing uploaded to produce a
|
|
147
|
+
number. Three signals, each of which was true of a session that ended a
|
|
148
|
+
weekly allowance: BLOATED when history is over 90% of input and over 50k a
|
|
149
|
+
step, STALE past seven days or 200 MB, and POLLING when an agent sleeps and
|
|
150
|
+
re-checks five or more times inside one turn.
|
|
151
|
+
|
|
6
152
|
## 0.11.2 — 2026-09-18 — a release tells you when a newer one exists
|
|
7
153
|
|
|
8
154
|
- Sealkeep says, once a day at most, when a newer release is on npm and what
|
package/README.md
CHANGED
|
@@ -50,6 +50,115 @@ source, your prompts, and whatever you pasted at 2am.
|
|
|
50
50
|
So the two obvious options are both bad: let them fill the disk, or `rm -rf` the reasoning
|
|
51
51
|
behind six months of work. Sealkeep is the third option.
|
|
52
52
|
|
|
53
|
+
## What it saves you
|
|
54
|
+
|
|
55
|
+
An AI coding session charges you for its own history on every single step, and nothing
|
|
56
|
+
tells you until the limit is gone. A session that has been alive for three months carries
|
|
57
|
+
roughly 185,000 tokens of accumulated conversation, and every request re-sends all of it.
|
|
58
|
+
Ask a one-line question and you pay 185,000 tokens to ask it. Let an agent run a loop of
|
|
59
|
+
shell commands and you pay it once per command, whatever the command does.
|
|
60
|
+
|
|
61
|
+
The worst version of this is resuming an old session. Pick up a months-old conversation to
|
|
62
|
+
ask two questions and the whole transcript goes with every request: one real evening, two
|
|
63
|
+
questions on a resumed session cost 41 million tokens, of which about 220,000 were the work.
|
|
64
|
+
The weekly allowance was gone by 2am, and nothing had warned anybody.
|
|
65
|
+
|
|
66
|
+
**Leave the session instead of resuming it.** `sealkeep fork` prices the choice, checks the
|
|
67
|
+
history really is recoverable, and writes a small pack — where the work got to, what was
|
|
68
|
+
being asked for, which files were open — to start fresh with. Everything else stays in the
|
|
69
|
+
vault, and the pack tells your agent how to ask for it.
|
|
70
|
+
|
|
71
|
+
```sh
|
|
72
|
+
sealkeep fork # the most expensive session you have open
|
|
73
|
+
sealkeep fork --write # write the pack and print the command to start fresh
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
```
|
|
77
|
+
The most expensive session you have open is the claude one in bot.
|
|
78
|
+
|
|
79
|
+
carrying on there 615k tokens per step, 97% of it re-read history
|
|
80
|
+
starting fresh 22k tokens per step, carrying a 392-token pack instead
|
|
81
|
+
you would save 593k tokens on every step from here on
|
|
82
|
+
|
|
83
|
+
The full session is sealed (afaa0cb4…) and searchable, so nothing is lost by leaving it.
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
That last line is the part that matters. If the session is not sealed and indexed yet,
|
|
87
|
+
Sealkeep says so and refuses to pretend walking away is safe, because the promise only
|
|
88
|
+
holds if your agent can genuinely get the detail back when it needs one.
|
|
89
|
+
|
|
90
|
+
**It can also just tell you the number.** `sealkeep meter` answers the question nothing else
|
|
91
|
+
can: what is each live session costing per step, how much of that is re-read history, and
|
|
92
|
+
what the same work would cost starting fresh.
|
|
93
|
+
|
|
94
|
+
```sh
|
|
95
|
+
sealkeep meter # the last 24 hours
|
|
96
|
+
sealkeep meter --hours 6 --json
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
It reads local session files only. No recovery phrase, no key, no network, nothing uploaded
|
|
100
|
+
to produce a number. One real morning on one machine:
|
|
101
|
+
|
|
102
|
+
```
|
|
103
|
+
tool where steps per step history total in signals
|
|
104
|
+
claude bot 457 597k 97% 272.8M BLOATED
|
|
105
|
+
claude sometest 368 474k 96% 174.3M BLOATED STALE
|
|
106
|
+
codex spala 581 162k 99% 94.2M BLOATED STALE POLLING
|
|
107
|
+
|
|
108
|
+
Total sent: 807.8M. The same work from fresh sessions carrying a 3k-token pack: about 36.5M.
|
|
109
|
+
That is roughly 771.4M spent re-reading, 95% of everything you sent.
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Three signals, each of which was true of a session that ended a weekly allowance:
|
|
113
|
+
**BLOATED** when history is over 90% of input and over 50k a step, **STALE** past seven days
|
|
114
|
+
or 200 MB, and **POLLING** when an agent sleeps and re-checks five or more times inside one
|
|
115
|
+
turn, paying the whole context on every tick.
|
|
116
|
+
|
|
117
|
+
**Recall never tells your session the same thing twice.** It used to re-send the same
|
|
118
|
+
preamble and the same list of preserved sessions after every prompt and every Bash, Edit
|
|
119
|
+
and Write. Measured on one real session:
|
|
120
|
+
|
|
121
|
+
| Injections over one session | 140 |
|
|
122
|
+
| :-- | --: |
|
|
123
|
+
| Payload they carried | ~65,000 tokens |
|
|
124
|
+
| Of that, lines the session had already been given | **80%** |
|
|
125
|
+
| What the repetition cost to re-send | **81.6 million tokens** |
|
|
126
|
+
|
|
127
|
+
A block added early is re-sent on every one of the thousands of requests after it, so
|
|
128
|
+
repeating yourself is the most expensive thing a memory tool can do.
|
|
129
|
+
|
|
130
|
+
So recall still runs at every boundary, exactly as before, and still searches against what
|
|
131
|
+
you just typed. It simply keeps track of what this conversation has already been told and
|
|
132
|
+
sends only the part that is new. The framing is said once. A passage that arrived as a
|
|
133
|
+
preserved session is not sent again as a search excerpt, because it is the same sentence
|
|
134
|
+
wearing a different prefix. Nothing is lost: a genuinely new excerpt, or a teammate's new
|
|
135
|
+
line, still arrives the moment it exists.
|
|
136
|
+
|
|
137
|
+
The book-keeping is per conversation, not permanent. A new session is a new reader and is
|
|
138
|
+
told where the work is up to, even though an earlier session on the same machine was told
|
|
139
|
+
the same thing.
|
|
140
|
+
|
|
141
|
+
Set `SEALKEEP_RECALL_PUSH=0` if you want memories only at session start and silence after.
|
|
142
|
+
|
|
143
|
+
**Your history stays searchable without living in the prompt.** The whole archive is one
|
|
144
|
+
`sealkeep search` or one MCP call away, so nothing has to be carried forward just in case.
|
|
145
|
+
|
|
146
|
+
**Your disk comes back.** Verified, searchable, idle sessions are reclaimed, and the
|
|
147
|
+
reasoning behind them survives in a form you can still read years later.
|
|
148
|
+
|
|
149
|
+
## What you can turn off
|
|
150
|
+
|
|
151
|
+
Everything automatic has a switch, on the local Settings page, with its cost stated rather
|
|
152
|
+
than hidden.
|
|
153
|
+
|
|
154
|
+
| Setting | Default | What it means |
|
|
155
|
+
| --- | --- | --- |
|
|
156
|
+
| Hand preserved history to an agent at session start | on | Your agent opens a project and knows where you left off. Each thing is sent once and never repeated; on a measured session that was under one percent of what the session sent. Off still writes the notes. |
|
|
157
|
+
| Let agents search this vault themselves | on | The local tool server, so an agent can look things up on demand. Nothing is exposed to the network. |
|
|
158
|
+
| Background CPU ceiling | automatic | Targets 30% of one core. A number here only ever makes Sealkeep gentler. |
|
|
159
|
+
| Background memory ceiling | automatic | The ceiling a worker may reach before it stops and retries smaller. |
|
|
160
|
+
| Background network limit | automatic | One 8 Mbps ceiling shared across Sealkeep's jobs. |
|
|
161
|
+
|
|
53
162
|
## How it works
|
|
54
163
|
|
|
55
164
|
The order is the safety property. Nothing is reclaimed before it is verified, and nothing is
|
|
@@ -160,6 +269,8 @@ it stores archives as single objects, and says so.
|
|
|
160
269
|
| `sealkeep autopilot status` · `off` | Check on it, or stop it |
|
|
161
270
|
| `sealkeep quickstart` | Same setup, no background service |
|
|
162
271
|
| `sealkeep status` · `doctor` | What is archived; whether this machine is healthy |
|
|
272
|
+
| `sealkeep meter` | What your live sessions cost per step, and how much of it is re-read history |
|
|
273
|
+
| `sealkeep fork` | Leave an expensive session without losing what it knows |
|
|
163
274
|
| `sealkeep queue run` | Encrypt everything waiting |
|
|
164
275
|
| `sealkeep daemon` | Watch, seal, index, and upload continuously; reclaim only when enabled |
|
|
165
276
|
| `sealkeep search <query>` | Metadata search; `--content` searches inside sessions |
|
|
@@ -181,9 +292,12 @@ Codex, so the agent itself can search your sealed history, check vault
|
|
|
181
292
|
status, and restore a session it needs — six tools, all local, nothing new
|
|
182
293
|
exposed to the network.
|
|
183
294
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
295
|
+
The installed lifecycle hooks identify the current Git project and prepare that
|
|
296
|
+
history locally, so the search is instant when the agent asks for it. What they
|
|
297
|
+
no longer do is push it into the conversation: at the start of a session you get
|
|
298
|
+
one line saying preserved history exists, and after that, silence until something
|
|
299
|
+
is actually requested. Two things still arrive on their own, because both are a
|
|
300
|
+
person talking rather than recall talking to itself:
|
|
187
301
|
|
|
188
302
|
- **One developer, several machines.** A finished Mac session is sealed and
|
|
189
303
|
its encrypted index syncs in the background. When the same developer opens
|