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
A question and its decision (was "The ask") {"ocx": 1, "kind": "question", "for", "question", "options", "stakes", "references", "run"}, options and references left out when empty and stakes and run when not given, and {"ocx": 1, "kind": "decision", "question", "note"} (questions): post writes each, given for or decision, as a pretty-printed fenced block after Markdown that no reader parses: "Question for USER: …"; the options numbered, the first (recommended); "What it changes: …"; "Read first: …", each reference linked by its title, a link from the repository's root that Fossil's Markdown completes; "Decide: on the OCX page"; or "Decision from USER: …" or, from one who may confirm it, "Closed by USER: …", its words escaped as Markdown, a fence's backticks and tildes among them, and refused unless the text reads back as the question or decision it was made from. Each is tagged with its kind in the same turn, and read leniently, a key the reader does not know passed over; their schemas are derived from OCX::Question and OCX::Decision, which help shows. A block without ocx, as post wrote before, asks nothing; a question asks no one, and a decision counts for nothing, as questions, section 2 says. A question's options read to a person numbered, the first recommended, as OCX::Choice writes each (1. Yes (recommended)), and as JSON its words alone spec/guards/question_spec.cr, spec/ocx/post_spec.cr, spec/ocx/questions_spec.cr, spec/ocx/console_spec.cr
A question's references, described post resolves each reference given, a hash, a prefix, a ticket's or tech-note's id, or a link of the server, whole, from its root, or from the host's root with the server's path again, to the one artifact, ticket, tech-note or wiki page it names where the caller is, by one query, and writes it as a link from the repository's root: /forumpost/HASH, /tktview/TICKET, /technote/ID, /artifact/HASH?ln=FIRST-LAST for a file's lines (a check-in's file by its path resolved to its artifact), /info/HASH for anything else Fossil names by hash, or /wiki?name=PAGE; refusing a link of another server or of no such page, lines given otherwise than as one line or one range, each line at most nine ASCII digits, one naming nothing or several, what Fossil holds private, and, from a clone, what the server's receipts say it has not received; and a question whose for may not read and edit (j, k) a wiki page it references, or whose edits there a moderator would hold. console gives, for each question waiting on the viewer, what to read first: what it replies to (the post, or its ticket; nothing for a thread's first post), then its references, described by one query with where each question and run is (Place#described), then one for the hashes their titles and excerpts hold: {title, path, url, excerpt}, the same in the JSON a client such as Stone reads, and every view shows each as a link, its title included: the page links the title with the excerpt folded beneath, the command line prints the title and url in full, or path with no public URL, the excerpt beneath, and the post's Markdown links each by its title; the description itself is {title, kind, by, at, excerpt, link, url}. kind is forum, ticket, technote, checkin, file or wiki. title is a thread's title as Fossil's forum reads it, a ticket's title, a tech-note's comment, a check-in's first comment line, a file's name and lines, or a page's name. by is the receipt's user (a ticket's first change's); at is the writer's clock; url is the link from the repository's public URL. excerpt is at most 300 characters on one line, an OCX message's block left out, or a file's lines (at most 20); each hash in a title or an excerpt naming one thing is shown by that thing's title, in quotes, one level deep, any hash in that title cut to "…", and one naming nothing here, or several, cut to "…" too, by one more query; each decision's note is shown so, by one query more when one holds a hash. Only what the caller may read is shown (2 a post, r a ticket, j a tech-note or a page, o a check-in or a file), never what Fossil holds private; the rest has the title "not readable by you", and a link naming nothing here "not in the repository" spec/ocx/described_spec.cr, spec/ocx/post_spec.cr, spec/ocx/console_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 and, in a run that names one, its clone, 10 to 40 lower-case hex digits the node's repository's server-code starts with, a report carrying its writer's server-code as its clone (protocol v2); or a question to a user or its decision, which no node acts on (above); the first such block in an artifact is its message; a run any text of which, a key among them, is not UTF-8 or holds a NUL once JSON's escapes are decoded, as \u0000 is a NUL, does not read as a run, and create and the node alike refuse it, naming the field (section 11, row 2), so no process is started with it; OCX writes each as a pretty-printed
```json
block
spec/ocx/messages_spec.cr, spec/ocx/acting_spec.cr
The ocx-message tag a hint written by create, stop, post and tag_messages for questions; the daemon and watchers read every message regardless of its tag, and page reports carry no tag spec/ocx/message_tags_spec.cr, spec/ocx/tag_messages_spec.cr, spec/ocx/run_pages_spec.cr

Fossil

Contract Pinned by
The daemon and watcher with Fossil 2.27: /chat-poll with a same-origin Referer; fossil remote off then fossil pull NAME, complete only when Fossil saves the default remote; one blob.rcvid for each pull, across round trips; the clone's default user named with fossil user default NODEUSER; /forume2 and /tktedit with csrf and Referer, mutype=Markdown for ticket comments, redirecting only once stored; fossil push --once NAME and fossil uv sync NAME leave the default remote unchanged spec/facts/fossil_spec.cr, spec/ocx/daemon_spec.cr, spec/ocx/daemon_pages_spec.cr, spec/ocx/run_pages_spec.cr, spec/ocx/server_pages_spec.cr, spec/ocx/pulls_spec.cr
Ticket changes as fossil ticket change makes them, setting icomment, login and mimetype (text/x-markdown), composed by OCX (D, J, K, U and Z cards) and stored with fossil bundle import, as a post is, their text in a file, so no limit on one argument bounds it: a run written by create, a stop by stop and a change by post, as the caller on the served repository; a change by post, and a run by create, from a clone's checkout, in the caller's clone; a change holding an OCX message stored with its ocx-message tag by the same command spec/ocx/create_spec.cr, spec/ocx/run_spec.cr, spec/ocx/post_spec.cr, spec/ocx/acting_spec.cr
Written in the caller's clone and pushed with fossil push (post, and create and tag_messages in a clone's checkout, after fossil pull), a push that reports Error:, makes no round trip, or that fossil fails, as when a writer outside OCX holds the clone at each of its runs, counting as not received, the refusal naming the post or change the clone holds, which a later sync sends unless the push was refused as not authorized; or written on the served repository named outright with --user CALLER (create, stop, tag_messages, and post, as a press on the web page writes a decision); either way Fossil records the artifact as received from that user (rcvfrom) spec/ocx/post_spec.cr, spec/ocx/create_spec.cr, spec/ocx/tag_messages_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), and, when it holds an OCX message, the control artifact tagging it ocx-message, written by OCX into a bundle file, each named by the repository's hash policy as fossil hash-policy says it (SHA1 under sha1 or auto, SHA3-256 otherwise), and stored by one fossil bundle import BUNDLE --publish --force [--user USER], on a repository named outright or in a checkout, which stores, indexes and tags them together or, failing, stores nothing, so no post is ever found stored and not indexed, or untagged (HISTORY.md decision 112); 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, spec/ocx/writers_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); and, after a command that met a writer or a reader outside OCX holding the repository, or a checkout's own database (database is locked), which stored nothing, fossil sql -R REPOSITORY ".timeout 15000" "DETACH configdb;" "BEGIN EXCLUSIVE; ROLLBACK;", or for a command in a checkout first the same there with --no-repository :memory: in place of -R REPOSITORY, on the checkout's own database alone, then that one on the repository alone, Fossil's settings detached from each, writing nothing, which waits for them to let go as SQLite waits on a lock, outside OCX's lock beside the repository, before the command runs again, until they have held on past three such waits or come first before each of eight runs after one that ended as they let go, the last failure raised then spec/ocx/fossil_spec.cr, spec/ocx/writers_spec.cr
The after-receive hook as hook installs it: %F git export --if-mirrored -R %R, once, replacing any ocx2-hook command and leaving every other hook alone; unhook removes both commands. No release root or node is installed. Standing reads Fossil's backoffice settings and chat-timeline-user. Fossil's backoffice runs its own export after a sync, doing nothing when there is no mirror. spec/ocx/hook_spec.cr
Protocol v1 run-work occurs on the agent machine: daemon checks the project password directory each minute, adding new and newly approved clones without a restart, and pulls every clone whole, publishes completion numbers, evaluates every unsettled run and hands watch RUN URL FILE --repository CLONE; watch alone reports through Fossil's pages. Its run lock and durable taken, ending and done states prevent another launch. A run with no state file whose ended the server's receipt page says this node user sent counts as done; an ended another user sent, whatever its user card says, does not. A waiting run is evaluated in later rounds. Each watcher gives each new arrival once at completed pulls, in server order, asking for authorized stops and naming a held-back filter. spec/ocx/daemon_spec.cr, spec/ocx/run_states_spec.cr, spec/ocx/run_pages_spec.cr, spec/ocx/giving_spec.cr, spec/ocx/watch_spec.cr
The fossil CLI only where a person would use it (clone, open, changes, stash list, pull, pull NAME, push, push --once NAME, uv sync NAME, user default, user, login-group, whatis, remote off, remote add NAME default, remote list, remote, info, tag add, wiki create, hook, settings, sql read-only, import --git, git export and status, hash-policy, bundle import, which stores a post, a ticket change or a control artifact of tags that OCX composes, with its tag, in one command, since Fossil has no command that writes a forum post), with Fossil 2.23 as the original floor; the node commands (pull NAME, remote off, remote add NAME default, remote list, user default, push --once NAME and uv sync NAME) are pinned on Fossil 2.27 by spec/facts/fossil_spec.cr, 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, spec/facts/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, and the ocx-message tag on them, read and added; 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 server URL its node's entry in the project password directory names (http or https with a host and no user of its own), the run user's password taken by the watcher from the node's credentials file and remembered by the clone, 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; removed by the watcher, for a run whose directory step has "remove_on": "saved" and whose sandbox ends with the node, once the run has ended, the watcher, Linux's subreaper while the process ran, has waited for each sandbox init it took, and Fossil, confined, finds no change, file it does not track or stash in a checkout step's checkout and no artifact unsent in the clone; ended's workspace says removed or kept: and what it holds, and a run answered lost by the next watcher, finding taken and the run's lock free, keeps it spec/ocx/watcher_spec.cr, spec/ocx/fossil_spec.cr, spec/ocx/program_spec.cr, spec/scenarios/talk_spec.cr
A run's process, as protocol v2 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, own_session as --new-session but for a process on a terminal, which is in a session of its own already, the terminal's, workspace_at as the workspace bound read-write at that one path before the paths named, each host path within the workspace seen at its place under it, and the command, env, cwd and made files reading $$workspace$$ and the values within it as the process sees them, while every checkout OCX opens names its repository by the path from itself, so it opens there too (HISTORY.md decision 86), and OCX's own sandboxed tasks, a project'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; one with no sandbox started by setsid in a session of its own, whose process group, and each group of that session holding what it left, a stop sends TERM, and which the watcher ends once the process has ended, by itself or past its wall, as it ends a sandbox's init bubblewrap left, whether or not the sandbox ends with the node, waiting until each has ended (HISTORY.md decisions 97 and 118); 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, spec/ocx/ending_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, answered in full 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; from a clone's checkout, the page, by name or by a URL under the server the clone syncs with, is read in the clone just pulled, from its newest version in the server's order whose sender holds admin or setup, as the server's receipt says, asked unsigned 64 at a time, a version it has not received ignored; a project 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/state/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 watcher 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
A run's terminal, as protocol v2 makes it for a run whose process.terminal is true: a fresh pseudo-terminal from /dev/ptmx its watcher holds, opened as none of the watcher's own and inherited by no program but the run's process, which starts in a session of its own whose controlling terminal it is, by the host's setsid -c outside timeout and bubblewrap, so a window set on it signals the program (SIGWINCH), and which says on its STDERR, exiting 127, when the program cannot be started; its window 50 rows by 200 columns, its far end the process's STDIN and STDOUT and a pipe of its own its STDERR, copied to what the terminal shows; the run's first line and each delivery typed in as the relay gives them, each ended by a carriage return, and, with deliveries: start, where the run and each delivery start a process of their own, an end of input (Ctrl-D) after that process's lines, a session that feeds never getting one; what the terminal showed, its escape sequences and carriage returns taken out, kept as STDOUT's end; TERM, like every variable, only as the run's env names it; a line longer than 4095 bytes cut there for a program reading lines, as Linux holds a terminal's line spec/ocx/terminal_spec.cr
Joining a run's terminal, attach RUN, on the command line of the node's host alone: the socket ROOT/state/runs/RUN.terminal (0600) its watcher binds, as the tool reaches it, by /proc/self/fd/N/RUN.terminal through a descriptor of that directory, as a socket's whole name may be no longer than 108 bytes, before the process starts, removing first one a watcher that was killed left, and removes when the terminal is let go, so only the account the node runs as may open it, no Fossil capability being asked; found by the run's hash or a prefix of it; the person's terminal, which must be one, raw while joined and given back as it was; first a line, their window's rows and columns, which the run's terminal takes on, Linux signalling its program (SIGWINCH), so it redraws at once to fit, no key needed, unless their window is already the terminal's, which signals nothing; then each key they type, while they see what it shows, its STDERR's copy among it, as it is, their terminal reading it as it reads any program's output, so a mode the run's program sets there, such as its alternate screen, stays once they leave; one person at a time, a second waiting; one who does not keep up missing what was shown meanwhile, the process never waiting on them; Ctrl-] going no further and closing the connection's writing half, after which the terminal has its own window again, 50 by 200, its program signalled again, before the node closes the connection, answering joining: left; a process that ends closing it, joining: ended spec/ocx/attach_spec.cr
create and stop write a run or stop as their caller, leaving the answer to the watcher. A run must name its node. On the agent machine, run RUN --repository CLONE reads the clone's project password file, asks the server for receipts, decides by hand and hands watch --by-hand. status reads runs for every node user an administrator's run names on the served repository, with no in_care; with status --repository CLONE --login on the agent machine it shows the node's offer (node user, clone server-code and enforced limits) and reads local care and processes. The offer is absent on the served repository. The hook has no node or last run; the daemon's last round comes from ROOT/state/daemon.log. spec/ocx/create_spec.cr, spec/ocx/run_spec.cr, spec/ocx/watch_spec.cr

Serving

Contract Pinned by
import RUN --root ROOT: a setup-only release tool on the served repository, offered as a POST on the page; dry runs check and list changes without writes. Import uses the owner's settings/builders.json, counts the run and first reports through Acting's receipt rules, compares the stage pattern, checks shared bytes and inventory, copies and smokes before offering next, then removes shared files. Stage, import, accept and rollback share one root lock. spec/ocx/release_import_spec.cr, spec/ocx/dry_run_spec.cr, spec/ocx/styles_spec.cr
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; a bar at the top linking each group of tools and each tool; with no tool named, the OCX page, /ext/ocx2-cgi: its header linking console, a page of its own of which it draws no card, then its tools in groups, drawing nothing a tool does not answer (runs, an agent's work, the repository and its node, releases, about this program), each group's title heading its tools, 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, a POST, so nothing typed in it is kept in a URL or cut short with one, 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 writes nothing, whatever it needs, taken from any request, a GET among them, the viewer still holding what it needs; one that may change something taken only by a POST whose Referer is OCX's own page, Fossil's base URL then /ext/ocx2-cgi or /ext/ocx2-cgi-next then nothing, / or ? (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 and no CSRF token, and never from another page of the site, such as a file a user committed, which Fossil serves under /doc (HISTORY.md decision 111), a GET of it showing its dry run; an answer's result before its log; a leaf that links by its words on one line, where it leads percent-escaped; console's own page, below; text escaped as Markdown, attributes as HTML spec/guards/environment_spec.cr, spec/ocx/styles_spec.cr, spec/ocx/elements_spec.cr, spec/ocx/console_spec.cr, spec/ocx/harness_spec.cr, spec/scenarios/question_spec.cr
What waits on a user, as data: questions [--for USER], needing 2r, writing nothing, the same answer from the page, as JSON, its host's command line, MCP, or a clone's checkout, where the server's receipt tool says who sent each question and decision; through the one generic layout, as every tool's answer; {for, waiting, to_confirm, open}: each question {asked, where, title, link, url, from, at, for, question, options, stakes, run, replies_to, references, decisions, confirmers}, each field once, absent ones left out, link from the repository's root by the first ten digits of a hash, at in UTC as its writer's clock said, replies_to and each of references described {title, kind, by, at, excerpt, link, url} as far as the caller may read it, each decision {from, at, note}, a note's hashes shown by their titles; no post's text, nor its block beside the question it holds spec/ocx/questions_spec.cr, spec/guards/question_spec.cr, spec/scenarios/question_spec.cr
A person's view: console [--for USER] [--login], needing 2r, writing nothing, from the page, its host's command line, MCP, or a clone's checkout. In a clone's checkout it shows runs only given --login; elsewhere it shows the record's runs. It reads questions' answer and the runs as status reads them, and each entry point lays it out its own way. Its page and its text are laid out for a person and are no interface of data: the page, /ext/ocx2-cgi/console, a page of its own in the skin with no list of tools, no answer around it and no form of its own, one link to the list, its title then one block of HTML, <html>, which Fossil's Markdown keeps whole, each link in it under the repository's root as FOSSIL_URI names it, each press a button posting its input and back to its tool, after which the page answers a redirect to console?written=HASH, saying so in a line, or console's page saying why nothing was written; the text, at the command line and over MCP, with no answer around it, the presses of a question as one call, the command line after the program and --repository and --user as given, or over MCP ocx_post and its input as JSON, the field to fill in as TEXT, then each option by its label, each excerpt's lines quoted, a control character shown as U+FFFD; on both, chosen by the tool's name, a section holding nothing left out and named in one closing line, and a refusal or a dry run one line, then in the text next: where the tool says what to do instead, a dry run's line saying it was one and, where console would stop without it, why. Its JSON is the view's data, which this row pins: the answer, its result {for, waiting, to_confirm, open, clone_users, running, ended}, the questions shaped for reading and the runs: clone_users, an array naming every node user an administrator's run names, empty when none is known; running and ended give their runs; local care is read only with --login on a clone; each question {question, for, from, at, where, changes, read_first, decisions, decide, confirm}, read_first only for what waits on you, its references, absent when it has none, decide and confirm only in your own view, holding what post needs, each a press {label, recommended, tool, input, asks, hint} of post --decision, its question named by the first ten digits of its hash, its input as post reads it, decision true, which MCP's ocx_post takes as it is; each run {objective, where, sent_by, runs_as, phase, since, note}, phase one of waiting, starting, running, stopping, lost and ended; at and since how long ago, and in JSON the time in UTC; no hash shown but in a link or a press, nor in its log, which counts the artifacts it asks the server of. spec/ocx/console_spec.cr, spec/ocx/styles_spec.cr, spec/scenarios/question_spec.cr
release [--root ROOT] [--release NAME --file FILE]: current and previous, names and SHA-256 inventories; listed file bytes as base64, current or previous only, signed-in setup or owner-listed builders only, nothing written; USAGE holds the fields spec/ocx/release_read_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 (Fossil's export hook, installed by hook, and export keep it current); 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
project NAME [--daemon-root DAEMON_ROOT] [--from UPSTREAM] [--mirrors DIR] [--kinds "session"]: make a served repository empty or from git, export it, join the login group, install its hook, chat user and ticket fields, with --daemon-root, file its NAME-node and run users' passwords privately under that root's settings/credentials/, for the running daemon to make its clone in state/clones/ within a minute; on the page it runs detached from the page's release root spec/ocx/import_spec.cr, spec/ocx/imports_detached_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, or by create, which gives it gio24 and R; it holds neither admin nor setup and is not a node user, or the node refuses the run; the node's credentials file supplies its password for a password step, used to clone and remembered by the run's clone; the watcher resets no server password spec/ocx/watcher_spec.cr, spec/ocx/decisions_spec.cr, spec/ocx/create_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 repository named that is not there is said to be, and no fossil command runs on it but the clone that makes it, so none leaves a lock beside it. A tool that acts on the served repository takes a checkout's only where Fossil's export 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
Given --receipt-fd N, the web page's receipt relays to the receipt service: the launcher has sent its identity line {user?, capabilities, repository}, then the CGI sends {ocx_receipt: 1, artifacts?: [...], capabilities_of?: USER} and reads the service's answer, with no repository access; this sandbox refuses every other tool. 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; in a clone's checkout, the server's own receipt asked, unsigned, its refusal given as it says it, and its answer refused unless it is of the artifacts asked, in order, and the user asked; in any other checkout, refused; 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; asked of 500 at a time, so any number may be), 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, wiki_moderated, whether the repository holds each wiki edit they save for a moderator (its modreq-wiki on, and the user lacking ModWiki, l), and ticket_moderated, whether it holds each ticket change they make in its ticket pages (its modreq-tkt on, and the user lacking ModTkt, q), all 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, spec/ocx/receipt_service_spec.cr
The check-ins no verdict has judged, by the reading rules: unaudited [--branch BRANCH], needing no capability, refused on the served repository to a caller without Read (o); the public check-ins with a row in Fossil's mlink (a check-in changing files), on BRANCH by its branch tag or on every branch, oldest first by receipt (rcvid) then row (rid), at most 50, each {checkin, branch, user, comment}, user its U card, with count; less every one on which a control artifact's T card (+ or *, events of type g, never only tagxref) sets audited or sym-audited to a value matching pass: … (against …) or fail: … (against …), received from a user who holds i when read, is no login named as the node of a run an admin or setup sent, and neither sent the check-in nor is its U card's user, and whose X, when a hash in full, names a run about the check-in: one whose first started from its node names it as checkout, or whose checkins names its branch, a hash naming no run counting for nothing; from a clone's checkout, the server's own answer to an unsigned POST of json and, given one, branch to /ext/ocx2-cgi/unaudited, answered in full within ten seconds, with asked the server's URL spec/ocx/verdict_spec.cr, spec/scenarios/audit_spec.cr
What was said where a record is, for protocol v1: thread OF [--after POST], needing Read (o), not offered on the web page; OF the hash, or a prefix of at least 4 hex digits, of any post of a forum thread, of a ticket's id or of any change of it, as post TO and create --ticket also name a ticket, refused when it names neither or more than one; each post of the thread (forumpost rows whose froot is its first post, edits included) or each change of the ticket that sets icomment, in the order received (rcvid, then rid), as {hash, from, when, text}, when the post's fmtime or the change's tkt_mtime in UTC as RFC 3339 writes it; at most 20, after the one POST names, refused when POST names one the server has not received, with more counting the rest; in a clone's checkout it refuses a clone with no remote and a pull that reports Error: or makes no round trip, pulls, reads the clone, and orders and names each sender by the server's receipt answers, asked unsigned 64 at a time, one the server has not received last and from no one, refused when the server says it has not received the first post or change, which no tool writes in a clone, as where its user nobody lacks Read (o); on the served repository named outright, its own receipts, a private artifact (private), such as a post awaiting moderation, left out for a caller without x spec/ocx/thread_spec.cr
A node on a clone signs in as the node user in its credentials file, holding goC4w, neither admin nor setup, and unmoderated ticket writing. Each daemon start restores the clone's default user and names its saved remote ocx-server. Reports are posted through /forume2 or /tktedit; verdicts are pushed with --once ocx-server and confirmed through the receipt page, and shares use uv sync ocx-server when the user holds y. Neither changes the saved default remote. Credentials name each run user's password explicitly; no served reader sets one. spec/ocx/daemon_spec.cr, spec/ocx/daemon_setup_spec.cr, spec/ocx/run_pages_spec.cr, spec/ocx/server_pages_spec.cr
A login asked for and given (HISTORY.md decisions 73 and 76): register SERVER CREDENTIALS [--login LOGIN] [--capabilities LETTERS], from the asker's command line alone, needing no capability there, the one tool needing none that changes something, which the web page and MCP withhold; with no file CREDENTIALS it makes a 32-byte random code and keeps {"user", "code", "capabilities"} there (by default goC4w), readable by its owner alone; with a code, it POSTs login and code to collect, the first call too, and keeps the password in place of the code, or refuses while the login is not approved with the link SERVER/ext/ocx2-cgi/approve?login=LOGIN&key=SHA-256&capabilities=LETTERS, to be opened only as printed, its capabilities those the file keeps (a file {"user", "code"} an earlier release made: those given, or goC4w), refusing other capabilities given; with a password, it says so. approve LOGIN KEY CAPABILITIES, needing admin, on the served repository, not over MCP: refuses a login that is not lowercase letters, digits and dashes, one of Fossil's own users, a key that is not 64 hex digits, no capability, a, s, u or v, a letter Fossil 2.27 does not define but R, a user holding admin or setup, and a user approve did not make or that no longer holds the password it set; makes the user holding exactly CAPABILITIES with a random password, or sets the one it made, keeping the password for the same key, and keeps {"key", "password"} in the config row ocx-node-key-LOGIN. collect LOGIN CODE, needing no capability and changing nothing, not over MCP: the password when the code's SHA-256 is the key kept and the user still holds that password, else refused spec/ocx/logins_spec.cr, spec/ocx/dry_run_spec.cr
Letting a user send runs (HISTORY.md decision 109): send_runs USER [--off], needing admin, on the served repository named outright, at every entry point; refuses, naming why, one of Fossil's own users (nobody, anonymous, reader, developer), whose capabilities OCX never changes, and a user the served repository lacks; reads the letters the user holds of its own (its user.cap), then adds R at the end of them unless they hold it, or with --off takes every R out, in one SQL statement that leaves every other letter as it is then, so one another writer gave the user after that read stays, and that writes nothing where the letters already say what is asked (HISTORY.md decision 111); answers {user, capabilities, note}, the capabilities as receipt reads them, inherited ones included, and note only when the user holds admin or setup, saying R changes nothing it may do, or when, R taken away, it holds R still from Fossil's own users, saying so; on the web page a GET, as the link send_runs?user=USER, shows its dry run with the form holding USER, and only a POST whose Referer is OCX's own page changes anything spec/ocx/send_runs_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, git), and ocx2 --mcp is the MCP server too, as a program's own configuration starts it, and ocx2 --mcp-http HOST:PORT the same over HTTP on loopback alone (one message posted to /mcp answered as JSON, a notification 202, any other method 405, any other path 404, more than 10 MiB 413, another host refused, the MCP version a client asks for given when it is one spoken), and ocx2 --mcp-tunnel TUNNEL-ID the same through OpenAI's Secure MCP Tunnel (its key in OCX_TUNNEL_KEY, refused without one; each command long-polled from /v1/tunnels/ID/poll answered at /v1/tunnels/ID/response with its request_id, channel and shard token: a message jsonrpc_response, a notification notify_ack, a session's end session_termination_response, a command of an unknown kind or past its response_timeout not answered; a refused poll backed off, an answer refused for a time tried again; ended, saying so, when the key is refused), and ocx2 --mcp-ollama URL --model NAME --steps N --system TEXT MCP's caller instead, OCX's agent for local models as a run's command (below); in a clone, MCP's caller holds what the server grants its user, as the server's receipt says unsigned, not what the clone lists, setup, the command line keeping the clone's, 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; a field's name or text that is not UTF-8 or holds a NUL, JSON's escapes decoded, is refused, naming it, before any tool reads it, at every entry point: the command line's own flags, its tool's name and an option's among them, the page, with a 403, MCP and OCX's agent's calls, which go on serving; create's fields and a pattern's JSON block are refused as the node refuses the run they make (above), naming its field; a failed operation's refusal keeps only its error's first line, so no answer carries a backtrace; every answer is {ok, tool, dry_run, log, result, stopped, next_step, took_ms}, its log the typed operations performed, the result only when the tool ran to the end, and --json prints it; as text, at the command line and in MCP's content, the result, or why it stopped, comes before the log, so a person reads what the tool answered first; 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, spec/ocx/mcp_http_spec.cr
OCX's agent for local models, as a run's command: ocx2 --mcp-ollama URL --model NAME --steps N --system TEXT, URL http or https with a host and each setting --NAME VALUE in any order, any other command line a usage error (exit 2); its run's line, {"run", "objective"}, the first line of its standard input, and a delivery's line the second when there is one, a line that does not read refused (exit 1); the run read from the clone by its hash, refused (exit 1) when the clone holds none, when its process.keep.stdout_when is not always, or when it is a session whose deliveries is feed; Ollama's /api/chat asked by POST, nothing streamed: {model, messages, tools, stream: false}, the system's words then the objective and the delivery's line as the user's, each tool of the checkout's group as {type: "function", function: {name: "ocx_NAME", description, parameters}}, the parameters its input's schema; its reply {message: {role, content, tool_calls: [{function: {name, arguments}}]}, prompt_eval_count, eval_count}, a call written as text in content (each outermost JSON object with a name and arguments) taken as one, a call to a tool not offered refused, never run, and each answer sent with the next step as {role: "tool", content: its text, tool_name}; no request larger than the run's process.keep.stdout sent; each reply printed as one JSON line {sent, received} before any call it asks for runs, the request sent and the reply received each exactly, sent on the first alone, and each answer a JSON line {name, arguments, text, refused} after it, never past the run's process.keep.stdout in all; a call run only with room left for its answer, an answer that would pass it cut to fit, ending in [cut: the run keeps no more of its standard output]; once the model calls no tool, its last words posted as the run's user with post: a reply to the delivery's post, or on its ticket, else where the run is, exit 0; the step budget, the bytes, a refused post, or Ollama not reached, answering other than 2xx or no chat reply, or not in a step's time when one is given, said on standard error, exit 1; no read timeout, the run's wall its only clock spec/ocx/mcp_ollama_spec.cr, spec/battery/battery_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).