This is the medium and authority of protocol version 2.
2.0 Layers
OCX's messages let people and agents ask for work and report on it in a Fossil repository, every request and answer kept, attributed and in order. A command, an agent or a host is one use of a message, not part of what every message is. Each layer reads only what it owns, uses only the layer below it, and hands the rest up unread.
| Layer | Input | Responsibility | Output | On failure |
|---|---|---|---|---|
| 1. Fossil | artifacts sent by sync or the web | stores each, named by its hash; records who sent it and in what order (its receipt); keeps posts in threads and changes on tickets; holds users and their capabilities | artifacts, receipts, capabilities | an artifact not received is not there to read |
| 2. Envelope | a post's or ticket change's text, and its receipt | finds the message (messages); reads its version, to and re, and the one key naming its content's kind; hands the content, unread, to the reader of that kind |
the sender (from the receipt), the user asked to act, the message answered, the kind, the content | not a message, or another version: ignored, and nothing written |
| 3. Content | one kind's content, with what layer 2 gave | checks the content against its kind's table (kinds), the sender's capabilities, and a run's restrictions; acts; writes its answers as new messages whose re is the run |
started, ended, before publications |
not its own (2.4: a run's to and clone, or for an answer those of the run its re names): ignored, and nothing written; otherwise refused: an ended, outcome refused, saying why |
| 4. Patterns | a wiki page run/NAME, and what the sender adds |
holds one use's content: a command, an agent's arguments, a project's conventions | a run's content, for create |
create refuses a pattern whose content layer 3 would refuse |
OCX's code is layers 2 and 3; layer 1 is Fossil's, and layer 4 is data. A kind OCX does not read passes layer 2 untouched, for whatever reader it is meant for. A key layer 3 does not know, in a run, is refused, so no restriction is ever skipped because a lower layer could not read it. Nothing Fossil records is repeated in a message: who sent it is its receipt's, and where it is, its thread's or ticket's.
Fossil is the record
Fossil stores immutable artifacts named by hash. A forum edit or ticket change is a new artifact. Corrections and stops add to the record; they do not retract it. Forum threads and tickets say where a run is; its answers go there. A check-in records the files; an unversioned file can be replaced.
Every repository records its own receipts: sender, time and address. Receipts are not copied by sync. A clone's receipt for a pull names the pulling user, not the artifact's sender. An artifact's user card is its writer's claim. The server's receipt is the authority: its receipt number, then the artifact's row number, gives server order, never the writer's clock. Only OCX, its tools and host administrators write the acting repository file.
Finding messages
The envelope finds a version 2 block without reading its content. No version 1 block is read. A run, stop or report written by other means counts under the same rules.
Tools tag messages with raw ocx-message, its value the kind, and for a
stop or report its re after a space. Reports posted through Fossil's pages
need no tag: daemon, watcher and status read messages through a completed
pull, regardless of absent, changed or cancelled tags. Questions still use
the tag index; tag_messages repairs tags.
Senders and permissions
Each daemon and watcher asks the server's receipt page, signed in as the
clone's user, about every artifact it decides by, including reports.
It gives sender, inherited capabilities at the time of reading, and server
order. A receipt that has not arrived gives no authority. If the server
pulls from anywhere, it must pull as a user with none of the capabilities
this protocol asks for.
Admin or setup may send runs and stops. A user holding R may send runs
with the isolation its pattern sets, and stop its own runs. The run's sandbox
and limits govern it; the clone needs no additional file to take it.
One such run at a time is allowed under state/r-alone.lock.
Refusals lists the bounds.
A process's clone syncs as the process's user. OCX reports and verdicts reach the server as the clone's user. A tool writing in a caller's checkout writes in its clone and pushes, so the server receives it as that caller. Who may read a thread, ticket or check-in is Fossil's own business.
Acting clones
A node is a host where OCX's daemon acts on runs, named by its hostname, such as x86-1 and aarch64-1. Each project has an acting clone on that host. The clone is a repository, not a node; its Fossil user is not a node.
A run's envelope to names the clone's user. Its content clone must be
the acting repository's full server-code: 40 lower-case hex digits.
Both must match before OCX acts; otherwise it passes by and writes nothing
to Fossil. Missing or malformed addresses are passed by too.
There is no actor on the server's repository in this design.
Make a clone with fossil clone, never by copying the file. A copy keeps
the server-code and could act on the same run. A new clone has a new code;
send a new run for it. Several clones may share a user because every run
names its clone. All those clones share that user's authority: a report's
receipt, not its repository, proves who wrote it.
A report counts only on the thread or ticket holding the run, if its re is the run and its sender is the run's
to. A started also requires the run's sender to be a different user
holding admin, setup or R. An ended needs no such sender, so a refusal
counts. Admin's report sent as admin does not count for another user's run.
The first counted started and ended, in server order, are used.
The acting clone also knows its own writes before the server receives them.
A launched run whose sender loses permission still must be stopped or
answered lost; that revocation does not permit another launch.
Users and passwords
The clone's owner chooses the clone's user. The daemon requires g, o,
C, 4 and w on the server, and unmoderated ticket writing, never
admin or setup. i permits verdicts; y permits unversioned files.
The clone's user is its local default user, holding setup in its own clone.
The daemon keeps a named remote ocx-server for complete pulls,
verdicts and files.
The process's user is named in process.user. It holds neither admin nor
setup and is never the clone's user or another known clone's user.
The watcher refuses any login ever named as a run's to, regardless of
sender, and any login holding every node letter goC4w, inherited letters
included. At create, the check also includes published clone files and
local daemon entries. A build taking only files needs no Fossil account.
For a workspace that signs in, admin's create makes a missing process's
user with a random password and approves it for the run's to.
An existing kept password is approved unchanged for that login too.
--reset-password explicitly resets an existing user's password;
an existing remote user's password OCX does not keep requires that reset.
Fossil's built-in users and clone users are never changed by this step.
Approval and reset, including approve's reads and writes, hold the same
lock beside the served repository. approve refuses a user create made:
its approval has collectors but no registration code key.
Approval reads fall back to the pre-rename ocx-node-key-LOGIN rows
(decision 76 in HISTORY.md); the next write moves the row
to ocx-register-key-LOGIN. A current row takes precedence.
The password step collects afresh through collect, signed in as the
approved clone's user. That login can collect without a code; registration's
code remains how an asker collects its own login. No run changes a password.
The step holds it privately for clone, which remembers it in the
process's new clone. It sets no value and writes nothing in started.
A supplied password key or $$password$$ is refused.
The credentials reader retains the older runs map. It uses a local
password from that map only when collect explicitly says the user has no
approval for this login, including a registration whose for is empty;
an approval permitting collection always wins. Thus older local credentials can
still work, but cannot hide a failed request or override an approved reset.
There is no per-user lock or binding to a clone. Several runs of one
process's user may sign in at once on several hosts. An explicit reset
invalidates the old password those processes hold, as a reset means to.
Published clone addresses
When its user holds y, the daemon publishes an unversioned file
ocx-clones/LOGIN/SERVER-CODE.json holding
{"login": "LOGIN", "clones": ["SERVER-CODE"]}, then syncs it.
It holds public identities only, never passwords.
With no explicit clone, create uses the one local daemon address for the
project and its user, when available. For an explicitly named recipient
elsewhere it reads the published files. Only a file whose current bytes the
server received from the login in its name counts; others are ignored,
with that reason in a refusal when no trusted file remains. Exactly one trusted file must name exactly
one clone for that login, with matching path and content. None, several,
or malformed content require an explicit full server-code. It never
defaults to the served repository's code where no daemon acts. From a
checkout its default is that checkout's own clone code.
Stale published files can therefore require the caller to choose.
What is kept on the host
| Path | Holds |
|---|---|
ROOT/settings/credentials/NAME.json |
project server URL, user, password, registration code and requested capabilities; older runs map is still read |
ROOT/settings/unconfined |
owner's permission to run without a sandbox |
ROOT/state/clones/NAME.fossil |
the acting clone |
ROOT/state/daemon.lock, daemon.log |
one daemon on the host, and its rounds |
ROOT/state/round.lock, r-alone.lock |
serialized decisions, and one run from R alone |
ROOT/state/completed/SERVER-CODE |
highest receipt of a whole pull, published by rename |
ROOT/state/runs/RUN.lock, .state |
the watcher's lock and durable taken, ending or done state |
ROOT/state/runs/RUN.state.publications |
durable values, kept log text and completed publication items; publish requests have an .answered marker beside them |
ROOT/state/runs/RUN.inbox, .terminal |
session pipe and terminal socket |
ROOT/state/runs/RUN.workspace, .log |
workspace path and watcher log |
| the run's directory | its workspace, kept unless removal once saved succeeds |
Only the host account may read private credentials, care and workspaces. Settings belong to the clone's owner; runtime state belongs to OCX. A nonempty old version 1 root directory is refused: stop its processes, move credentials and unconfined permission to settings and runtime files to care before starting the daemon. No user lock is made or consulted.
Verdicts and versions
Verdicts defines which judgements count. Stability defines additions within version 2. Server tool answers tolerate fields added by a newer server, nested result fields included. The fields needed by the current reader remain required; receipt answers for other artifacts or users are refused.