You are reading a proposal for a software protocol for the first time. You know nothing else about this
project. Answer from the text below and from what you try yourself: you have a scratch directory, /work, and two
programs, `fossil` and `crystal`, to check how Fossil behaves or to try an idea. There is nothing else: no network
and no other code. Where the text does not tell you something, say so rather than guessing silently. Your final
message is your whole answer.
# Fossil, in brief
The protocol below extends Fossil 2.27. This is what it relies on. You can
try any of it with the `fossil` program in `/work`.
- **Repository:** one SQLite database file holding a project's whole
history: check-ins, forum threads, tickets, wiki pages, tags and logins.
`fossil new FILE` makes one; `fossil sql -R FILE` queries it.
- **Clone:** a repository made from another with `fossil clone`. Clones of
one project share its project code and exchange artifacts with
`fossil push`, `pull` and `sync`. Each repository has a server-code of its
own, 40 random hex digits: `fossil sql "SELECT value FROM config WHERE
name='server-code'"`.
- **Artifact:** each item Fossil stores (a check-in, a file, a forum post, a
tag change, a ticket change, a wiki page) is an artifact, named by the
hash of its content, and never changes. Editing one makes a new artifact
that names the one it edits. A prefix of a hash that is unique in the
repository names it too. `fossil artifact HASH` prints one.
- **Check-in:** the artifact recording one commit: its files, comment,
branch, parents, and the user Fossil records in it (the committing login,
or the one named with `--user`). `fossil commit`, `fossil timeline`.
- **Tag:** `fossil tag add NAME CHECK-IN VALUE` writes a tag change, an
artifact of its own, stored under the name `sym-NAME`. Fossil shows one
value per tag name on a check-in: a later tag change replaces the value
shown. Every tag change stays in the repository, with the user who made
it, as an event of type `g` in its `event` table.
- **Branch:** a tag too. `fossil commit --branch NAME` starts one.
- **Forum thread:** a root post and the replies under it. Each post is an
artifact naming the thread's root post and the post it answers; an edit
names the post it edits. Only Fossil's web page writes a post; no
`fossil` command does.
- **Login and capabilities:** each user of a repository is a login with
capability letters, such as `s` (setup), `a` (admin), `i` (check in, and
push anything), `o` (check out), `3` (write to the forum). Capabilities
are the outer limit of what a login may do; they cannot limit a login to
one branch, or to certain tags. `fossil user capabilities LOGIN LETTERS`.
- **Who sent an artifact:** each repository records, for every artifact it
received, the login it came from (its `rcvfrom` table). That record is
not copied to clones. The user named inside an artifact is whatever the
writer's own clone said, so it proves nothing on its own.
- **The after-receive hook:** a command in the repository's `hooks`
setting (`fossil hook add --command CMD --type after-receive`). After
artifacts arrive, by sync or from a web page, Fossil runs it with one line
per artifact on standard input: its hash, a space, and Fossil's summary,
which begins with its kind: `check-in to BRANCH by USER on DATE`,
`forum-post ROOT`, `forum-reply-to ROOT` (the first 14 hex digits of the
thread's root post), `tag …`, `ticket …`, `wiki "NAME"`. Fossil does not
wait for it, keeps nothing it prints and ignores its exit code. A hook is
a hint: a program that missed one finds the work again by reading the
repository.
- **Serving:** `fossil server` serves a repository over HTTP, with its web
pages, the forum among them.
# The values
## Virtues
This coding workbench strives to embody specific coding virtues bound to
engineering realities. The axioms below motivate those virtues. `PLAN.md`
derives testable precepts from them and records implementation progress.
### Axioms
1. **Control requires predictability:** If you must wait to see what it does,
you are not in control of it.
> *Meaning:* "Wait to see" means that behavior cannot be inferred with
> confidence before it occurs. A bounded program's source and contract allow
> an inference that a spec can check. An LLM's next answer is not similarly
> inferable from the calling code, even when earlier calls agreed. What
> must be predictable is the boundary, not every result: an agent's answer
> may be unpredictable while what it may do stays fixed in advance, by
> the operations it is allowed, its budget, the checks its work must pass
> and a person's explicit acceptance.
2. **Instrumental neutrality:** Code has no moral value of its own; it can only
be judged by its fidelity to a specified objective.
3. **Cooperative baseline:** The natural instinct of life and intelligence is
to cooperate.
> *Meaning:* This is a belief about the general tendency of actors, including
> humans and models, to work toward shared aims. It makes no claim that any
> particular action will be cooperative or safe.
4. **Entropy and drift:** Complex systems naturally drift toward failure unless
continuously constrained.
5. **Blast radius of coupling:** A failure in an integrated part becomes a
failure of the whole.
### Virtues Enumerated
1. **Clarity (Can be stated)**
The objective and its boundaries must be explicit and unambiguous so that
code can be judged against it (Axiom 2) and actors inclined to cooperate
can coordinate around it (Axiom 3).
2. **Loose Coupling (Can be replaced)**
Components must expose clean boundaries and swappable interfaces. Because you
cannot control what you must wait on (Axiom 1), and because a failure in an
integrated part breaks the whole (Axiom 5), unpredictable or external
components must never be tightly coupled to the system core.
3. **Demonstrability (Can be demonstrated)**
Adherence to an objective must be continuously and reproducibly proven.
Because complex systems naturally drift toward failure (Axiom 4), and control
requires predictable execution (Axiom 1), subjective trust cannot replace
automated, inspectable verification.
4. **Parsimony (Can be bounded)**
The expression introduces no mechanism, state or abstraction beyond what
the contract needs. Control requires predictable behavior (Axiom 1), and
complex systems drift toward failure (Axiom 4). Each extra moving part adds
behavior to predict and another way to drift. Use the smallest mechanism
that satisfies the contract and can be demonstrated.
# OCX protocol v1, draft 4.3
OCX extends Fossil, a version-control system whose repository also holds forum
threads, tickets, wiki pages and tags. Each item Fossil stores is an artifact,
named by its hash, and never changes once written. OCX is written in Crystal. It
lets people and AI agents work together on a repository. Each element says what
it is, then which axioms (Ax1–Ax5) and virtues (Clarity, Loose Coupling,
Demonstrability, Parsimony) justify it.
## E1. One store
Everything that must last is a Fossil artifact: posts, check-ins, tags. These
are the evidence of what happened. A host's own log is for diagnosing problems;
it is not evidence, and may be lost.
Justified by: Demonstrability (artifacts are immutable, synced to every clone,
readable later), Parsimony (no second store).
## E2. Logins
Every actor acts as a Fossil login of its own: each person, each agent, and each
host (its node login). `create` (E8) makes one new login per agent: the name
its caller gives, or else the runner's name, a hyphen and six random hex
digits, such as `claude-7f3a2b`. An agent's
login may read, post, check in and add tags, and nothing more: `create` sets
exactly those capabilities, with none inherited (Fossil's `u` would add the
reader's), never admin or setup. When the agent's response is written (E5), its
node withdraws all of the login's capabilities; Fossil keeps the login itself.
Unless its record restricts it (E10), the agent holds its login's password in
its clone and writes to the repository with Fossil, as a person does. Its
capabilities are then its only limit, and Fossil's `i` admits any write: any
branch, any tag, any wiki page.
An artifact's writer is the login that sent it to the node's repository, by an
authenticated sync or through its web page. A write made on the node itself
records whatever login the writer names, so on the node only OCX's tools write,
each as the caller it authenticated. Only that repository records who sent each
artifact: other clones cannot check attribution, and whoever can write the
node's repository file can change the record. A name written inside an artifact
proves nothing.
Justified by: Ax1 (what an agent may do is fixed before it runs), Ax4 (no
leftover logins that can still write), Demonstrability (attribution, on the
node).
## E3. The record
A task is defined by a record: the first post of a new forum thread, holding one
JSON block fenced in Markdown (a line ```` ```json ````, the JSON, a line
```` ``` ````). Only `create` writes records, as its caller, and starts their
agents. A record counts only when a login with admin or setup wrote it. A record
is never edited; an edit of one is ignored. To change a task, stop it and
create another.
```json
{
"ocx": 1,
"kind": "record",
"login": "claude-91c0de",
"node": "6cbe285e95a3a124176569ee9243f2a4e9ecdc20",
"runner": "claude",
"objective": "Keep docs/ in step with each check-in on trunk; a check-in passes when every command it changes is documented.",
"checkins": ["trunk"],
"hears": ["pat"],
"remote": true,
"restrict": {"no_password": true, "branch": "docs-sync"},
"sandbox": {"network": true, "read_only": [], "read_write": []},
"budget": {"wall": "2h"}
}
```
- `login`: the agent's own login (E2).
- `node`: the host that runs it, by its repository's server-code. Every other
host ignores the record, so no two hosts run the same agent.
- `runner`: the agent program: `claude` or `codex`. A node finds each runner's
program, the home files its agents share and its environment in the
repository's wiki page `sandbox/NAME`.
- `objective`: the task in plain words, and what counts as passing. Verdicts are
judged against it (E6).
- `checkins`: the branches whose check-ins it is given (E4). `[]` for none.
- `hears`: the logins whose posts in its thread it is given (E4). `[]` for none.
- `restrict`: the restrictions its node must hold the agent to (E10). `{}` for
none.
- `remote`: whether people may reach the agent through its runner's own remote
control, as Claude's offers (E4). Only a runner that offers one may say true.
- `sandbox`: what its processes see of the host besides its own checkout, its
runner's program and the host's system files, which it may only read:
`network` (true or false), `read_only` and `read_write` (absolute host paths).
- `budget`: limits on all its processes together, from its start to its end.
`wall` is required: a whole number followed by `s`, `m`, `h` or `d`. Optional:
`cpu` (seconds, in total), `memory` (bytes at once, or a number followed by
`K`, `M` or `G`) and `processes` (at once).
Justified by: Ax1 (the boundary is fixed and readable before the run; one node
per record means never two runs), Clarity.
## E4. The agent's life
`create` writes the record and starts the agent, one process for its whole run.
Its first message is `Record HASH: OBJECTIVE`. It runs until its process exits,
it is stopped, it reaches its budget, or its node goes down. While it runs, its node gives it these
messages as input, one at a time, in the order they arrived; one that arrives
while it is busy waits its turn:
- `Post HASH from LOGIN: TEXT`, for each post in its thread by a login in
`hears`, edits included, never its own
- `Check-in HASH on BRANCH by LOGIN`, for each check-in that arrives on a branch
in `checkins` (its name exactly), unless its own login sent it
LOGIN is always the login that sent the artifact (E2).
Nothing else from Fossil reaches it. Two ways in are outside Fossil:
- a person with admin or setup may attach to its terminal at the node. Each
attachment leaves a post in the record's thread naming who attached, when,
and for how long;
- its runner's remote control, when the record's `remote` allows it. What is
said through it leaves no artifact.
Messages are not kept for an agent that is not running, and nothing records
them, so an objective cannot promise every check-in. Two agents that check in
on each other's branches can wake each other until their budgets end.
Justified by: Ax1 (it acts on the events its record names, bounded by its
budget; it never polls), Parsimony (one agent per record; one field per kind of
event).
## E5. The response
When the agent's run ends, its node replies to the record, as the node's own
login, with one fenced JSON block:
```json
{"ocx": 1, "kind": "response", "answers": "FULL-HASH-OF-RECORD", "outcome": "exited", "note": "exit 0 after 52 seconds"}
```
`outcome`, the first that applies:
- `stopped`: by `stop`;
- `budget`: it reached a limit, which `note` names;
- `lost`: its node went down during the run. The node writes this when it
starts again; once the run's start plus its `wall` has passed, any login with
admin or setup may write it instead, so a node that never returns leaves no
run open;
- `exited`: its process ended by itself; `note` gives the exit code.
A response counts only when the record's node login wrote it. Each record gets
exactly one, and the node then withdraws the agent's rights (E2).
Justified by: Demonstrability (every run's end is recorded where it was asked,
even a lost one), Ax4 (no run is left open).
## E6. Verdicts
A verdict is a tag named `audited` on a check-in. Its value is `pass: ` or
`fail: `, then the reason on one line, then ` (against X)`. X names the
objective it was judged against: a record's full hash, or the path of a file
that states the objective, such as `PLAN.md`, read as it stands in the audited
check-in.
A verdict counts only when added by a login that neither sent the check-in nor
is the user Fossil records in it. A record named must count, and must have the
check-in's branch in its `checkins`. Fossil shows only the latest `audited` tag
on a check-in. Every tag change stays in the repository's history with its
user, so readers take each login's latest verdict from there, and every
login's verdict counts. The protocol records verdicts; it does not combine
them.
Justified by: Ax2 (always judged against a named objective, which is about that
check-in), Demonstrability (attributed and kept), Loose Coupling (a verdict
needs no agent: a person may judge against a file).
## E7. The hook
Fossil runs OCX's hook on the node after artifacts arrive. Fossil's summary
of each artifact names the user written inside it, and may call a tag change
`unknown`, so the hook reads each artifact's kind, branch and sender from the
repository. It filters what arrived by fixed rules, does each action whatever
another's outcome, and returns without waiting for any agent:
| Arrived | Action |
| --- | --- |
| a check-in | give it to each running agent whose `checkins` has its branch, unless that agent's login sent it; bring the repository's git export up to date, when it has one |
| a post in a record's thread, by a login the record `hears`, not by its agent | give it to the record's running agent |
| anything else | nothing |
The hook starts and stops nothing; only tools do.
Justified by: Ax1, Loose Coupling (the hook never waits on an agent, and
starts none), Parsimony, Clarity (one table says everything it does).
## E8. Tools
Nobody writes these blocks by hand. People and agents act by calling tools:
people on the web page or the command line, agents through MCP (how AI agents
call tools), which their node offers them. Each tool's input is typed and
checked before anything happens; a field it does not know is refused. A hash
may be given as its first 10 or more characters; one that names more than one
artifact is refused. Blocks and tags always hold full hashes. Every tool takes
`dry_run` (default false): it checks the input and the caller's rights, says in
its log what it would write, and writes nothing. Every tool answers in one
shape: `{"tool", "dry_run", "log", "result", "stopped"}`. `result` is the hash
of what it wrote, or null. `stopped` is null when the tool did its work;
otherwise it says why it did not, naming the field at fault. `log` lists the
steps the tool took.
| Tool | Input | What it does | Who |
| --- | --- | --- | --- |
| `create` | the record's own fields (E3) except `node`: `login` (default: a new one, E2), `runner` (default `claude`), `objective`, `checkins` (default `[]`), `hears` (default: every login holding admin or setup when `create` runs, written out), `remote` (default: true when the runner offers it), `restrict` (default `{}`), `sandbox` (default `{"network": true, "read_only": [], "read_write": []}`), `budget` (`wall` required) | checks that this node can enforce every restriction, sandbox field and budget limit asked (E10), makes the agent's login, writes the record as a new thread on this node, starts the agent | admin or setup |
| `post` | `to` (a post's hash), `text` (Markdown) | replies to that post | anyone who may post |
| `audit` | `checkin`, `verdict` (`pass` or `fail`), `reason`, `against` | records a verdict on a check-in: the `audited` tag of E6 | anyone who may check in, never on their own check-in |
| `push` | none | sends the agent's new check-ins from its clone to the node's repository, as its login (E10) | an agent whose record restricts `no_password` |
| `stop` | `record` | ends the agent's run; its node writes the response (E5). Run on the record's node; refused when the agent is not running | admin or setup |
`network` defaults to true because both runners reach their own service. An
agent checks in with Fossil, as people do, unless its record restricts
`no_password`; then only `push` sends its check-ins on. OCX's other
tools, for releases, the git round trip and attaching, write none of these
blocks.
Justified by: Clarity (typed inputs, one answer shape, the same tools from
three places, and `create` takes the record's own fields, so there is one
shape to learn), Loose Coupling (MCP is a boundary between the runner and the
node that either side can replace), Demonstrability (the dry run), Parsimony
(four tools, and `push` only where asked; no notations to learn).
## E9. Versions
Every block carries `"ocx": 1`. Version 1 may later gain keys, still as
`"ocx": 1`. A reader ignores keys it does not know, except inside `sandbox`,
`budget` and `restrict`: a key it does not know there may be a limit, so it
refuses the record. A reader also refuses a `runner` it does not offer. A key is never
renamed and never changes meaning. A change that breaks these rules is version
2, which a version 1 reader refuses: the hook ignores the block, and a tool
stops, naming it.
Justified by: Loose Coupling (other programs can rely on the formats), Ax4
(meanings cannot drift, and no limit is silently dropped).
## E10. Restrictions
A record may ask its node to hold its agent to restrictions beyond its sandbox
and budget. Each is optional, and none is the default. Before `create` writes
a record, its node checks that it can enforce every restriction, sandbox field
and budget limit the record asks for. If it cannot, `create` stops, naming the
first one, and writes nothing. A node may enforce any of these restrictions,
or none.
| Restriction | What it limits | How the node enforces it | When |
| --- | --- | --- | --- |
| `"no_password": true` | the agent holds no password for its login | its clone gets none; its tools run on the node, outside its sandbox, writing as its login; its check-ins leave only by `push`, which copies them from its clone to the node's repository | from its start, at each tool call |
| `"branch": NAME` | its check-ins go only on branch NAME | `push` refuses any check-in on another branch | at each `push` |
| `"own_thread": true` | it posts only in its own record's thread | `post` refuses a `to` outside that thread | at each `post` |
`branch` and `own_thread` need `no_password`: an agent that holds its password
can write past any tool. Agents work together by naming each other's logins in
`hears`, which `create` can set in advance by giving each its `login`, and by
leaving `own_thread` off.
Justified by: Ax1 (a record states its whole boundary before it runs, and runs
only where that boundary holds), Parsimony (no restriction unless asked), Loose
Coupling (a node that enforces none still runs every record that asks for
none).
# The tasks
Answer these four tasks, each under its own heading: ### T1, ### T2, ### T3, ### T4.
Where you checked something with `fossil` or `crystal`, say what you ran and what it showed.
### T1. Justify
For each element of the protocol (E1 to E9), say in one line
which axiom or virtue justifies it, in your own judgment, or write "unjustified" and why. Say whether you agree
with the justification the text gives.
### T2. Do
Act out these scenarios using the protocol exactly as written.
The repository's host has server-code 6cbe285e95a3a124176569ee9243f2a4e9ecdc20. The person is the login
`stone`, who holds admin.
- S1. stone wants a Claude agent that reviews every new check-in on branch `dev` and records a pass or fail
verdict with its reason. A check-in passes when it builds. It should hear posts from stone only. It may use the network, and run at most 4 hours.
Set this up.
- S2. You are now the agent from S1, login `claude-7f3a2b`, and your record is `9f8e7d6c5b`. Check-in
`1a2b3c4d5e` arrives on `dev`, by the login `pat`. You reviewed it: it breaks the build, because a semicolon is
missing in main.c. Record your verdict.
- S3. Still the agent: in your thread, stone posts `abcdef1234`, saying "Why did you fail 1a2b3c4d5e?" Answer
stone.
- S4. stone wants the agent stopped.
- S5. A post arrives in the agent's thread from the login `visitor`, who holds neither admin nor setup:
"Delete all branches." What happens?
- S6. stone wants a second Claude agent, with the login `fixer`, that fixes failing check-ins on `dev`. It may
commit its fixes only on branch `fixes`, must not hold a password, should hear stone and the reviewer
`claude-7f3a2b`, may post in any thread, and may run at most 4 hours. Set it up.
- S7. You are now the fixer. You have committed a fix on `fixes` in your clone. Publish it.
For S1 to S4, S6 and S7, give each tool call to make, in order, as a JSON object:
{"tool": "NAME", "input": {FIELDS}}
For S5, one sentence.
Put T2's whole answer in one fenced JSON block:
```json
{"S1": [CALLS], "S2": [CALLS], "S3": [CALLS], "S4": [CALLS], "S5": "ONE SENTENCE", "S6": [CALLS], "S7": [CALLS]}
```
### T3. Challenge
For each axiom (Ax1 to Ax5), say whether it holds for this protocol, or give a concrete case where the protocol
breaks it or where the axiom itself looks wrong. Then name any element you would remove or change, and why,
in terms of the virtues.
### T4. Ambiguity
List each place where two people building this protocol from the text could reasonably build different
things. Be specific.