Login
Interfaces
Login

Every contract between OCX and something outside it, each pinned by a spec that fails when it changes. The guard spec/guards/interfaces_spec.cr fails when a row names no spec that exists and is not marked pending for a slice of docs/slices.md, and when a notation head in the code is not listed here. Add a row when adding a contract; change the spec when changing one, deliberately.

In Fossil's artifacts

What OCX writes into Fossil's artifacts, and reads back.

Contract Shape Pinned by
The ask Question: … References: … optional Options:, Stakes: … For: <login>; versioned JSON cases specify portable parser results spec/fixtures/question-contract.json, spec/guards/question_spec.cr
An audit a raw tag audited on a check-in (Fossil's --raw, so no name for it) with value pass: <note> (against <objective>) or fail: <note> (against <objective>), the note and objective each one line; author and time are the tag artifact's; written by audit as the caller, never on the caller's own check-in, in a clone and pushed or on the served repository with --user, and read back as the served repository holds it spec/guards/audit_spec.cr, spec/ocx/verdict_spec.cr
An OCX message a JSON object in a fenced block (
```json
or a bare
```
) of a forum post or a ticket change, its fences paired as CommonMark pairs them, repeating no name, its ocx the whole number 1: a run, a stop, a started or an ended, addressed to one node by its node (protocol v1, section 3); the first such block in an artifact is its message; OCX writes each as a pretty-printed
```json
block
spec/ocx/messages_spec.cr

Fossil

Contract Pinned by
Ticket changes made with fossil ticket change, appending to +comment and setting icomment, login and mimetype (text/x-markdown): a run written by create and a stop by stop, as the caller on the served repository; a change by post, in the caller's clone; and the node's reports, as its node user spec/ocx/create_spec.cr, spec/ocx/run_spec.cr, spec/ocx/post_spec.cr, spec/ocx/node_spec.cr
Written in the caller's clone and pushed with fossil push (post), a push that reports Error: or makes no round trip counting as not received; or written on the served repository named outright with --user CALLER (create, stop); either way Fossil records the artifact as received from that user (rcvfrom) spec/ocx/post_spec.cr, spec/ocx/create_spec.cr
A post: a reply, or a thread's first post, composed as Fossil's forum artifact (D, G or H, I, N, U, W and Z cards, a card's argument with a space as \s), put in with fossil test-content-put in a checkout, an empty one of a repository named outright, and indexed there with fossil test-crosslink HASH; from a clone it is pushed, and the served repository indexes it as a post received from the pushing user; a push needs Check-In (i), and Fossil 2.27 refuses one without it with Error: not authorized to write spec/ocx/post_spec.cr, spec/ocx/create_spec.cr, spec/ocx/fossil_spec.cr
Read with fossil sql on the repository, query-only: tickets, their changes, forum posts, check-ins, tags, wiki pages, receipts and settings (docs/design/facts.json) spec/ocx/fossil_spec.cr
The after-receive hook as hook installs it: ROOT/ocx2-hook --log ROOT/node/hook.log [--node USER] %R in the repository's hooks setting, ROOT/ocx2-hook a link to current/ocx2 and ROOT/node 0700, an install by an earlier release naming the node's user with --login, which it skips, reading as another command that hook replaces; the hook is any one whose command runs ocx2-hook, deleted by its place in Fossil's list, the last first, and no other hook is touched; it reads Fossil's list of what arrived, each artifact's hash and summary, and when a summary begins check-in to it brings the repository's git export up to date (slice 40; the maintainer, f24d164c4e), and otherwise exports nothing; its log one JSON line per run, {"when", "repository", "artifacts", "took_ms", "exported"} and, given a node, its fields, exported the export's run, absent when the repository has none or another run was asked to make it, and a failed run when its export cannot be read, read back from its end and read across releases, so no field is renamed and a field added is optional; Fossil 2.27's backoffice runs it only after a page answers 200, with --nojail when the server runs as root, holding a lease for a minute from each start, and backoffice-nodelay and backoffice-disable are read as Fossil reads them, the repository's or else the account's global value spec/ocx/hook_spec.cr, spec/ocx/harness_spec.cr, spec/ocx/export_spec.cr
Protocol v1's node on the server's repository, behaving as protocol v1 sections 3 to 12 say: the hook given --node USER, as hook --node USER installs it (ROOT/ocx2-hook --log ROOT/node/hook.log --node USER %R), refused for a USER the served repository lacks or one holding a capability of its own (HISTORY.md decision 38); installing it is the node starting, its check of every run for USER; it acts on the artifacts Fossil lists as arrived and nothing else (HISTORY.md decision 39), each run it starts handed to a watcher, the hook again with --watch RUN; its log line's answered, handed, unhanded, ending, given, ungiven, watched and reports say what each round did spec/ocx/watcher_spec.cr, spec/ocx/program_spec.cr, spec/ocx/node_spec.cr, spec/ocx/decisions_spec.cr, spec/ocx/messages_spec.cr, spec/ocx/steps_spec.cr, spec/ocx/hook_spec.cr, spec/ocx/session_spec.cr
The fossil CLI only where a person would use it (clone, open, close, changes, push, user, login-group, whatis, remote, info, ticket change, tag add, wiki create, hook, settings, sql read-only, import --git, git export and status, and two test commands, test-content-put and test-crosslink, since Fossil has no command that writes a forum post), with Fossil 2.23 as the floor for every flag, started only by OCX::Fossil::Place, on the host or confined in a sandbox, where its errors are kept apart and fail as on the host; from the web page or what it starts, with none of the request's environment, since fossil given GATEWAY_INTERFACE answers as a CGI spec/guards/external_programs_spec.cr, spec/ocx/fossil_spec.cr
Fossil's operations: OCX reaches Fossil only through OCX::Fossil::Place's operations, each named for what it does (settings, users and the login group; the forum posts and ticket changes holding an OCX message, with their receipts; a ticket's newest change and a comment appended; a post a prefix names, and a post put in; check-ins and their tags, with who sent each; wiki pages, listed by a prefix of their names and every version read with who sent it; clones, checkouts and pushes; git's fast-export imported, and the git export), the transport private, so no caller passes fossil's command words, and Fossil's SQL and forum artifact format written in src/ocx/fossil.cr and src/ocx/fossil/ alone; git likewise through OCX::Git's operations. Reads have two implementations, held to the same examples: the fossil program, and Crystal reading the repository's database directly and query-only (ROADMAP.md), which a checkout on the host uses unless told otherwise; an artifact's content, writes, a sandbox and the served repository named outright stay with the program spec/ocx/fossil_spec.cr, spec/guards/external_programs_spec.cr

A run's workspace and sandbox

Contract Pinned by
Layout: ROOT/agents/USER/projects/PROJECT/RUN (0700), made fresh by the run's watcher each time it prepares the run, what was there removed: clone, the run's user's clone of the repository's public URL (its email-url, http or https with a host and no user of its own), the user's password set fresh and random each time and remembered in the clone alone (HISTORY.md decision 29), the URL holding it given to fossil clone on its standard input (--args -), never on its command line; and tree, a checkout of the check-in the run's checkout names then spec/ocx/watcher_spec.cr, spec/ocx/fossil_spec.cr
A run's process, as protocol v1, sections 5 to 8 make it: the plan written each time it runs and kept nowhere; bubblewrap's arguments from the sandbox layer's fields in the protocol's order, and OCX's own sandboxed tasks, an import's git and fossil, written as the same layers (src/ocx/tasks.cr); cpu, processes and files by a shell's ulimit inside, wall by timeout -s KILL outside; a status above 128 read as the signal that ended it, as shells do spec/ocx/sandbox_spec.cr, spec/ocx/steps_spec.cr, spec/ocx/watcher_spec.cr, spec/ocx/program_spec.cr
A run's program: its command, the program then its arguments, one named by an absolute path refused unless it is on the host, its directory (as given and with links followed) read-only and first on the PATH; its homes, absolute paths, bound read-write into the workspace by their names; its env, names a shell exports, over PATH and USER; a program directory or home that reaches the node's own files refused, as the limits' paths are spec/ocx/program_spec.cr, spec/ocx/messages_spec.cr
A pattern for create: the text at a URL, http or https, fetched without signing in within ten seconds and a mebibyte, whose first fenced
```json
block holds a run's fields, in Markdown or as Fossil renders a wiki page's (<pre><code class="language-json">), or the whole text when it is a JSON object; by convention the wiki page run/NAME, written as Markdown (--mimetype text/x-markdown), since Fossil's own wiki markup makes links of brackets; a URL naming a wiki page of the served repository (its public URL, then /wiki?name=NAME) is read in the repository instead, from the page's newest version, by receipt, that a user holding admin or setup sent, other versions ignored; an import copies the served repository's run/ pages that count into the new one, written as its admin
spec/ocx/create_spec.cr, spec/scenarios/talk_spec.cr, spec/ocx/import_spec.cr
A session's inbox: ROOT/node/runs/RUN.inbox, a named pipe (0600) its watcher makes fresh before writing started, holds open for reading and writing, lets no program inherit, and removes when the program ends; the hook puts each delivery there as one line, never waiting to open it, and gives nothing when no one reads it spec/ocx/session_spec.cr, spec/ocx/watcher_spec.cr
Writing a run, starting one by hand and stopping one: create, run and stop, admin or setup, on the served repository named outright, from the web page or its host's command line; create writes a run as the caller, its objective required, by default the first post of a new thread the objective titles, for this host's node, and as a user it makes holding gio24 when the run names none; stop a stop where the run is, and run has this host's node decide a manual run as started by a person, refusing a run that is not manual and saying why the node leaves one waiting; a write on the repository itself starts no hook, so each has this host's node act on it at once when the run names that node (HISTORY.md decision 39), and answers what it did (acted); each reads where the hook stands before it writes, a dry run lists the node's act, and a failure of the act after the write names what was written spec/ocx/create_spec.cr, spec/ocx/run_spec.cr, spec/ocx/dry_run_spec.cr

Serving

Contract Pinned by
The release root: staged/<check-in>, staged/next and staged/gate.log are the agent's, the log holding all that a stage's gate printed, written as it runs, so a long gate can be followed, and a gate that fails refused with its last line, the first five examples that failed with how many in all, and the log; current, previous and accepted copies are the server's; a release holds the shard.yml targets built from tools/ and nothing else in bin/, with gate.txt and source.txt (the checkout's remote, without its login, from which the page links each tool to the line that declares it at the release's own check-in) spec/ocx/staging_spec.cr, spec/ocx/release_commands_spec.cr, spec/guards/provenance_spec.cr, spec/ocx/styles_spec.cr, spec/ocx/command_spec.cr
The CGI: reads FOSSIL_REPOSITORY, FOSSIL_USER, FOSSIL_CAPABILITIES, FOSSIL_NONCE, FOSSIL_URI, REQUEST_METHOD, QUERY_STRING, PATH_INFO, CONTENT_LENGTH, HTTPS, HTTP_HOST and HTTP_REFERER by value, the build settings by value, and only the names of the rest of the environment; served as ocx2-cgi, the active release candidate, or ocx2-cgi-next, the pre-release candidate, saying which, inside Fossil's skin, or JSON with json; answered as Markdown that Fossil renders in its skin; with no tool named, the list, each tool a card: what it does, a "(src)" link to the file and line that declare it in the release's source at its own check-in, the capabilities it needs marked held or not for the viewer, what a changing tool would do now (its dry run, an operation a line), and its form, which is its input (dry_run among its switches, json the page's own, each described in its tooltip), left out when a POST of it would be refused: the viewer lacks what it needs, or the form has nothing for the viewer to fill in and what the tool would do now stops (a plan made with no input cannot judge a form with fields, such as create's); with a tool named, a button back to the list, the tool's answer and its own card, which beside a dry run leaves out what the tool would do now; the context's facts in a strip, as set by Fossil and the server, and a release root refused from the request; a style block taking its colours from the skin; stage not offered, saying why; a tool that needs a capability taken only by a POST whose Referer is Fossil's base URL or a page under it, as Fossil checks its own forms (the base https when Fossil's HTTPS is on, as fossil server --https sets it behind a proxy that ends TLS, whatever REQUEST_SCHEME says), since Fossil passes no Sec-Fetch-Site spec/guards/environment_spec.cr, spec/ocx/styles_spec.cr, spec/ocx/harness_spec.cr
Git exports: the program served under the name git, or git-next from the release offered as next (ocx2-git and ocx2-git-next too), (<ext>/git/NAME.git/…), serves the git export of the repository Fossil serves the request through, NAME its file's name without its extension, read-only over git's smart HTTP (info/refs?service=git-upload-pack and git-upload-pack, a gzipped request accepted, one whose gzip does not read refused with 400; a request body over 50 MB, raw or expanded, refused with 413, and one announced over it never read), from the directory its last-git-export-repo setting names, which fossil git export records (OCX's hook and export keep it current, slice 40); a push is refused (403), a viewer without o or h gets 403, another repository's export, whatever its file is named, 404, since Fossil gives the viewer's capabilities for the served repository alone; a repository without an export 404, an export git cannot read or a fetch git fails 500, git's answer read whole before any header is written; git is started only by OCX::Git, with PATH alone in its environment spec/ocx/git_export_spec.cr
The git export kept current: export, setup, on the served repository named outright, refused in a checkout and withheld from MCP, runs fossil git export into the directory the repository's last-git-export-repo setting names (refused when it names no git repository), one run at a time: a run first leaves ocx-export-again in the export's .git, then tries the flock on ocx-export-lock there, and the holder exports while that mark is left; the run is kept as ocx-export-last.json there, {"when", "took_ms", "runs", "added", "failure"}, added what Fossil said each export added; a failed export refuses with what Fossil said, and the next run exports what awaits; the output is the run and the state fossil git status gives (mirror, awaiting, last_export, autopush, main_branch) with the last run, and a dry run lists the export with awaiting, autopush and the last failure; where Fossil cannot say, as after an export killed before it kept anything, awaiting is absent, unreadable says why, and the export runs and mends it; nothing sets an autopush spec/ocx/export_spec.cr, spec/ocx/dry_run_spec.cr
Importing a git repository: import UPSTREAM NAME [--mirrors DIR], setup, on the served repository named outright, withheld from MCP; UPSTREAM a git URL or a directory on the served host, bound read-only into the sandbox; in a sandbox within half an hour, a bare clone (git -c safe.directory=* clone --bare --no-local), its branches alone as git's fast-export with marks, the upstream's own branch (its HEAD) named trunk, so each check-in keeps its branch, a checkout opens on the upstream's own, and the tags stay git's, and fossil import --git with Fossil's marks, the caller its admin; the repository placed beside the served one as NAME with the served one's extension, its export made of the clone in DIR/NAME (DIR by default where the served repository's export is), its .mirror_state seeded with each check-in's commit and the newest check-in's day; exported once, recording it, the export's git configuration keeping the upstream's URL; the hook added with this release's command where it is installed on the served repository; its public URL set as its email-url for its administrator, the caller, the served one's with NAME for its last segment, so a run's clone is made from it with no step by hand (the maintainer, 2026-10-09: "be ready to use the new repo without other steps"), a fact of the repository set once when it is made, not OCX's runtime state (precept C2), and left unset where the served one has none; a name not of letters, digits, ., _ and -, a repository or export already there, or no export to go beside, refused; it joins the served repository's login group last, made of the two and named for the served one where there is none, so its admin, the caller, signs in to it as to the served one (the maintainer, 2026-10-08); a run that fails removes what it made, the new repository leaving the login group first, and the directory it works in, .NAME.import beside the served repository, goes when it ends spec/ocx/import_spec.cr, spec/ocx/dry_run_spec.cr
An imported repository brought up to its upstream: what the upstream added since, from the export's marks, onto each branch Fossil has not moved past and onto upstream/BRANCH where it has pending: slice 39
Onboarding a repository: the hook installed, email-url from the served repository's, the person onboarding signing in by Fossil's login group, the web page in its menu pending: slice 37
A run's user: a Fossil user made for runs by a person, in Fossil's user pages, holding neither admin nor setup and not a node's user, or the node refuses the run; its password set fresh and random by the watcher each time it prepares a run, used to clone and kept only in the clone (HISTORY.md decision 29); OCX keeps no password file spec/ocx/watcher_spec.cr, spec/ocx/decisions_spec.cr
A tool run at the command line with no repository named takes the repository of the checkout it is run in, found as Fossil finds it, by its checkout file (.fslckout, or the older _FOSSIL_) from the working directory up, read directly; one named with --repository always wins, and outside a checkout there is none. A tool that acts on the served repository takes a checkout's only where this release's hook is installed in its repository, which marks the served one, since a hook's settings are never cloned; elsewhere it refuses, naming the checkout's repository (the maintainer, 2026-10-07, after the use-fslckout branch's example) spec/ocx/command_spec.cr, spec/ocx/hook_spec.cr, spec/ocx/fossil_spec.cr
Who sent an artifact, for protocol v1 (docs/slices-v1.md, slice v1.4): receipt [--artifacts 'HASH ...'] [--capabilities-of USER], needing no capability, on the served repository named outright, refused in a checkout; each hash in full (SHA1 or SHA3-256, in hex), any other refused; for each, in the order asked, whether the served repository received it (a phantom it has only heard of is not received), the login its receipt names, that login's capabilities as Fossil grants them, inherited ones included, the receipt's number (rcvid) and the artifact's row number (rid), which orders the artifacts of one receipt; for --capabilities-of, that user's capabilities, absent for one it lacks; to a caller without Read (o), and for a private artifact to one without x, every artifact not received and no capabilities; never the receipt's address spec/ocx/receipt_spec.cr
A node on a clone, for protocol v1 (docs/protocol-v1.md, section 10; HISTORY.md decision 43): node SERVER CREDENTIALS [--check], needing setup on the clone, from the command line alone, on the clone named with --repository in a release root, refused for a repository whose hook this root installed (the server's); it reads the file CREDENTIALS, {"user", "password", "runs": {USER: PASSWORD}}, refused unless only its owner may read it, signs in to SERVER (https, or http on this host alone; no user, query or fragment) as user with a POST of u and p to /login, keeping the cookie Fossil sets, refused without one, and refuses a node user the server lacks or that holds admin or setup there; it pulls the clone as the user it remembers, refused when the pull reports Error: or makes no round trip, and acts on what the pull brought (its new receipts, in order) as the server's node acts on what its hook is given, or with --check on every run for the node: who sent each artifact, that user's capabilities, and the server's order are the answers of GET /ext/ocx2-cgi/receipt?json&... there, asked once each, a batch of 64 at a time, within ten seconds and a mebibyte; an artifact the server has not received decides nothing and is given to no session; a run whose user it holds no password for is refused; each report it writes as the node user it pushes at once, and goes on only once the server says it received it from the node user; each run to start is handed to a watcher through the root's link, made as hook makes it, with --server SERVER --credentials CREDENTIALS, which clones SERVER as the run's user with the password the file holds, and keeps the file apart from every path the run binds; on every node, a run is refused whose user works for another node, the node of the first run an admin or setup sent naming that user, in the server's order spec/ocx/remote_node_spec.cr, spec/ocx/decisions_spec.cr, spec/ocx/dry_run_spec.cr
The one program: ocx2 chooses its entry point by the name it is started under (ocx2, ocx2-cgi, ocx2-mcp, ocx2-hook, git), and ocx2 --mcp is the MCP server too, as a program's own configuration starts it, its tools/list giving the tools MCP offers; each tool is defined once by its typed input and answer and reached from every entry point, refused by the caller's capabilities; every answer is {tool, dry_run, log, result, stopped, took_ms}, its log the typed operations performed, the result only when the tool ran to the end, and --json prints it; a dry run is the same answer, changing nothing; with no tool it runs list, each tool with the derived schema of its input, which MCP's tools/list renders; help adds the output, context and answer schemas; status shows the context and names the environment present but unread spec/ocx/command_spec.cr, spec/ocx/elements_spec.cr, spec/ocx/dry_run_spec.cr, spec/ocx/styles_spec.cr

Command lines

ocx2 documents its usage at the top of tools/ocx2.cr and prints it when run alone: every tool, as data. It takes explicit arguments; the served CGI receives only the request fields allowed by precept C6 (Explicit Arguments).