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.6
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.
It has four parts, each resting on Fossil directly:
1. **Fossil, the medium:** what OCX relies on.
2. **OCX, the control plane:** messages that ask a node to run work, and the
node's answers.
3. **Verdicts, a data-plane standard:** how anyone records a judgement of a
check-in, and how anyone reads one.
4. **Tools:** how people and programs write all of this.
What the work itself writes (check-ins, posts, tags) goes straight to Fossil,
never through the control plane. The control plane never depends on a verdict,
and a verdict needs no record. Each element says which axioms (Ax1–Ax5) and
virtues (Clarity, Loose Coupling, Demonstrability, Parsimony) justify it.
# Part 1. Fossil, the medium
## F1. One store
Everything that must last is a Fossil artifact: posts, check-ins, tags, ticket
changes. 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).
## F2. Users, and who sent what
Every actor acts as a Fossil user of its own: each person, each running
program, and each node (its node user). A user's capabilities are the outer
limit of what it may do, and Fossil's `i` admits any write: any branch, any tag,
any wiki page.
An artifact's sender is the user it reached a repository from, by an
authenticated sync or through the web page; each repository records this for
itself, and does not copy it to clones. A write made on a node itself records
whatever user the writer names, so on a node only OCX's tools write, each as
the caller it authenticated. The user named inside an artifact proves nothing.
Justified by: Demonstrability (attribution, on the repository that received
it), Ax1 (what a user may do is fixed in Fossil before it acts).
## F3. A network on a persistent store
OCX treats Fossil as a network whose every message lasts:
- **Sending is writing an artifact.** Sync carries it to every clone; nothing is
lost on the way.
- **The hook is an interrupt; the repository is the truth.** Fossil runs the
after-receive hook from its backoffice after artifacts arrive. A write made
on the node itself starts no backoffice, so whatever writes there runs it
afterwards. A node that missed a hook reads the repository again.
- **The answer is the acknowledgement, and it lasts.** A request that has its
answer is never acted on again, and what is still open is read from the
repository, never kept anywhere else.
- **Nothing is retracted.** Stopping, correcting and replacing are new
artifacts that point at old ones.
- **Order comes from references** (a reply names the post it answers, a check-in
its parents), not from clocks.
Justified by: Parsimony (no queue, no state store, no retries), Ax4 (every
open request is found again after any failure), Demonstrability (every request
and answer is kept).
# Part 2. OCX, the control plane
## C1. Messages
An OCX message is one JSON block fenced in Markdown (a line ```` ```json ````,
the JSON, a line ```` ``` ````) inside a forum post, either a new thread's first
post or a reply in any thread, or inside a ticket change. Its thread, or its
ticket, is its place. Every message carries `"ocx": 1`, its `kind` (`record`,
`stop` or `response`) and the `node` it is for: a node, by its repository's
server-code. A `stop` names the record it stops in `stops`, and a `response`
the record it answers in `answers`, each by its full hash. Two repositories
that share a server-code (a copy, or a clone made from a file) would both act,
so a node's repository is made new or cloned over HTTP.
A node acts on a message only when it names this node, its version is known,
and its sender (F2) may send that kind: a user holding admin or setup for a
`record` or a `stop`, the node's own user for a `response`. Every other message
it ignores, writing nothing. An edit of a message is ignored; to change a
request, stop it and send another. Nobody writes messages by hand: tools do
(Part 4).
Justified by: Clarity (one envelope, three kinds), Loose Coupling (anything that
can write a post or a ticket change can send one), Ax1 (only the senders it
names can ask a node for anything).
## C2. The record
A record asks a node to run a program as one user, on the artifacts it names,
within limits:
```json
{
"ocx": 1,
"kind": "record",
"node": "6cbe285e95a3a124176569ee9243f2a4e9ecdc20",
"user": "claude-91c0de",
"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"}
}
```
- `user`: the Fossil user the run acts as (C5).
- `runner`: how it runs:
- `claude` or `codex`: a session, one process for the whole run, given each
artifact as a delivery. A node finds each runner's program, the home files
its runs share and its environment in the wiki page `sandbox/NAME`, counted
only when a user with admin or setup wrote it.
- `command`: the program `command` names (a list: the program, then its
arguments), run to completion once for each check-in it is given, in a
fresh checkout of that check-in. For CI.
- `objective`: the task in plain words, and what counts as passing.
- `checkins`: the branches whose check-ins it is given. `[]` for none.
- `hears`: the users whose posts in its place, or changes to its ticket, it is
given. `[]` for none, and always `[]` for a `command`.
- `remote`: whether people may reach a session through its runner's own remote
control, as Claude's offers. Only a runner that offers one may say true.
- `restrict`: the restrictions its node must hold it to (C6), written out in
full: `{}` for none.
- `sandbox`: what its processes see of the host besides its checkout, its
program and the host's system files, which they may only read: `network`
(true or false), `read_only` and `read_write` (absolute host paths).
- `budget`: limits on all its processes together: for a session, its whole run;
for a `command`, each run. `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).
A CI record differs only in its runner:
`{"runner": "command", "command": ["crystal", "run", "ci.cr"], "user": "ci-dev", "checkins": ["dev"], "hears": [], …}`.
Justified by: Ax1 (the whole boundary is fixed and readable before anything
runs), Clarity (one record for a session and for CI), Parsimony.
## C3. What a node does
| It receives | It does |
| --- | --- |
| a `record` for it | checks that it can enforce every restriction, sandbox field and budget limit (C6). If it cannot, it writes the response `refused`, naming the first. Otherwise it gives the record's user exactly its capabilities (C5) and opens the record. A session starts at once; its first delivery is `Record HASH: OBJECTIVE`. A `command` waits for its first check-in |
| a check-in on a branch in an open record's `checkins`, not sent by that record's user | gives it to the run: a session gets `Check-in HASH on BRANCH by USER`; a `command` runs once on it |
| a post in an open record's place, or a change to its ticket, by a user in its `hears`, not by its own user | gives it to the session: `Post HASH from USER: TEXT`, or `Change HASH to TICKET from USER: TEXT` |
| a `stop` for one of its open records | ends the run, and writes the response `stopped` |
| anything else | nothing |
When a session ends by itself or reaches its budget, the node writes the
response. A `command` record stays open until it is stopped. Starting, a node
reads its open records (those with no response) and answers `lost` for each
session whose process is gone; a `command` record simply goes on.
USER is always the artifact's sender (F2), read from the repository, never from
Fossil's summary, which names the user written inside it. A session takes one
delivery at a time, in the order they arrived; one that arrives while it is busy
waits its turn. Nothing is kept for a record that is not open, so an objective
cannot promise every check-in. Two runs that check in on each other's branches
can wake each other until their budgets end. Each action happens whatever
another's outcome, and the hook returns without waiting for any run.
Two ways into a session are outside Fossil: a person with admin or setup may
attach to its terminal at the node, and each attachment leaves a post in the
record's place naming who attached, when and for how long; and its runner's
remote control, when `remote` allows it, which leaves no artifact.
Besides OCX, a node's hook may do work of its own on a check-in, such as
bringing the repository's git export up to date; that is not part of this
protocol.
Justified by: Ax1 (a run acts only on what its record names; nothing polls),
Ax4 (open records are found again from the repository), Parsimony (one table),
Loose Coupling (the hook never waits on a run).
## C4. The response
The node answers each record once, as its node user, at the record's place: a
reply to the record's post, or a change to its ticket.
```json
{"ocx": 1, "kind": "response", "node": "6cbe…", "answers": "FULL-HASH-OF-RECORD", "outcome": "exited", "note": "exit 0 after 52 seconds"}
```
`outcome`, the first that applies:
- `refused`: the node could not enforce what the record asks; `note` names it;
- `stopped`: by a `stop`;
- `budget`: a limit was reached, which `note` names;
- `unenforced`: the node could no longer enforce a restriction, sandbox field or
budget limit, which `note` names (C6);
- `lost`: the node went down during a session. It answers this when it starts
again; once the run's start plus its `wall` has passed, any user with admin or
setup may answer it instead, so a node that never returns leaves no record
open;
- `exited`: the session's process ended by itself; `note` gives its exit code.
After the response, the node withdraws the run user's capabilities (C5).
Justified by: Demonstrability (every request is answered where it was asked,
even a lost one), Ax4 (no record is left open).
## C5. The run's user
`create` (Part 4) names the run's user, or makes a new one: the runner's name, a
hyphen and six random hex digits, such as `claude-7f3a2b`. The node gives that
user exactly the capabilities to read, post, check in and add tags, with none
inherited (Fossil's `u` would add the reader's), never admin or setup, and
withdraws them all when the record is answered. Fossil keeps the user itself.
Unless the record restricts `no_password` (C6), the run holds its user's
password in its clone and writes with Fossil as a person does, its capabilities
its only limit.
Justified by: Ax1 (what a run may do is fixed before it runs), Ax4 (no leftover
users that can still write), Demonstrability (all a run writes is attributed to
it).
## C6. Restrictions
A record may ask its node to hold its run to restrictions beyond its sandbox and
budget. Each is optional, and none is the default. A node may enforce any of
them, or none, and OCX's `status` lists those it enforces.
| Restriction | What it limits | How the node enforces it | When |
| --- | --- | --- | --- |
| `"no_password": true` | the run holds no password for its user | its clone gets none; its tools run on the node, outside its sandbox, writing as its user; its check-ins leave only by `push`, which copies them into the node's repository and runs the backoffice | from its start, at each tool call |
| `"branch": NAME` | its check-ins go only on branch NAME | `push` refuses a check-in on another branch | at each `push` |
| `"own_thread": true` | it posts only in its record's place | `post` refuses a `to` elsewhere | at each `post` |
- **Before the run:** a node that cannot enforce what a record asks answers it
`refused` (C4). A `create` dry run on the node makes the same check.
- **During the run:** a node that can no longer enforce one ends the run and
answers `unenforced`.
- `branch` and `own_thread` need `no_password`: a run that holds its password
can write past any tool. Runs work together by naming each other's users in
`hears`, which `create` can set in advance by giving each its `user`, and by
leaving `own_thread` off.
Justified by: Ax1 (a record states its whole boundary, runs only where that
boundary holds, and stops when it no longer does), Parsimony (no restriction
unless asked), Loose Coupling (a node that enforces none still runs every
record that asks for none), Clarity (a caller sees what a node enforces).
## C7. Versions
Every message 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 the
node answers the record `refused`. A node 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 node ignores.
Justified by: Loose Coupling (other programs can rely on the formats), Ax4
(meanings cannot drift, and no limit is silently dropped).
# Part 3. Verdicts, a data-plane standard
## V1. A verdict
A verdict is a tag on a check-in: `audited` for a judgement, by a person or an
agent, or `ci` for a program's check. 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 `command` run's verdict is written for it: its node adds a `ci` verdict on the
check-in it ran on, `pass` when the program exited 0 and `fail` otherwise, its
reason the program's last line of output, against its record.
Justified by: Ax2 (always judged against a named objective), Loose Coupling (a
verdict needs no record: a person may judge against a file).
## V2. Reading verdicts
A verdict counts only when its sender (F2) neither sent the check-in nor is
the user written in it. A record it names must have the check-in's branch in its
`checkins`. Fossil shows only the latest tag of a name on a check-in, but every
tag change stays in the repository with its user, so a reader takes each user's
latest verdict from there. Every user's verdict counts; how to combine them is
the reader's choice. Readers include people, OCX's `queue` and `activity`, and
checks such as a merge gate or a CI check.
Justified by: Demonstrability (attributed and kept), Ax2, Clarity (one rule for
every reader).
# Part 4. Tools
Nobody writes messages or verdicts by hand. People act through tools on the web
page or the command line; a run calls them through MCP or OCX's command line,
which its node offers it. 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.
Messages 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
not, naming the field at fault. `log` lists the steps it took.
| Tool | Input | What it writes | Who |
| --- | --- | --- | --- |
| `create` | the record's fields (C2), `node` defaulting to this node's, `user` to a new one, `runner` to `claude`, `checkins` to `[]`, `hears` to every user holding admin or setup when it runs, written out, `remote` to true where the runner offers it, `restrict` to `{}`, `sandbox` to `{"network": true, "read_only": [], "read_write": []}`; `budget` with its `wall` is required; and where: `to` (a post to reply to), `ticket`, or neither, for a new thread | a `record`, at that place; on the node itself it runs the backoffice, so the record is acted on at once | admin or setup |
| `stop` | `record` | a `stop` for it, at its place | admin or setup |
| `post` | `to` (a post's hash), `text` (Markdown) | a reply to that post | anyone who may post |
| `audit` | `checkin`, `verdict` (`pass` or `fail`), `reason`, `against`, `tag` (`audited`, the default, or `ci`) | a verdict (V1) | anyone who may check in, never on their own check-in |
| `push` | none | the run's new check-ins, copied from its clone into the node's repository as its user (C6) | a run whose record restricts `no_password` |
| `status` | none | nothing: says who and where the caller is, and which restrictions this node enforces | anyone |
`network` defaults to true because both session runners reach their own
service. OCX's other tools, for releases, the git round trip and attaching,
write no messages and no verdicts.
Justified by: Clarity (typed inputs, one answer shape, the same tools from
every place, and `create` takes the record's own fields), Loose Coupling (MCP is
a boundary either side can replace), Demonstrability (the dry run), Parsimony
(six tools, no notation to learn).
# 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.