Login
Rebuild slices
Login

The scope of the first slices of the rebuild, as the maintainer set it out (a001dc306e). A slice is a check-in that implements one specific, justifiable function, passes every guard, and has coverage demonstrating that function.

Slice 0: the reset

The guards are made independent of src/, and then src/ is reset to nothing (the maintainer, ba2c79940b), on a new ocx2 branch, leaving ocx-human-feedback as the working reference (7fcdcca8bf). What stays is the documentation, the guards, CI, the data files and the gap lists.

Keep

Make the guards independent first

Only three parts of spec/ use the library today:

Data files that name source files

Their guards require an exact match, so they change in the same check-in as the source they name, at the reset and whenever a file goes: docs/precepts/exceptions.json, spec/coverage/ratchet.json, docs/design/modules.json (then crystal run spec/support/generate.cr) and facts.json, docs/survey/functionality.json and gaps.json, the rows of docs/interfaces.md, and PLAN.md's parity contract.

Slice 0.5: four ways in, one tool

The first slice is the harness every later tool runs in: one executable, ocx2, reached four ways, and one tool that answers what it was given. It does nothing useful by itself. What it settles is the inputs each way in really carries, so the first useful tool (slice 1) and the first useful path (slice 3) are built on inputs observed, not assumed (the maintainer, in the session reviewing slice 1).

The executable chooses how it was entered by its name (argv[0]), as the console's CGI program already does to serve git (tools/cgi.cr). A name ending -next is the same entry, served from the release offered as next:

Entered as Style Input Output
ocx2 CLI arguments text, or JSON with --json
ocx2-cgi in Fossil's ext root CGI the request Markdown in Fossil's skin, or JSON
ocx2-mcp MCP JSON-RPC on standard input (initialize, tools/list, tools/call; trunk's src/mcp_server.cr) JSON-RPC
ocx2-hook hook Fossil's %R and the received artifacts on standard input a log line; calls by record from slice 3
git in Fossil's ext root git the request git's smart HTTP, read-only (slice 5)

The CLI, the CGI and MCP reach every tool; the hook reaches only the tools that change something, each called by a post on a record (USAGE.md, "Calling a tool by record"). Who may run a tool is decided by the caller's capabilities and by the sandbox it runs in, never by the way in.

The one tool: what was given

status answers in every style with what the entry resolved and what it received: the release, the style, the login and its capabilities, the repository and checkout, the request's fields by name, the names of the environment variables present but not read, and how long the run took. Nothing else. The run with no command is list, the usage as data, and echo answers its arguments as it read them (HISTORY.md decision 33).

The harness

A spec starts the one executable each of the four ways from captured inputs and checks what status answers:

Tools, defined once

A tool is one typed definition (HISTORY.md decisions 32 and 33): its name, one summary, the capability it needs, a typed input (with dry_run) and a typed output, each field described once, and one method. Input, output and context are elements (src/ocx/elements.cr) whose JSON and schemas are derived from their types, so the CLI, the forms, MCP's tools/list (the tool list's answer) and help are renderings of them, and adding a tool writes no code for any entry point. Every answer has one shape: a log of typed operations, the result only when the tool ran to the end, and why it stopped (16a5a0e43d). The log is the one place the flag is honored: a check is performed in a dry run too, a change only for real. Specs run each tool's example, and its dry run, which must change nothing.

Each tool checks what it needs, explicitly. What it needs about the caller and the place comes resolved in the caller (below); the tool does not resolve it. The capability is checked for every caller in every entry point, as Fossil reads capabilities (setup implies every one, admin every one but setup), and a refusal names what the caller held. Everything else a tool needs is an argument or a check in its log, and a refusal names what is missing. The CGI shows every tool to every viewer as a card, with its form only when a POST of it would run (HISTORY.md decisions 34 and 35).

The context, resolved once at the wrapper

Each entry point resolves one caller before any tool runs, and resolves in it everything about the caller and where the call acts: the repository, the checkout, the login, its capabilities and the release root. A tool method reads the context and never works these out itself; it only checks that what it needs is there and refuses, naming what is missing, when it is not. So tools never read the environment (precept C6, Explicit Arguments: the served CGI request fields and the build settings are its stated exceptions). The CLI and MCP find the caller as Fossil does outside a server. The last column says what is built:

Need CGI CLI and MCP Hook Built
Identity FOSSIL_USER --user, else the default user of the repository: the enclosing checkout's, or the one named with --repository none: the server's service user yes; binding.json is not read (slice 2)
Capabilities FOSSIL_CAPABILITIES the login's capabilities in that repository; none where there is no repository; a clone lists its cloner as setup none yes
Repository FOSSIL_REPOSITORY --repository, else the enclosing checkout's (in a work unit, its clone) %R yes
Request REQUEST_METHOD, QUERY_STRING, PATH_INFO, CONTENT_LENGTH, HTTPS, HTTP_HOST, HTTP_REFERER, FOSSIL_URI, body (exactly CONTENT_LENGTH bytes: on a GET Fossil leaves standard input open) arguments, or the JSON-RPC call artifacts on standard input yes
Page nonce FOSSIL_NONCE none none read; no page has a script to use it
Home and path stated, never inherited the account's home; fossil gets only that and its path stated yes
Record the query an argument, or the bound unit the artifacts received no (slice 3)
Working and target branch the record's definition the binding none no (slice 3)
Secrets none none read by a command: the unit's clone remembers its own login's password, and Fossil uses it none yes
State and pipes read only the workspace's files the wake pipe, written no (slice 3)
Clock start time, for the run's duration start time start time yes
Build settings read by value, for stage's gate note the same the same yes
The rest of the environment what Fossil and the web server pass the shell's, or the MCP client's what the Fossil server passes yes, by name only

The environment is an input

Every entry style is started with an environment OCX does not choose, and that environment is an input whether or not OCX reads it: it reaches every program OCX starts unless a wrapper says otherwise, and some of it changes what those programs do. This is a fact to account for, not a channel for configuration, which stays explicit (precept C6, Explicit Arguments; the maintainer, 7d1ff175d5). Examples that matter here: FOSSIL_USER and FOSSIL_HOME change fossil's login and settings; CRYSTAL_CACHE_DIR, CRYSTAL_PATH and SHARDS_* change a build; HTTP_PROXY and HTTPS_PROXY change where a sync goes; TMPDIR, LANG, LC_* and TZ change file places, messages and times.

References: Fossil's server extensions (the FOSSIL_* variables and CGI fields), its hooks (substitutions, standard input, and the write transaction a hook runs inside), and docs/fossil.md. The hook must not open the repository it was called for; it hands the hashes on and returns (precept I5, Rollback Journal).

Where each style runs

The CGI and the hook run in the outer sandbox, the Fossil server's, which reaches the served repository, the release root and Fossil's extension root; a session's sandbox sits inside it and reaches only its workspace (the maintainer, dd06d0a5e5). So acts on what the server owns, such as setting a login's password, are the CGI's and the hook's, for a caller with the capability.

What the code holds now

Built: the frame above; list, help, status (with the node's server-code) and echo; stage, accept and rollback, kept since releases are needed and stage is how a release is previewed; audit stripped (the accepted release's records verdicts meanwhile); the web page, a card for each tool; the captured inputs in spec/fixtures/fossil-2.27 and spec/ocx/harness_spec.cr, which replays them, and the hook's log, its only output. What the capture showed: Fossil passes an ext program the Referer but not Sec-Fetch-Site or Origin (its src/extcgi.c lists what it passes), so a change is taken from a POST whose Referer is under Fossil's own base URL, as Fossil checks its own forms; it states a setup login's capabilities expanded; and on a GET it leaves standard input open, so a CGI reads exactly CONTENT_LENGTH bytes.

Slice 1: workspace create

The first useful tool: make a work unit's workspace, reachable from all four ways in. It replaces the old release's workspace create, which is how an agent is brought in today.

Slice 2: OCX Records and responses on a ticket

The second tool: add a ticket change as the caller's login, either an OCX Record (GLOSSARY.md) or a response to one, so every later path has a place to ask and to answer. OCX Records start on tickets: a ticket change names its ticket-id, and Fossil's own command line can add one (fossil ticket), while it cannot post to a forum. Forum posts as OCX Records and responses follow after this slice, for milestone-sized work that needs a thread. Reachable all four ways.

Releases

stage, accept and rollback are built; the maintainer accepted the node's first release, a7a5e719eb90, from ollama.openbeagle.org's page on 2026-10-06 (HISTORY.md decision 31), and a rollback there is still to show.

Slice 3: an OCX Record creates a workspace and runs a task

The smallest useful path: a person with admin or setup adds an OCX Record to a ticket; the hook runs it: the workspace is created (slice 1) and a task runs in its sandbox; the result comes back as a response on the ticket (slice 2). Running is a tool of its own (the old release's workspace run), so the CLI, the CGI and MCP can run it too for testing.

Short tasks and long ones; what a crash leaves

A call says whether its task completes or stays (the session definition's "completes" or "stays", USAGE.md "What you handle"). This slice takes only tasks that complete: creating a workspace, a response, a bounded run. A task that stays, a session answering turn after turn, needs the daemon (slice 8). The hook runs a task to its end and exits, and a crash can come at any step, after a password is set or a task has run but before the response, so what a run leaves is written on the record, and what is ephemeral stays on the node (decision 3):

Built: work, which the hook runs after each receipt given the node's own login (spec/ocx/work_spec.cr); a lock is held while its run lives.

One record for workspace, session and listeners

A unit's whole definition is one post: a fenced

```json
block holding the workspace (its sandbox), the session (the process) and the records and branches it listens to. Fencing keeps it readable, because Fossil renders an unfenced JSON post as prose and loses its layout. Today's reader ignores a fenced definition, which is how sol-ocx lost its login directories (69bf7e7e9a was skipped, 5ad49ff621 followed). The new reader takes the fenced block, and a guard requires a fenced and an unfenced copy of a definition to read the same.

Each unit holds its own login

Every unit has a Fossil login of its own, made by a person in Fossil's user pages. Whoever creates the unit's workspace, with admin or setup, sets a fresh random password on that login and clones with it in the same process (HISTORY.md decision 29); the password is never on the record or in a file of its own, only in the clone's remembered remote. The child then reads, commits, syncs and reports through that clone directly; there are no host-mediated operations. Tests show:

The sandbox holds

Tests show, from inside a running child:

The structural guard on the sandbox's single call site stays beside these tests; it shows where confinement starts, and they show that it holds. Built: run and its sandbox (spec/ocx/run_spec.cr), with CPU, memory, file-size and wall-clock limits. A process-count limit is not set: Linux exempts a task whose host user is root, as the server's is, so it comes when tasks run as a host user of their own.

Milestone: one demonstrated path

After slices 1 to 3 and 10, one path is shown end to end on the served host: a person adds an OCX Record to a ticket; the hook creates the unit's workspace and runs one bounded task in its sandbox; the response lands on the ticket. The same demonstration shows a sync that fails and a run killed midway and recovered as slice 3 says, both among PLAN.md's failure demonstrations. An agent's edit, its check and a person's acceptance come with slice 8 and after.

The slices after it, to ocx parity and past it, are in slices-parity.md.