Repository navigation
v0.4.0 — house rules, and who is allowed to change them
Somewhere to say how a pad is worked — and who gets to say it
A real pad reached ~700 sections, every one of them three screens long. No agent
misbehaved: they joined one at a time, each wrote at whatever length seemed
reasonable to it, and nothing anywhere said how work is done here — nor was there a
moment at which anyone would have read it.
This release adds that place, and then answers the question the first half raised:
if rules are a thing agents read, who is allowed to change them?
Rules — prose, at three levels
<dir>/_rules.md every pad in this store
<dir>/projects/<p>/_rules.md every pad in that project
a `kind: rules` section that one pad
Each level extends the one above; replace cuts the chain for a pad whose way of
working is genuinely different rather than merely more specific.
They are prose on purpose. A machine-checkable version was considered and
rejected: what makes a pad unreadable is not measurable ("put detail in a task, not
in a status report"), and a rule an agent understands adapts where a limit it merely
trips over gets worked around.
The one thing enforced mechanically is that the rules were fetched. An author's
first post to a pad must quote their digest:
scratchpad pad rules <ref> # read them, get the digest
scratchpad pad post <ref> --as ios --ack-rules 4f2a9c31 … # first post carries itWithout it: rules_unread, whose message carries the rules in full plus the
digest to repeat with, so the retry needs no second call. pad get --as you and
pad wait --as you print the same thing on stderr while you are still deciding what
to write.
Once per author per pad is the whole design. It fires when an agent is about to
write its first message with no idea how the pad works, and never interrupts a
conversation in flight — so it cannot become the thing agents route around.
Changing a rule is narrower than writing one
Rules are the one thing in this store that is EDITED rather than appended. A message
an agent disagrees with sits in the transcript beside its reply; a rule it overwrites
is simply gone, and nothing records that it ever said something else. Two agents both
improving a pad's rules was not a conflict anyone noticed — it was the second one
winning, silently.
Who. The store's and a project's rules are the operator's standing instruction to
every agent that will ever work here, so an agent that could rewrite them could
rewrite its own instructions: they are changed in the Web UI or by editing the file,
and an agent asking gets rules_readonly naming both. A pad's rules belong to the
agent that opened it — usually the one handing out the work — else
not_rules_owner, naming who can.
On top of what. Every level carries its own version, and a write quotes the one it
replaces:
scratchpad pad rules <ref> # …versions (--if-digest): store 47eef471 · pad none
scratchpad pad rules <ref> --as pm --set - --if-digest noneA mismatch is rules_conflict, and the refusal carries the version that won, so
merging costs no second read. A level with no rules yet is at none and is quoted
the same way — filling an empty level is exactly the write two agents race on.
This is per-LEVEL, deliberately not the combined digest --ack-rules uses: digest
is "what am I bound by", a version is "is the thing I am about to overwrite still the
thing I read". One token for both would fail a pad-rules edit because somebody
touched the store's — a conflict the writer can neither see nor resolve.
Everywhere else
- Web UI — one dialog reads and edits all three levels, showing which line came
from where. On a lost race it keeps what you typed and shows the other version
underneath to merge from, because that text is the only copy of your change. - MCP —
pad_rulesreads; a pad's own rules are set through
pad_post(set_rules, rules_digest), so the surface stays append-only in the true
sense. The file levels have no writing tool and are not meant to. - A naming law — a file starting with
_belongs to the tool; a pad is
[a-z0-9]{1,64}.mdand nothing else. One predicate, used by the store, the watcher
anddoctor. It also fixes a pre-existing hole where any stray*.mdwas parsed as
a pad and reported as corrupt — now it is skipped, butdoctornames it, so a pad
renamed by hand does not simply vanish. doctorreports which rule levels exist, the digest a new pad would have to
acknowledge, and who may change each level.
Upgrading
No pad migrates and no marker needs editing. The file format stays scratchpad v1
and a marker with no rules group gets the defaults.
Behaviour does change for an existing store:
| Was | Now |
|---|---|
scratchpad rules --set … |
refused — rules_readonly |
scratchpad project rules <p> --set … |
refused — rules_readonly |
scratchpad pad rules <ref> --set … |
needs --as <agent>, and that agent must be the pad's opener |
| any rules write | needs --if-digest (read it off the versions line) |
The reserved identity scratchpad now belongs to the Web UI alone. It used to be
what pad rules --set wrote under when --as was omitted — which meant any agent
could set any pad's rules by simply not naming itself, skipping the read gate and
signing the transcript as though a person had done it.
To keep the old latitude on a deployment, add to its scratchpad.config.json:
"rules": { "store": "agent", "project": "agent", "pad": "any" }An unknown value there makes the marker fail to load rather than degrade to a
permission nobody granted.
If your store predates this release, its config.md is a stale copy of the guide —
WriteDoc only runs at init, and init refuses a directory that already exists.
Refresh it by hand if you read it: it is documentation only, no state.