@ssheleg/agent-sync 1.2.2
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 +332 -0
- package/LICENSE +21 -0
- package/README.md +389 -0
- package/agent-sync.example.json +40 -0
- package/agent-sync.schema.json +144 -0
- package/bin/agent-sync.js +149 -0
- package/package.json +46 -0
- package/plugins/agent-sync/.claude-plugin/plugin.json +18 -0
- package/plugins/agent-sync/commands/agent-sync.md +16 -0
- package/plugins/agent-sync/hooks/_lib.sh +39 -0
- package/plugins/agent-sync/hooks/guard.sh +55 -0
- package/plugins/agent-sync/hooks/hooks.json +69 -0
- package/plugins/agent-sync/hooks/renew.sh +10 -0
- package/plugins/agent-sync/hooks/session-end.sh +14 -0
- package/plugins/agent-sync/hooks/session-start.sh +8 -0
- package/plugins/agent-sync/skills/agent-sync/SKILL.md +372 -0
- package/plugins/agent-sync/skills/agent-sync/references/adapter-contract.md +80 -0
- package/plugins/agent-sync/skills/agent-sync/references/backend-fs.md +57 -0
- package/plugins/agent-sync/skills/agent-sync/references/backend-outline.md +103 -0
- package/plugins/agent-sync/skills/agent-sync/references/hooks.md +99 -0
- package/plugins/agent-sync/skills/agent-sync/references/lease-protocol.md +145 -0
- package/plugins/agent-sync/skills/agent-sync/references/pipeline-binding.md +76 -0
- package/plugins/agent-sync/skills/agent-sync/references/roadmap.md +103 -0
- package/plugins/agent-sync/skills/agent-sync/references/two-sources.md +131 -0
- package/plugins/agent-sync/skills/agent-sync/scripts/agent_sync.py +2454 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,332 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project are documented here.
|
|
4
|
+
This project adheres to [Semantic Versioning](https://semver.org/).
|
|
5
|
+
|
|
6
|
+
## 1.2.2 — 2026-07-29
|
|
7
|
+
|
|
8
|
+
### Changed
|
|
9
|
+
- **The npm package is `@ssheleg/agent-sync`.** Unscoped `agent-sync` was rejected on publish
|
|
10
|
+
with a 403: npm's name-similarity policy fires only on `PUT`, so `npm view` reporting E404
|
|
11
|
+
("free") predicts nothing — the collision was with an existing `agentsync`. Scoped names are
|
|
12
|
+
exempt from that policy, which is the documented fix.
|
|
13
|
+
- **The command is still `agent-sync`.** A package's `bin` name is independent of its package
|
|
14
|
+
name, so nothing about daily use changes; only the install line grows a scope.
|
|
15
|
+
- GitHub install (`npx github:appvillis-com/agent-sync`) and the Claude Code plugin are
|
|
16
|
+
unaffected — the registry only ever bought the short name.
|
|
17
|
+
|
|
18
|
+
## 1.2.1 — 2026-07-29
|
|
19
|
+
|
|
20
|
+
### Fixed — documentation that contradicted the code
|
|
21
|
+
Compressing the skill surfaced three statements that measurement had already disproved and
|
|
22
|
+
that nobody had gone back to correct. This is the drift the tool exists to catch, in the
|
|
23
|
+
tool's own documentation.
|
|
24
|
+
|
|
25
|
+
- `lease-protocol.md` opened by declaring that *no backend offers compare-and-swap, so both
|
|
26
|
+
leases and id reservations are decided by replaying one append-only log*. Half of that is
|
|
27
|
+
still true — id allocation is positional over the log — and half has been false since
|
|
28
|
+
1.0.0. It now separates the two mechanisms, because confusing them is how this went wrong
|
|
29
|
+
twice.
|
|
30
|
+
- The same file still said the **run** writes the claim tag and the tool only verifies. As
|
|
31
|
+
of 1.2.0 the tool writes it through.
|
|
32
|
+
- `backend-fs.md` described a "git-file lease" — commit the lock, push it, read the
|
|
33
|
+
rejection — a design that was never built. Leases have never depended on which knowledge
|
|
34
|
+
backend is configured, and the file now says so.
|
|
35
|
+
|
|
36
|
+
### Changed
|
|
37
|
+
- `SKILL.md` trimmed from 4779 to 4325 tokens (13% headroom under the 5000 cap), with the
|
|
38
|
+
full measurement history left in `CHANGELOG.md` and `lease-protocol.md` where it belongs.
|
|
39
|
+
- `lease-protocol.md` gains the cross-machine section it was missing.
|
|
40
|
+
|
|
41
|
+
## 1.2.0 — 2026-07-29
|
|
42
|
+
|
|
43
|
+
### Added — the claim is written through to the roadmap again
|
|
44
|
+
Demoted to a check in 1.0.0 because an unattended process rewriting a shared registry is
|
|
45
|
+
the collision a lease exists to prevent. It is back, with that objection engineered out:
|
|
46
|
+
|
|
47
|
+
- **One row.** The single table row containing the task id as a whole word. Zero rows →
|
|
48
|
+
nothing happens. Two or more → **refused**, with the reason. It never guesses.
|
|
49
|
+
- **One cell.** Only the configured cell changes; links, notes and every other column are
|
|
50
|
+
untouched byte for byte. `cell` is 0-based, negative counts from the end.
|
|
51
|
+
- **Reversible.** The previous text is stored in `.agent-sync/claims.json` and restored
|
|
52
|
+
verbatim on release — not a default, what was actually there. After acquire→release,
|
|
53
|
+
`git diff` on the roadmap is **empty**.
|
|
54
|
+
- **Atomic.** Written to a temp file and moved into place, so a crash cannot leave the
|
|
55
|
+
register half-edited.
|
|
56
|
+
|
|
57
|
+
Closing a task is still yours: the tool refuses to write `done` on your behalf, because a
|
|
58
|
+
status a machine sets is a status nobody checked. `references/roadmap.md` documents the
|
|
59
|
+
whole cycle — claiming, closing, re-planning, and what to do when the claim cannot be
|
|
60
|
+
written.
|
|
61
|
+
|
|
62
|
+
### Added — cross-machine leases
|
|
63
|
+
`leaseBackend: "git"` pushes a commit to `refs/agent-sync/leases/<key>`, and the remote's
|
|
64
|
+
non-fast-forward rejection **is** a compare-and-swap. Verified against a hosted remote
|
|
65
|
+
before being written: A created the ref, B pushed a different commit without force and was
|
|
66
|
+
rejected, the ref still held A. Then eight parallel processes against the real remote —
|
|
67
|
+
**one winner, seven losers all naming it**.
|
|
68
|
+
|
|
69
|
+
Expired leases are stolen with `--force-with-lease` against the exact object seen, so a
|
|
70
|
+
steal cannot clobber a holder who renewed in between. `local` remains the default and is
|
|
71
|
+
still exclusive between processes on one filesystem; `acquire` and `check` now say which
|
|
72
|
+
guarantee you actually have instead of implying the stronger one.
|
|
73
|
+
|
|
74
|
+
## 1.1.0 — 2026-07-29
|
|
75
|
+
|
|
76
|
+
The skill can now take **any** project from nothing to a validated setup on its own.
|
|
77
|
+
|
|
78
|
+
### Added
|
|
79
|
+
- **`check`** — validates the whole setup and refuses to call a broken one healthy. It fails
|
|
80
|
+
on a register whose allocation pattern matches nothing, a guard glob that matches no file
|
|
81
|
+
(a rule protecting nothing), a gate whose script is missing, a mirror source that is not
|
|
82
|
+
there, empty credentials, a `.gitignore` that misses the env file — or that file being
|
|
83
|
+
**tracked by git**, the one unrecoverable mistake here — a hand-edited or stale snapshot,
|
|
84
|
+
**a snapshot no agent instruction file links**, and a register with no baseline. Every one
|
|
85
|
+
of those failed for real during this tool's own adoption.
|
|
86
|
+
- **`scaffold`** — creates the documentation architecture where it is absent: a decision
|
|
87
|
+
register with an allocation line and an `AGENTS.md` pointing at the generated snapshot. It
|
|
88
|
+
never touches an existing file. A tool that rewrites a project's conventions on adoption is
|
|
89
|
+
worse than one that does nothing.
|
|
90
|
+
- The snapshot is stamped with a **hash of the configuration** it describes, so staleness
|
|
91
|
+
means the configuration moved on — not that a commit happened. Comparing commits was wrong
|
|
92
|
+
at both boundaries: a snapshot is generated before the commit that carries it, and the
|
|
93
|
+
config is usually added in that same commit, so the very first adoption always looked stale.
|
|
94
|
+
|
|
95
|
+
## 1.0.1 — 2026-07-29
|
|
96
|
+
|
|
97
|
+
### Fixed
|
|
98
|
+
- **A rate-limited knowledge base stopped the work, not just the record.** `journal`, `record`
|
|
99
|
+
and `signal` raised when the store was unreachable or throttling, so a burst of shard creation
|
|
100
|
+
could fail a run outright. The plane carries visibility, not correctness: publishing now
|
|
101
|
+
reports the gap loudly and lets the caller continue. Swallowing it would hide a hole in the
|
|
102
|
+
record; raising made an availability dependency out of a notebook.
|
|
103
|
+
- Retries widened to seven attempts for `429` and transient `5xx`, which is what a burst of
|
|
104
|
+
document creation actually needs.
|
|
105
|
+
- Run journals moved to the shard naming scheme (`20 Runs — <run>`) so they are enumerated like
|
|
106
|
+
every other log.
|
|
107
|
+
|
|
108
|
+
## 1.0.0 — 2026-07-29
|
|
109
|
+
|
|
110
|
+
A full audit of the running system against its own promises. Three surfaces were
|
|
111
|
+
configured and unimplemented, and the central safety claim was false. All measured, none
|
|
112
|
+
inferred.
|
|
113
|
+
|
|
114
|
+
### Fixed — the lease was not exclusive
|
|
115
|
+
- **A shared append-only document loses writes.** Twelve concurrent appends to one Outline
|
|
116
|
+
document returned twelve successes and left **three** lines: `editMode: append` reads,
|
|
117
|
+
appends and writes back, so simultaneous writers clobber each other and each is told it
|
|
118
|
+
succeeded. A lease decided on that can be held by two runs, each with proof.
|
|
119
|
+
- **Sharding per writer fixes the loss and breaks the decision.** 12/12 land, but without
|
|
120
|
+
compare-and-swap nothing can answer "is a contender still writing?", so eight parallel
|
|
121
|
+
processes each read only their own shard and **eight won one key**. A three-second settle
|
|
122
|
+
window took it to five. It cannot reach one.
|
|
123
|
+
- **Exclusion now comes from `os.open(O_EXCL)`** — an atomic create is the decision, and the
|
|
124
|
+
plane carries the record. Twelve parallel processes, **one winner, eleven losers all naming
|
|
125
|
+
the same holder**. Publishing to the plane can fail without affecting correctness, so it is
|
|
126
|
+
reported rather than raised.
|
|
127
|
+
- The limit is stated instead of implied: a lock file is exclusive between processes on one
|
|
128
|
+
filesystem, advisory across machines. `exclusiveLease` joins the capability set and defaults
|
|
129
|
+
to false, because declaring it without compare-and-swap is the most damaging lie an adapter
|
|
130
|
+
can tell.
|
|
131
|
+
|
|
132
|
+
### Fixed — configured but not implemented
|
|
133
|
+
- **`claimTags`** appeared in the schema, in every config and in DEC-0216, and was read
|
|
134
|
+
nowhere. `status` now reports where a held lease and the git claim tag disagree — and says
|
|
135
|
+
plainly when the configured mapping *cannot be verified at all*, which is the case in the
|
|
136
|
+
project that shipped it. The tool verifies; the run writes. A process that rewrites a shared
|
|
137
|
+
registry unattended from a hook is the mechanism that clobbers other agents' work.
|
|
138
|
+
- **Mirror drift detection** was asserted in a docstring beside code that never checked it.
|
|
139
|
+
`status` now reports pages whose stamped commit is not HEAD.
|
|
140
|
+
- Transient `5xx` from the knowledge base are retried like `429`; twelve concurrent document
|
|
141
|
+
creations had been failing outright.
|
|
142
|
+
|
|
143
|
+
## 0.6.0 — 2026-07-29
|
|
144
|
+
|
|
145
|
+
### Fixed
|
|
146
|
+
- **The mirror was configured, documented and not implemented.** `mirror.enabled` and
|
|
147
|
+
`mirror.sources` existed in the schema, the config and the generated setup snapshot, and
|
|
148
|
+
nothing read them — a surface with nothing behind it, which is the failure mode that reads as
|
|
149
|
+
finished. `board --mirror` now renders each configured document into the plane, stamped with
|
|
150
|
+
the commit it was made from, refusing any page whose generated marker a human removed. A cap
|
|
151
|
+
on the number of files is reported rather than applied silently: a quiet truncation reads as
|
|
152
|
+
"everything is mirrored" when it is not.
|
|
153
|
+
|
|
154
|
+
## 0.5.0 — 2026-07-29
|
|
155
|
+
|
|
156
|
+
### Added
|
|
157
|
+
- **`adopt`** — inspect an existing project and *propose* a configuration. Adoption is where a
|
|
158
|
+
coordination tool most easily starts lying: guess a register wrong and every later check is
|
|
159
|
+
confidently about the wrong file. So it reads the repository, prints what it found, prints the
|
|
160
|
+
decisions it **refuses to make for you** (a registry file carrying ids with no "next free id"
|
|
161
|
+
line cannot have allocation reserved safely), and writes nothing. In a submodule it proposes no
|
|
162
|
+
registers at all, because decisions belong to the parent repository.
|
|
163
|
+
|
|
164
|
+
## 0.4.0 — 2026-07-29
|
|
165
|
+
|
|
166
|
+
Found by simulating three agents working three repositories at once, entered from one
|
|
167
|
+
umbrella — the arrangement this tool is for. Every defect below was invisible from inside
|
|
168
|
+
a single checkout.
|
|
169
|
+
|
|
170
|
+
### Fixed
|
|
171
|
+
- **Every submodule agent ran isolated, in degraded mode, seeing nobody.** A submodule is
|
|
172
|
+
its own git repository, so the project root is the submodule and `.env.agent-sync` — which
|
|
173
|
+
lives in the superproject — was never found. Three agents entered from one umbrella and
|
|
174
|
+
coordinated with nothing, each reporting `ungated` while believing it was configured. The
|
|
175
|
+
env file is now located from the superproject and parent directories, so one credential
|
|
176
|
+
file serves the whole tree.
|
|
177
|
+
- **A submodule's `reconcile` reported every umbrella decision as an orphan.** The as-built
|
|
178
|
+
log is shared by all repositories; id registers are per-repository, and a service repo
|
|
179
|
+
declares none because decisions live in the parent. Comparing the shared log against a
|
|
180
|
+
local register produced a wall of false findings — the loudest possible way to teach
|
|
181
|
+
people to ignore a check. Register checks are now scoped to what the checkout can judge,
|
|
182
|
+
and say plainly when they are not evaluated here.
|
|
183
|
+
- **Regenerating the board from a submodule replaced the shared view with a narrower one.**
|
|
184
|
+
Four repositories wrote one page; last writer won. The board now carries only facts true
|
|
185
|
+
from every checkout, and repo-local findings moved to their own generated page.
|
|
186
|
+
|
|
187
|
+
### Added
|
|
188
|
+
- **`setup`** writes a generated snapshot of how *this* project is wired — registers,
|
|
189
|
+
guarded files, gates, the two documentation sources, what is written where, and what is
|
|
190
|
+
never deleted. Commit it and link it from the project's agent instructions so every agent
|
|
191
|
+
reads the same description of the pipeline instead of inferring it from behaviour. It is
|
|
192
|
+
generated rather than hand-written, because a hand-written description of a configuration
|
|
193
|
+
drifts from it, which is the exact failure this tool exists to surface.
|
|
194
|
+
- **The lifetime and deletion protocol is now stated.** Nothing in a log is edited or
|
|
195
|
+
deleted: the logs are replayed in order, so removing a line silently rewrites a
|
|
196
|
+
conclusion other agents already acted on. Correct by appending. Generated pages are the
|
|
197
|
+
narrow exception, and one that has lost its marker is refused, not overwritten.
|
|
198
|
+
|
|
199
|
+
## 0.3.3 — 2026-07-29
|
|
200
|
+
|
|
201
|
+
### Fixed
|
|
202
|
+
- **The enforcement hook ran in a different mode from the agent it was guarding.** A hook is
|
|
203
|
+
spawned with a bare environment and never inherits the operator's
|
|
204
|
+
`set -a && . ./.env.agent-sync`, so every hook silently fell back to the `fs` backend while
|
|
205
|
+
the agent's own commands used the cloud. Consequences, both invisible: the guard **denied
|
|
206
|
+
edits whose lease was properly held**, and it recorded runs as `ungated` while the agent had
|
|
207
|
+
been told `gated`. The gate was structurally broken in exactly the scenario it exists for.
|
|
208
|
+
The tool now loads `.env.agent-sync` itself — the path is deterministic, so correctness must
|
|
209
|
+
not depend on how the process was invoked. An already-set variable still wins.
|
|
210
|
+
|
|
211
|
+
## 0.3.2 — 2026-07-29
|
|
212
|
+
|
|
213
|
+
### Fixed
|
|
214
|
+
- **`reconcile` demanded an as-built record for an id nobody had taken.** The id scraper
|
|
215
|
+
matched every `DEC-\d+` token in a register, including the "Next free ID" pointer — the one
|
|
216
|
+
number that by definition is *not* allocated. Two symptoms, one cause: a permanent false
|
|
217
|
+
finding on the unallocated id, and a baseline stamped one higher than reality, which quietly
|
|
218
|
+
excused the newest real decision from ever being checked. The register's own
|
|
219
|
+
`nextFreeIdPattern` now identifies that pointer and subtracts it.
|
|
220
|
+
Found by running the new duty against this project rather than by reading the code.
|
|
221
|
+
|
|
222
|
+
## 0.3.1 — 2026-07-29
|
|
223
|
+
|
|
224
|
+
### Fixed
|
|
225
|
+
- **The guard blocked the lease holder.** A hook runs with `CLAUDE_SESSION_ID` in its
|
|
226
|
+
environment and a plain shell command usually does not, so the run id was derived two
|
|
227
|
+
different ways for one session: the agent acquired a lease as `r-f49d900b9` and was then
|
|
228
|
+
denied by its own `PreToolUse` guard as `r-5ef2554fe611`. The primary flow — acquire,
|
|
229
|
+
then edit a guarded register — could not complete. Found when the gate refused the very
|
|
230
|
+
commit that was writing its decision record.
|
|
231
|
+
The marker file is now authoritative for the checkout, with the session name recorded
|
|
232
|
+
beside it: a different session rotates the id, while a run that merely *learns* its
|
|
233
|
+
session name adopts it instead of rotating.
|
|
234
|
+
|
|
235
|
+
## 0.3.0 — 2026-07-29
|
|
236
|
+
|
|
237
|
+
### Fixed
|
|
238
|
+
- **Three of the four hooks were dead on macOS.** They called `timeout`, which is GNU
|
|
239
|
+
coreutils and absent from a stock macOS, so `session-start`, `renew` and `session-end`
|
|
240
|
+
all died with "command not found" — leases were never renewed and never released
|
|
241
|
+
there, the exact abandoned-lease failure this tool exists to prevent. A portable
|
|
242
|
+
`run_limited` helper now uses `timeout`, then `gtimeout`, then a plain-bash watchdog.
|
|
243
|
+
`guard` was unaffected, so enforcement itself never lapsed.
|
|
244
|
+
|
|
245
|
+
### Added
|
|
246
|
+
- **The as-built record, and the duty to reconcile it against git.** Git documents say
|
|
247
|
+
how it *should* be — written before the code, often without it. `70 As-built` says how
|
|
248
|
+
it *actually is*, derived from what agents really wrote. Two source-of-truths answering
|
|
249
|
+
two different questions; the gap between them is the finding, not a defect. New
|
|
250
|
+
`record` and `reconcile` commands, wired into the pipeline's docs-study stage (resolve
|
|
251
|
+
divergence before writing code) and docs stage (update both sides, then re-check).
|
|
252
|
+
- **`reconcile` is a ratchet, not a flood.** `--set-baseline` stamps today's ids as a
|
|
253
|
+
counted backlog that may only shrink; ids written after it must carry an as-built
|
|
254
|
+
record. A check that fails on all of history is a check that gets switched off.
|
|
255
|
+
- **Awareness names the repository.** Work spans several repos entered from one umbrella,
|
|
256
|
+
and "r-alpha holds ASC-072" is only actionable once you know which checkout it is in.
|
|
257
|
+
- **`npx agent-sync update`** — updates every channel and prunes the shadow copy in the
|
|
258
|
+
same step, because `npx skills update --global` recreates it on its own even when
|
|
259
|
+
claude-code was never targeted.
|
|
260
|
+
- **`install.sh`** POSIX fallback and a **Cursor rule** (`cursor/rules/agent-sync.mdc`,
|
|
261
|
+
no relative links, since the file gets copied into foreign projects).
|
|
262
|
+
|
|
263
|
+
## 0.2.0 — 2026-07-29
|
|
264
|
+
|
|
265
|
+
Coordination is not only mutual exclusion. An audit against the stated purpose — *agents
|
|
266
|
+
see what each other are doing and pick up important changes in time* — found the tool
|
|
267
|
+
enforced exclusion and delivered neither half of the awareness.
|
|
268
|
+
|
|
269
|
+
### Fixed
|
|
270
|
+
- **`status` shows what other runs are doing.** It reported only the caller's own leases,
|
|
271
|
+
so an agent learned a task was taken and nothing about who held it or what they were
|
|
272
|
+
touching. A lease you cannot see makes you blocked; a lease you can see makes you
|
|
273
|
+
coordinated.
|
|
274
|
+
- **Cross-repo signals were write-only.** `signal` appended and nothing ever read the log,
|
|
275
|
+
so a producer was still never told a dependency had been filed against them — the exact
|
|
276
|
+
failure the feature exists to prevent. `status` now surfaces what landed since this run
|
|
277
|
+
last looked, watermarked per run so it stays quiet until something actually changes.
|
|
278
|
+
- **The board renders recent signals** alongside live leases.
|
|
279
|
+
|
|
280
|
+
### Notes
|
|
281
|
+
- Verified with three concurrent runs across two repositories: an agent working inside a
|
|
282
|
+
submodule alone sees the leases and signals of agents in the parent repository, because
|
|
283
|
+
both read one coordination plane.
|
|
284
|
+
|
|
285
|
+
## 0.1.0 — 2026-07-29
|
|
286
|
+
|
|
287
|
+
First release.
|
|
288
|
+
|
|
289
|
+
### Added
|
|
290
|
+
- **Lease authority with TTL** — `acquire` / `renew` / `release`, decided by replaying
|
|
291
|
+
one append-only log. Document order is authoritative; timestamps only expire a lease,
|
|
292
|
+
because agents' clocks differ and the protocol must not depend on them.
|
|
293
|
+
- **Race-free id reservation** — positional allocation over the same log, so two agents
|
|
294
|
+
cannot be handed one number. An id reserved and never written to git is reported as a
|
|
295
|
+
leak rather than silently reclaimed.
|
|
296
|
+
- **Pluggable adapter contract** — six primitives, three declared capabilities
|
|
297
|
+
(`atomicAppend`, `totalOrderRead`, `search`), and a mandatory honest-degradation path:
|
|
298
|
+
a backend that cannot arbitrate exclusively must refuse lease authority and say so.
|
|
299
|
+
- **Backends** — `outline` (hosted or self-hosted; server-side append gives a total order
|
|
300
|
+
without compare-and-swap) and `fs` (local, degraded, `ungated`).
|
|
301
|
+
- **Run journal and cross-repo signal feed** — `filed → accepted → delivered → closed`,
|
|
302
|
+
so a producer learns a dependency was filed against them.
|
|
303
|
+
- **Generated board** — commit-stamped, and it refuses to overwrite a page that lacks the
|
|
304
|
+
generated marker, so a page a human took over is reported instead of clobbered.
|
|
305
|
+
- **Claude Code hooks** — `SessionStart`, `PreToolUse` (deny a guarded edit or a commit
|
|
306
|
+
staging one without a live lease), throttled `PostToolUse` renew, `SessionEnd` release.
|
|
307
|
+
The guard exits 2 on its own internal failures, because any other code fails open.
|
|
308
|
+
- **`init` as the first command** — it asks where coordination state lives instead of
|
|
309
|
+
guessing, writes committed shape and a gitignored mode-600 env file, and leaves the
|
|
310
|
+
token line empty for the operator to fill.
|
|
311
|
+
- **Validator with a negative self-test**, plus CI.
|
|
312
|
+
|
|
313
|
+
### Verified against a live instance
|
|
314
|
+
Built and then exercised end to end against a real Outline deployment, which surfaced three
|
|
315
|
+
defects the unit-level work had not:
|
|
316
|
+
- **Markdown normalisation.** The store rewrites a `- ` bullet to `* `, so the log parser now
|
|
317
|
+
emits `- ` and accepts `-`/`*`/`+`. Anchoring to the character written rejected every line
|
|
318
|
+
the server returned.
|
|
319
|
+
- **A silent pre-filter hid malformed lines from the counter meant to expose them**, so the
|
|
320
|
+
unparseable ratio read 0% while nothing parsed. Anything entry-shaped now reaches the pattern
|
|
321
|
+
and is counted.
|
|
322
|
+
- **An unreadable log reported as a lost race.** `acquire` now raises above a 2% unparseable
|
|
323
|
+
ratio rather than naming a holder who does not exist.
|
|
324
|
+
- HTTP error bodies are surfaced instead of dropped — a bare `400` cost a debugging round when
|
|
325
|
+
the response said `collectionId: Invalid UUID`.
|
|
326
|
+
- The collection may be given as a UUID, a `urlId`, or the whole `name-urlId` slug from the
|
|
327
|
+
address bar, because that is what a person actually copies.
|
|
328
|
+
|
|
329
|
+
### Notes
|
|
330
|
+
- Hooks exist only in Claude Code. Elsewhere the same checks run as a self-check and the
|
|
331
|
+
run is recorded `ungated` — a documented limit, surfaced rather than hidden.
|
|
332
|
+
- Requires [task-pipeline](https://github.com/ssheleg/task-pipeline) for its stages.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Appvillis
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|