Login
OCX plan
Login

This plan says what OCX is for and what finishing it means: the objective, the precepts that guard it, the gaps between the intended product and the code, the parity it must reach and the phases that get it there. README.md holds the axioms and virtues, ARCHITECTURE.md how OCX is put together, USAGE.md the concrete commands and artifacts, and HISTORY.md how it got here. Beyond these phases, the long-term direction of OCX's building blocks, which reaches past this project, is in ROADMAP.md. When wording here conflicts with them, they govern and this plan must be corrected.

What it is for

OCX gets coding work done by people and agents together, with every step on a Fossil record that anyone with access can read later.

Precepts

Each precept is a testable consequence of a README axiom and virtue. The existing IDs remain stable for their guards: C derives from Clarity (README axioms 2 and 3), I from Loose Coupling (axioms 1 and 5), and A from Demonstrability (axioms 1 and 4). The latter two prefixes retain the older names Interchangeability and Accountability; they do not introduce extra axioms or virtues. Parsimony (axioms 1 and 4) also shapes precepts C1 (File Boundedness), C7 (Pinned Interfaces), and I7 (Single Process Site): each bounds a different source of needless complexity. A precept without a guard spec is a memory, not a mechanism. The ledger spec fails when a precept has no spec tagged # precept: <id>.

The cooperative premise in Axiom 3 is not a security assumption. Axioms 4 and 5 account for fallibility and the consequences of integration, so the derived controls remain necessary: precept I4 (Server-Only Writer) limits access to the served repository, precept I6 (Pluggable Confinement) specifies a replaceable confinement mechanism, and precept A2 (Artifact Audit) records review verdicts.

Conflict check, done before admission:

No precept requires an agent to open a served repository, so precept I4 (Server-Only Writer) has no exception.

Id Name README virtue If … then … Guard
C1 File Boundedness Clarity, Parsimony If a part is to be read whole, then no source, spec or Markdown file exceeds 400 lines, and every document renders with its links leading somewhere. spec/guards/size_spec.cr, spec/guards/documents_spec.cr
C2 Single Owner Clarity If a fact is to have one owner, then no code writes runtime or ephemeral state into any repository's config table. spec/guards/config_state_spec.cr
C3 Stated Change Clarity If a change is to be stated, then its check-in comment carries Intent, Expression, and Demonstrates lines. spec/guards/checkin_spec.cr
C4 Question Shape Clarity If a question is put to a person, then OCX frames it in the question shape (question, references, optional options and stakes); the notation is never typed by an agent or a person. spec/guards/question_spec.cr
C5 Canonical Naming Clarity If the project is named in code, then the name is OCX; the origin names appear only under a History heading. spec/guards/naming_spec.cr
C6 Explicit Arguments Clarity If configuration is to be stated, then it is an explicit argument; no code, guard, or CI step reads an environment variable, except that the program's wrapper takes from it by value the variables Fossil describes a CGI request with (the repository, user, capabilities, nonce and base path; the method, query, sub-path, body length, HTTPS flag, host and Referer) the build settings that hold no secret, and the terminal's type (TERM), which a run at a terminal passes on (the maintainer, 7242762209), and of the rest only their names. spec/guards/environment_spec.cr
C7 Pinned Interfaces Clarity, Parsimony If an interface is to be relied on, then it is listed in docs/interfaces.md with the spec that pins it, or the rebuild slice it is pending for, and every notation head the code writes is listed there. spec/guards/interfaces_spec.cr
I1 Runner Isolation Loose Coupling If a runner is to be replaceable, then its CLI's invocation and output formats live only in its adapter, and the adapter has a conformance spec that runs the real CLI. spec/guards/runner_adapter_spec.cr
I2 Repository Portability Loose Coupling If a repository is to be replaceable, then no source names a specific repository or host path; the repository is always a parameter. spec/guards/repository_neutral_spec.cr
I3 Pinned Toolchain Loose Coupling If the toolchain is to be replaceable, then CI prints and pins the dependency ledger, compiler included; a developer's run on another compiler is reported as not a gate result, and the merge gate refuses any compiler but the pin. spec/guards/dependency_ledger_spec.cr, spec/gate/compiler_gate_spec.cr
I4 Server-Only Writer Loose Coupling If Fossil is the store, then only the Fossil server, and the programs it spawns to answer a request, open a served repository; every agent works in its own clone under its own login and syncs. spec/host/served_writers_spec.cr
I5 Rollback Journal Loose Coupling If a served repository is to stay compatible with remote clients, then it runs in rollback-journal mode, never WAL. spec/host/journal_mode_spec.cr
I6 Pluggable Confinement Loose Coupling If a session is to be confined, then the confinement is a written plan and one replaceable call site: bwrap is named in one source file and started in one place, so another mechanism can take the same plan. spec/guards/confinement_spec.cr
I7 Single Process Site Loose Coupling, Parsimony If an external program is to be replaceable, then src/ starts it in exactly one place: one Process call per program, inside the function that wraps it, which is where another implementation takes over; callers reach it only through operations named for what they do, its transport private and its command words and SQL in its module. The maintainer's standing rule, stated 2026-09-23 after fossil was started from four places and only one of them had been kept from the console's environment, and 2026-10-07 after Fossil.run passed fossil's words through. spec/guards/external_programs_spec.cr
A1 Visible Evidence Demonstrability If a change is to be shown, then the demonstration its check-in names exists in the tree. spec/guards/checkin_spec.cr
A2 Artifact Audit Demonstrability If a unit is to be trusted, then its audit is a Fossil tag named audited on the check-in itself, whose author is the login that added it and whose value begins with the verdict pass or fail; the suite prints coverage and verdicts. spec/guards/audit_spec.cr
A3 Parity Gate Demonstrability If a merge is proposed, then the precept ledger has zero gaps and every row of its chosen parity contract cites a demonstrated check-in. spec/guards/ledger_spec.cr, spec/guards/parity_spec.cr, spec/gate/parity_gate_spec.cr
A4 Staged Deployment Demonstrability If a build is to be shown before it is served, then serving is a separate, named step: OCX's served link resolves into a release, never into a checkout. spec/host/deploy_spec.cr
A5 Origin Home Demonstrability If a run is to be shown, then its outcome is written to the artifact that prompted it, never to a new ticket or thread of its own. spec/guards/outcome_home_spec.cr

Host guards for precept I4 (Server-Only Writer), precept I5 (Rollback Journal), and precept A4 (Staged Deployment) live under spec/host/, tagged host, and run with crystal run ci.cr -- host; a bare crystal spec runs them too, and tells the truth about the host it runs on. They take nothing from configuration: the served directory and the served CGI root are read from the running Fossil server's own command line (--repolist, --extroot), and when no server runs here they are pending with that reason, never silently green. On 2026-09-21 they failed on the live host: three served repositories were in WAL mode, migrated in place the next day, and the served CGI links resolved into a checkout. Precept A4 (Staged Deployment) judges OCX's own link; trunk's stand until the maintainer takes them down (HISTORY.md decision 17).

Functional gaps

The architecture describes the finished product, not the state of this checkout. This table is the current gap inventory. Three places are kept apart in it:

reference means code exists on the reference branch but nothing here and no end-to-end outcome is demonstrated; gap means the needed behavior is absent or regressed everywhere; evaluate means a prior branch has a candidate whose value or fit still needs testing; here means this branch has the code and its specs but not yet the whole demonstration, and the row says what is still to show. ocx and trunk evidence identifies designs to inspect, not proof that they work. The list is the product gap inventory, not a decision to block a merge on every row.

Functionality Check-in on this branch Current evidence, gap and next demonstration State
Shared records — src/ocx/turns.cr and src/ocx/definitions.cr exist. Show a JSON definition, a human post, one agent response and derived standing on the same hash, with no duplicate answer. reference
Agent work units — Workspace.create, Launch.start and workspace serve exist as separate steps; creation still permits a file clone and keeps a second password file. Show one tool, from the CLI and a POST, that creates a workspace binding record, the unit's own login, HTTPS clone and branch, and a separate tool that runs a task in it with its runner and grant (docs/slices.md, slices 1 and 3). A person makes the login in Fossil's user pages; creating, which needs admin or setup, sets a fresh random password on it and clones with it in the URL, so only the clone remembers it and the login has one live workspace (HISTORY.md decision 29); no password enters a post, an MCP request or a model's request. gap
Confined execution — Bubblewrap has a written plan, but the current sandbox can expose the workspace clone and no cgroup meter is demonstrated. Show that the child reaches its own workspace and not the served repository or another unit's, and CPU, memory and process limits with usage recorded at task end. Verify that termination and over-limit failure are reported on the record. gap
Event-driven work — The hook, ocxd and served loop exist; ocxd already parents and reaps launched tasks. ../wake is only an edge-triggered latency hint. Demonstrate daemon startup reconciliation from synced records, one child per claimed work unit, supervision through exit, restart recovery after lost hints and failed sync, and a recovery trigger for a live daemon if a hint is lost with no later event. The current daemon's in-memory handled set and launch-note path do not prove this. reference
Distributed work: forum node — The existing /ext/ocx/status JSON endpoint can report a remote thread's agent state; a live SSE status stream is pending. Show a node accepting a local forum post under its local Fossil login, syncing it to the remote repository, observing remote status through SSE with status-endpoint polling fallback, and syncing the response back to the same local thread. Verify the two nodes keep separate credentials and permissions. gap
Distributed work: execution node — The clone-and-record design permits a target node, but periodic HTTPS sync, local hook activation, bounded on-target CI logs and result sync are not demonstrated. Show a separately provisioned node sync a task, run it on real target hardware after local after-receive processing, tag or post its result under its own login, and sync that evidence to the origin. An exclusive job still needs a server-serialized claim; a declared independent target run does not. gap
Comparable agents — The CGI has human views and this branch has a five-tool native runner, but they do not yet present the same work-unit contract as Claude/Codex over MCP. trunk has an Ollama loop and four-task battery: gemma4_31b and codex-crystal-gemma4 passed 5/8 trials. Run one saved task through human CGI, one MCP client and named local Gemma; compare edits, checks and reports, including failures. reference
Visible model exchanges — This branch writes the final answer to the record but does not post each raw model exchange. Post the exact request JSON, including system/task messages and advertised tool schemas, and the exact response JSON, including model output and tool calls, plus tool results, to the prompting thread or ticket before the next step. Record model identity and tool-definition revision. Keep session credentials outside the model request; reject unsafe or oversize payloads before sending rather than truncate audit evidence afterward. gap
Project context — A manifest creates read-only peer checkouts. Show a revision-pinned view and a separate live-status query to the peer's own record; define refresh behavior so a snapshot is not called current status. reference
Grounded search — trunk has src/vec_search.cr, indexing code and specs; this branch has none. Restore an artifact-linked search slice for people and agents. Resolve where derived vectors live without letting an agent write the served repository file. gap
Grounded search: documentation freshness — trunk has src/vec_staleness.cr, but its model contradiction test is pending. Show a known stale claim found and a current claim left unflagged, with source links and a human-reviewable result. evaluate
Model improvement — trunk has a conditioned-model builder, input digest and recorded smokes; those establish prompt packaging, not trained weight changes or reliable coding. Restore repeatable evaluations, compare against a baseline and promote only a model that passes edit tasks. evaluate
Branch contributions — Workspace defaults to a task branch, but no explicit contribution target or gated proposal is demonstrated. Record work branch and target branch in the specification; show a check-in on the work branch, CI and independent audit, then an attributed proposal or acceptance on the target. Fossil login permission is repository-wide, so also detect and report wrong-branch changes. gap
Reviewable changes — Audit tags, CI guards and a coverage ratchet exist; CI still fails on earlier check-in-format and self-audit expectations. Show a local model's cited review report on a check-in, then a distinct login's audited verdict and a CI service login's ci verdict. Meter the local review task and measure CI time before calling either free or fast. reference
Consistent tools 650b95f70f, 726c53ba93 A tool is one typed definition, and the CLI, the web page, MCP and the hook are generic walks over it: every schema is derived from its types, and list is the one source of every tool list, MCP's tools/list included (HISTORY.md decisions 32 and 33; spec/ocx/styles_spec.cr). Still to show: grants projected with it, Claude and Codex attaching to a work-unit-bound MCP server and invoking the same tools, a bounded task delegated to Gemma, and the daemon, not the idle client, driving the next turn on a hook. here
Reversible releases 7cc1f59d7e, cfd31d7024, 31dad9ff8e stage checks, builds, smokes and offers a release; accept copies it whole into the root and serves it, and stops when what is offered is served already; rollback serves the previous one again. A change is taken only from a POST from the site's own page, by Fossil's own check (HISTORY.md decisions 30 and 35), and the preview accepts only a node's first release (decision 31). On 2026-10-06 the maintainer accepted a7a5e719eb90 from ollama.openbeagle.org's page. Still to show: a rollback there, and a later release accepted from the active page, each served link resolving to an immutable accepted copy. here

Failure demonstrations for the first work-unit slice:

Scenario Required observation and response
A wake arrives during a task, or a hint is lost while idle After a task, query the record again before blocking; after a lost idle hint, recover by the chosen retry or reconnect mechanism. Serve.run already does the first, but does not prove the second.
Sync fails or arrives while scratch has edits Do not act on a stale clone or overwrite scratch. Bound retries, show unsynced to the human, and resume from the record after sync.
A model reply is malformed, too large or exceeds its step, token or time budget Record a typed failure on the origin before another model step. If posting is unavailable, retain a local pending diagnostic and publish it after sync recovers; never claim the record has it already. Do not commit or propose unverified edits. The current native runner can commit written files after its step budget fails.
A sandbox plan exposes another unit's workspace or a served repository path Refuse launch and prove the child cannot resolve another unit's workspace or the served repository; meter resource use and record an over-limit exit. The current sandbox binds the whole workspace read-write.
A release or audit arrives without its prerequisite evidence Refuse acceptance until stage smoke and checks finish; require a distinct reviewer login for an audited verdict. The current stage code smokes before offering, and host/link and audit guards exist; a release was accepted live on 2026-10-06, but a refused acceptance and the identity proofs remain.

These are test cases, not numerical risk scores. SQLite supports WAL as a concurrent journal mode; WAL does not by itself imply corruption. Precept I5 (Rollback Journal) remains OCX's served repository contract. The host guard detects departures; a deliberate server-owned maintenance action changes journal mode, not an unreviewed startup script or a process outside precept I4 (Server-Only Writer).

trunk also offers a web chat workflow and a single-binary CLI/CGI surface. Compare their user benefit and failure modes before adding either to the README. Retain the outcome if it improves the task contract; do not transplant its polling loop, repository-config runtime cursors or checkout-served release merely to recover the feature.

Node synchronization and Fossil backoffice

Fossil's backoffice --poll N periodically runs backoffice jobs on named local repositories; it does not initiate HTTPS sync. Fossil's own secondary nodes use scheduled fossil sync. An execution node therefore needs an explicit periodic sync of its own clone under its own remembered login. The interval sets task and result latency; no model process or tokens are needed between syncs. Evaluate backoffice polling only for timely processing of artifacts already received in that clone, rather than as a substitute for network sync.

After-receive hooks run from backoffice after artifacts arrive, including on a client clone, but can be delayed; their input may omit arrivals older than 24 hours. Reconcile the full record after startup and each successful sync. The hook documentation also says it runs while Fossil holds a write transaction. Under precept I5 (Rollback Journal), a hook must not synchronously query that same repository: hand the received hashes to a node-local pipe, return, then let the daemon query after the transaction ends. Today's Wake.hook opens the repository in the hook and needs a contention test and a corrected handoff before this path can be called reliable. Keep any periodic backoffice process on the node's clone; a separately launched process must not open the central served file under precept I4 (Server-Only Writer).

The forum node's remote status read is separate from sync. The current /ext/ocx/status?thread=ROOT endpoint returns JSON; SSE is still to be implemented, with authenticated status polling as fallback. The answer itself arrives through Fossil sync. Prove the local forum post, remote agent answer, live status and returned post all refer to the same thread hash.

Work-unit and tool contract

Creating a work unit and running a task in it are separate tools, each reachable from every entry point (HISTORY.md decision 29; docs/slices.md, slices 1 and 3). The unit's single JSON specification on the record names the origin, agent login, work branch, contribution target, node selection, runner, grant and resource budget; defaults require only record and agent. The node-local binding and directory are derived from that specification, not a second user-facing workspace definition. A new unit on the same record has its own explicit id.

A tool is one typed definition across CGI, CLI and MCP (HISTORY.md decisions 32 and 33): its name, summary, needed capability, typed input and output, and one method that takes every step through a log honoring dry_run; each entry point reads its own input into the typed input and writes the answer in its own layout, from the types alone. Still to come: the executor receives a bound work unit and validates its grant, and the first work-unit tool is ocx.read, a bounded artifact or path range, never raw clone SQLite.

The bound MCP surface for Claude and Codex is deliberately small:

Tool Result and boundary
ocx.context Work specification, standing, branches, node and effective grants for this unit.
ocx.read Bounded record, source or diff excerpt from the unit's clone; no repository database or secret.
ocx.edit Validated patch to the unit's scratch tree only.
ocx.check Named allowlisted check with bounded output and metered usage.
ocx.report Answer or cited review report on the prompting record, as the bound login.
ocx.delegate A bounded local-model subtask under a separately named and provisioned agent login.
ocx.propose Candidate diff and target branch for host-side validation; it does not merge or attach an audit verdict.

The Gemma baseline starts with the first five tools; delegation and proposal appear only when the grant and task need them. Each unit's clone remembers its own login's password. The node gives a confined CLI child a work-unit-bound local MCP endpoint; a small stdio adapter serves clients that expect a child MCP process. The endpoint exposes only the granted operations and is revoked when the task exits. The daemon receives hook hints, reconciles records, starts the client with the task prompt and supervises its cgroup until exit; an idle Claude or Codex process is not required to watch for new work.

The daemon and hook run under node/server service identities, not Fossil agent logins. A provisioned agent login authors its unit's posts and check-ins; a delegated local model uses its own login; CI and independent auditors use their own logins for tags. The specification records these roles, and a service note declares when the daemon posted on behalf of a unit. Fossil's repository-wide capabilities set the outer limit; the work-unit grant narrows tool access and does not pretend to restrict Fossil check-ins to a branch. Node claims must prevent two nodes from executing an exclusive job while allowing a declared independent review or comparison on both. A server-spawned CGI serializes the claim, records it on the same hash and issues a bounded lease; a stale lease can be replaced under an explicit expiry and recovery rule. Clone sync alone cannot arbitrate simultaneous claims. Prove contention and crash recovery before distributing execution.

A unit's login is made by a person in Fossil's own user pages (HISTORY.md decision 29, which replaces decisions 24 and 26 to 28 on this branch). Creating its workspace needs admin or setup: it sets a fresh random password on the login and clones over HTTPS with it in the URL, so only the clone's remembered remote holds it and older clones of the login stop syncing. Never copy a password into a JSON post, MCP request or synced artifact. The unit commits and syncs as its own login; integration into the target requires a separately attributed acceptance or explicit gate policy.

The Fossil capability reference sets the outer permissions: g clones, o reads code, 2 reads forum, r reads tickets, 4 posts forum entries without moderation, and i syncs writes. In particular, i accepts more than check-ins; it cannot express "this branch only" or "audit tag only." OCX grants such as read, edit, check, report, delegate, propose and audit narrow the mediated operations, while separate provisioned logins and host-side validation distinguish agent, CI and reviewer acts. Test the effective Fossil caps on each project, including inherited category caps, before granting a work unit.

For Gemma, start with inspect, bounded read, patch, verify and finish. Give one saved edit task a fixed step and byte budget; add a tool only when the task shows it is needed. Post each exact Ollama request and response JSON, the advertised schemas and the tool result to the prompting record before the next model step. Keep session credentials outside requests and refuse unsafe or oversize exchanges before sending; do not truncate the record afterward. Choose the smallest available Gemma variant that can run the task and record its exact model identity. Its first proof is three independent runs of the saved task, each with the correct change, passing focused checks, a completed record reply and the full exchange under the fixed budget; score failed runs too. A larger model may diagnose a failure, but does not replace this proof. Trunk's four-task battery and structured tool/result loop are starting evidence. Its fuller prompt passed 7/16 trials against 4/16 for the terse variant, so Parsimony means the shortest sufficient prompt, measured by the task, not the fewest words. Its 192-step default, ambient repository configuration, repeated schema/dispatch tables and local-only raw logs are not the target contract.

Parity contract

The maintainer has not yet chosen which branch merges into which target or which functional subset that merge must carry; the slices to ocx parity and past it are in docs/slices-parity.md. The gate remains red until the scope is written here as rows, each with a check-in on this branch and a live demonstration reviewed by the maintainer. A future feature in the gap inventory above need not block a smaller, honest merge.

Behaviour Check-in Demonstration Status
Merge target and required subset chosen on the record — Record the decision and the demonstrated check-ins for the selected functions here. open

Phases

  1. Make the baseline truthful. Resolve the existing guard failures on this branch without pretending the earlier check-ins had demonstrations they did not have. Record the distinction between spec coverage, host evidence and live user evidence. Choose one small Gemma edit task and write its minimal input, output, tool and verification contract before adding machinery.
  2. Prove one agent work unit. Restore HTTPS creation, which sets the password of the unit's own login, made in Fossil's user pages (HISTORY.md decision 29), and run a task in it as a separate tool; tools are already one typed definition across CGI, CLI and MCP (decisions 32 and 33). A confined Gemma task reads selected artifacts, edits scratch and posts exact exchanges. Show hook wake, daemon supervision, restart recovery and a metered cgroup result.
  3. Prove clients, nodes and contribution. Bind Claude and Codex to the same MCP surface and show the daemon starts each on a record change. Delegate a bounded subtask to local Gemma under its own login. Show a locally written forum post sync to a remote agent, status through SSE with /ext/ocx/status fallback, and its reply sync back. Show periodic sync delivering a task to target hardware, its local hook starting CI, and bounded output returning by sync. Test backoffice timing, exclusive claims and an independent target run. Propose a checked work-branch change with attributed acceptance.
  4. Prove review and release. Record a cited local-model review, a separate auditor verdict and CI service verdict on one check-in, and measure their costs. A built release was staged and accepted through the served interface on 2026-10-06 (a7a5e719eb90); roll one back there too.
  5. Extend only what the Gemma slice needs. Compare its saved tasks against a hosted runner and add grounded search, documentation freshness and model improvement only with separate evidence of user benefit. Preserve the result, not trunk's polling, storage or oversized prompt machinery.
  6. Compare branches before merging. Revisit this table with live evidence from the current branch. Decide which remaining trunk functions improve the README's product, and record explicit deferrals for those that do not.

Working rules

Open design questions and deliberate deferrals