Login
History
Login

The events, decisions and failures that shaped OCX: where it came from, why earlier approaches were reset, what to keep from them, and the decisions the ocx branch was founded on. Where OCX is going is in PLAN.md.

Where it came from

What to keep

The maintainer's list of the design points worth saving, from the prompt given to agent-sol at the command line and recovered from its history (4617cd3fdf):

  1. JSON posts on tickets or forum threads carry the communication between humans and agents, so mechanical tools can use those hashes directly as a shared starting point for executing something.
  2. HTTPS sync for isolation: real file-system isolation, with access to the primary served repository through the login assigned to each agent. It is better isolation than trunk had.
  3. The hook drives behavior from data updates, without polling.
  4. Staged built binaries, with acceptance and roll-back.
  5. audited and ci tags with their own metadata, to give confidence in check-ins.
  6. Code coverage checks, and a mechanism, not yet fully verified, to keep them from taking too long on each new check-in.
  7. Useful guards, such as keeping each third-party executable's call site in a single place, though the wrappers do not yet describe well what each executable is used for.
  8. The 400-line limit on each file.

Well, we'll see how we merge all this, but I'm trying to go back to the foundation yet again and capture what really works. It seems we arrived at a few design points worth saving, like communicating between humans and agents using JSON posts on tickets or forum threads, which enables mechanical tools to directly use those hashes to get a shared starting point upon which to execute something. I think we also arrived at a better isolation mechanism than we had with the "trunk" design where https-based sync allows real file-system isolation while providing agent-login assigned access to the primary served repository. We identified the hook mechanism to drive behaviors based on data updates without polling. We identified a good process for staging built-binaries with acceptance and roll-back. We began adding "audited" and "ci" tags with additional metadata to provide some confidence in check-ins. We added code coverage checks and a mechanism (I haven't fully verified) to avoid coverage checks taking an excessive amount of time to run for each new check-in. I believe we developed some useful guards, such as keeping third-party executable call-sites at a single point, though I'm not confident in the design of the wrappers to encompass a functional description of the executable utilization. I think the 400-line-per-file limit was also helpful. What other elements of this new design/implementation seem to be really valuable? I want to try to get the most critical points into README.md and PLAN.md.

The maintainer has also said on the record:

Decisions of 2026-09-21

These decisions, made when the ocx branch began, record that branch's reasons; code and older documents cite them by number. The README governs the axioms and virtues, ARCHITECTURE.md the structure and PLAN.md the purpose; PLAN.md's gap table and phases govern the current work. A conflicting historical decision is evidence to resolve, not a second source of authority.

  1. The objective is a workbench coordinating any agents over Fossil; the native agent is one interchangeable runner beside claude and codex; third-party CLIs stay supported on Pro logins for cost.
  2. Working mode: the maintainer fixes form and target, the model produces the history, the maintainer audits by sample; the plan, not trunk, is the target.
  3. Fossil's design is followed: the server is the only writer of served repositories; agents hold clones under their own logins; ephemeral state never enters a repository; audit-worthy communication is tickets and forum in Fossil's own shape.
  4. The branch merges into trunk at parity with one honest merge check-in; history is never glossed.
  5. Tickets are not task records; a run writes back to the artifact that prompted it.
  6. Question cards are derived, not stored; the question is a body convention; the reply is a post.
  7. Build and deploy are separate steps with a smoke check between.
  8. Multi-repository from day one, with no repository-specific dependency in code; only the project's own repository holds this code; serving stays with the Fossil server; the Stone relationship is Fossil-contractual.
  9. Units are not named in advance; trust comes from saying what will be done and doing it.
  10. The name is OCX.
  11. The audit record is a tag on the audited check-in, not a file in the tree and not a wiki page.
  12. No environment variables: configuration is an explicit argument, and the host is discovered from the running server, not described to the code.
  13. A session's home is its workspace: the binding is ~/binding.json, the tree ~/tree, OCX's prompt ~/prompt; a CLI's own login directory is bound under the workspace by its basename, read-write, and nothing else of the host's home is visible. The prompt is passed where the command says ({prompt}), and task ~ inside the sandbox writes the answer as the workspace's identity.
  14. A command-line agent answers as a session in the sandbox: claude in its default permission mode with its tools named (bypassing permissions is refused to root, which the sandbox's user is), codex in its full-auto mode with its own sandbox inside OCX's; the agent's printed answer, or the file it leaves, is the turn, and the check-in is named whether the agent committed on the branch itself or OCX committed what it left.
  15. The task a ticket prompts is its title and its comment as last set whole; what was appended to the comment since are turns on the record, never the task (a prompt built from the accumulated comment made every later ask malformed).
  16. The served console shows one project per request, the one Fossil says the request is for, and shows its tickets and its threads only to a viewer whose Fossil capabilities read them (r, 2), as Fossil's own pages do. Trunk gated its console on a login (docs/fossil-auth-cgi.md) because that console could act and because a viewer must see only projects they may see; this console cannot act, so the first reason is retired, and the second is met by Fossil's capabilities rather than a gate of OCX's own.
  17. OCX is served beside trunk, not in its place: its own link under the ext root is what precept A4 (Staged Deployment) judges; trunk's links, which resolve into its checkout, stand until the maintainer takes them down, because the contract between the two is Fossil's record and nothing else. Served repositories found in WAL mode are migrated to rollback mode in place with Fossil's own tool (done 2026-09-22 for the three that were).
  18. The console lives inside the Fossil skin, as trunk's did: a logged-in person of sufficient capability visiting the repository keeps every feature of the Fossil web server and gets, in the same chrome, the questions addressed to them first, then the open questions, then what agents are doing and did (the order of trunk's dashboard: Needs you, In work, done). Fossil wraps a text/html ext response whose outermost element is <div class='fossil-doc'> in the skin; the same program serves a bare page under any link name but ocx, kept because it is useful on its own. The first cut of the console (F.3, G.2) threw this learning away; the maintainer pointed it out on 2026-09-22.
  19. Serving needs no shell after the first time: the deploy step gates on ci.cr, builds, releases a copy named for its check-in with the gate's result beside it, smokes it, and stages it as next; the console shows a setup or admin viewer what is current, what is staged (with a preview link, /ext/ocx-next) and where a rollback goes, and takes an accept or a rollback as a POST carrying the token from the release root, moving only the current, previous and next links. The served links point at those and never move again. Trunk's lessons kept: a source commit is not live (deploy-verify), and a copy without a name became a stale divergent binary (ticket 926b5abe); here every copy is named by its check-in and the served surface is what is verified.
  20. The served console reads the served repository Fossil names in the request, query-only and with Fossil's busy timeout, as Fossil's own pages do; it is the server's ext program, part of serving, not an agent, so precept I4 (Server-Only Writer) admits it and every served project has a console with nothing to configure and nothing to sync. The first cut read a clone named in a sources file (the maintainer found /stone/ext/ocx empty on 2026-09-22): a misapplied precept, since the nine corruptions came from writers and WAL, never from a reader.
  21. Whoever stages a release cannot choose what runs, nor alter what runs once chosen. The release root has two areas: staged/, the agent's, where releases are written and next is offered, the only path bound into a workspace that builds releases; and the root itself, the server's, holding current, previous, the token and every accepted release, each a copy taken from staged/ at acceptance and smoked before current moves. The maintainer's objection on 2026-09-22 to a workspace holding the whole root; the first install is the root owner's, once.
  22. scripts/ holds translations of trunk's start-fossil.sh and scripts/sync-fossil.sh, each a single file that states everything it does (host names, paths, the repository list, $HOME where the script read it) and finds its base directory from its own place in a checkout, as the scripts did. The precepts govern OCX, which is src/, spec/, tools/ and ci.cr; they do not bind scripts/, and the guards do not scan it. Agents do not change these files on any branch without the maintainer's approval on the record; each file says so at its top, and there is no other file their behaviour depends on. A release carries the shard.yml targets built from tools/ and no others, so a stale program in bin/ is never carried either (release 5349ffa94069 carried two). The maintainer's review of 2026-09-22 (thread cde80fe75b, 5797348fd9) backed out the first attempt, which put settings files and a reusable fossil invocation in src/ to satisfy precept I2 (Repository Portability) and precept C6 (Explicit Arguments); the maintainer then chose scripts/ as their place and kept them out of releases.
  23. Sessions are launched from the console. A setup or admin viewer starts one on a new or existing thread with a POST to the CGI. The CGI creates the workspace when there is none and starts the session detached from the request. The session sleeps on its record with task --wait and answers each new turn. Timers are for chores such as garbage collection, never for creating sessions. The maintainer's reasons (thread adfc87fba2, 2026-09-23): the manual steps were error-prone, he will not be tied to a console session, and a timer adds nothing here. This replaces the timer in the backlog's wake entry.
  24. An agent login is provisioned from the console, and its password is kept once per login in agents/<login>/password beside the release root. The account is created only on the repository whose console provisions it; the same password is set on the other members of its login group only where the account already exists, so provisioning never grants anything on a repository it was not asked for (the first cut created the account on all 25 members of this host's group, and the maintainer questioned it, 2026-09-23). Each repository keeps its own user table, and fossil user changes only the one it is given (www/caps/login-groups.md, tried on scratch repositories 2026-09-23). An account is retired on one repository by withdrawing its capabilities, since Fossil never deletes a user. A launch copies the password into the session's workspace, and a login may have any number of workspaces, each bound to one record of one project. Stated plainly: the Fossil server's user, and so the CGI, can read every agent's password, and each sandboxed session sees its own login's password, but no other agent's. The CGI is trusted at that level anyway, since it can operate on a served repository directly. The maintainer chose this over resetting the password at each launch (thread adfc87fba2, 2026-09-23), because resetting would break other running sessions of the same login and buys little. This amends decision 20: the console still reads a served repository query-only for everything it shows, and provisioning a login is its one write, made with Fossil's own fossil user.
  25. The console keeps its state on the record, and only a workspace keeps files. A launch writes the grant (when the record has none) and a note saying who started the session with what on its thread or ticket, as the agent. The console's Sessions list is derived from those notes, and a runner's default grant is the latest on the repository. A session's own state stays in its workspace directory (~/run, launch.log, launch.pid), since a workspace is sandboxed and works with a checkout anyway; the agent's password file stays as decision 24 put it. The public URL a session clones from and writes to is each repository's own email-url setting, set by its administrator, and a launch is refused without it. Earlier cuts guessed the URL from the request, three times wrongly, and kept launch files and a saved grant per runner beside the workspaces. The maintainer's words (thread adfc87fba2, 2026-09-23): "Only the workspaces should be getting state from the filesystem… Fossil is our abstraction to the storage wherever it can handle it", and "The email-url config property can be requested to be configured on each repository."
  26. Each work unit and each guest has a Fossil login of its own, made by an invite: a definition carrying a one-time password encrypted to the holder's public key, which the holder changes on Fossil's login page (its p capability) so that its clone remembers a password only it knows. The task child uses that clone directly, with no host-mediated operations; the sandbox, not a broker, keeps the served repository and other workspaces out of reach, and revocation or expiry removes the login's capabilities. This replaces decision 24's password file and its reason: a change breaks nothing when one login has one holder. Accepted cost: a password carried out of a sandbox works anywhere until its login is revoked or expires, and Fossil cannot limit a login to one branch. The maintainer's choice (thread 58d537bd67, ac5eaaf8ef, 2026-10-03), after asking for a design that uses what Fossil already provides.
  27. An invite's one-time password is handed over directly, in a channel the inviting person already shares with the holder; it is sealed to the holder's public key (seal) only when it must cross the record. The login's terms are its contact info, which only an admin can change, and the holder opens its record with its own first post and ends it with a closing post. This amends decision 26, which had every invite carry a sealed password. The reasons: the maintainer has only Fossil's web pages and no shell to seal with (0a85704e1b), the direct hand-off is dead once the holder replaces the password, and codex-cloud-1 joined and reviewed this way and found the documents disagreeing (c1815b2d32, 2026-10-03).
  28. The seal tool is removed, and an invite's one-time password is only ever handed over directly, never on the record. It had no use: the maintainer hands passwords over in a channel already shared with the agent, a unit's comes from the console that starts it, and nothing yet needs a password to cross the record. Crystal's standard library offers digests, HMAC, PBKDF2, symmetric ciphers and TLS but no public-key encryption, so seal bound libcrypto's lower-level calls itself; the maintainer judged that a sign of not knowing the standard library, and the tool unnecessary (236e40d65b, 2026-10-04). This amends decision 27. If a password must ever cross the record, the need comes first and the design follows it.
  29. There are no invites. A unit's login is made by a person in Fossil's own user pages. Whoever creates the unit's workspace needs admin or setup, because creating sets a fresh random password on that login and clones over HTTPS with it in the URL, in the same process; the password is never on the record and never in a file of its own, only in the clone's remembered remote. Setting it stops every older clone of that login from syncing, so a login has one live workspace, and a post that creates a workspace through the hook needs no password in it: the poster's capability is what allows setting one. Running a task in the workspace is a separate tool. The maintainer, 2026-10-04, in the session reviewing slice 1; this replaces decisions 24, 26, 27 and 28 for the ocx2 branch.
  30. Accepting and rolling back carry no token. Decision 19's token in the release root guarded the console's POST against a forged request from another site; the CGI now takes any change only from a POST whose Referer is its own page, as Fossil checks its own forms, since Fossil passes an ext program the Referer and not Sec-Fetch-Site (its src/extcgi.c), and from a terminal whoever can read the token can move the links anyway. So the token added a second lock in the browser and none at the terminal. The maintainer, 2026-10-05, in the session reviewing slice 1; this amends decision 19 and the token of decision 21 for the ocx2 branch.
  31. ollama.openbeagle.org is a staging server: its stakes are low (some agent logins and otherwise public data), its work is copied by Fossil's sync on immutable records, and it runs on isolated, untrusted hosts. On it, ocx2-cgi-next is the pre-release candidate and ocx2-cgi the active release candidate. The preview runs agent-built code as the server's account, by choice, bounded by the CI checks and by which agents are trusted. The web page does not offer deploy, which runs the checkout's own code; once a release is served, only the active release accepts, the pre-release candidate accepting only a node's first release, trusted on first use; either rolls back. Before any server holding private code or where downtime is costly, these gate: the preview as a separate OS user (or staging only), since checks enforced by the server's own account guard against mistakes and not a hostile build; acceptance recorded as an artifact holding the release digest, the full check-in, the node, the login and the time, made from the live page, with accept hashing the files itself; trust across nodes by a signature from a key held off the server; reproducible builds, tested by building one check-in twice in different places and comparing; and a per-agent or drop-only staged area in place of a shared one. The maintainer, 2026-10-05, in the session reviewing the CGI, after two outside reviews; this amends decisions 19 and 21 for the ocx2 branch.
  32. A tool is one typed definition, and every entry point is a generic walk over it (stone's review, part 3, 4bb787403b). A tool gives its name, summary, needed capability, a typed input and a typed answer, each field described once, and one method taking the dry-run flag; the CLI, the web page and MCP read their own input into the typed input and write the answer in their own layout, from its type alone, so nothing is written per tool for any entry point and nothing machine-structured comes from a second source (MCP's tools/list is MCP's rendering of the same types; ocx.dry-run is gone). Every answer carries the steps the tool took, or in a dry run would take, its result only when it ran to the end, and why it stopped. The flag is honored in one place, the step log a tool takes every step through: a check runs in a dry run too, an act only for real, and a failed step stops the run as a refusal naming it. The usage is the catalog as data. Inside, values are typed, JSON stays at the edge, a value is built by naming its fields, and every refusal is one exception (docs/crystal.md).
  33. Schemas are derived, never coded, and a log records operations (stone, after 4bb787403b). The tool usage is the tool list, and MCP's tools/list is its answer, rendered: one source, each tool with the schema of its input; help adds the context: the schemas of each output, of the context every tool receives, and of every answer, and where releases live. The catalog holds those derived schemas and nothing that restates them: no command-line usage strings, no list of options. dry_run is a field of every tool's input, so it appears in every derived schema, form and command line; the CLI's --json, --repository and --user are the CLI's own. An answer's log replaces its steps: each entry is a typed operation with its operands, such as take_release {root, name}, its schema derived from its type, with no prose and no outcome; a check is performed in a dry run too, a change only for real, and when a run stops its last operation is the one that stopped it. Caller is Context. The web page answers Markdown, which Fossil renders in its skin, so it can be walked by its headings.
  34. The web page keeps one page and changes how each element is drawn, the layout stone chose from six drawn on a design canvas with the staged release's real data (stone's review, part 4, 71e2b98cd6). Each tool is a card: its summary, the capabilities it needs marked held or not for the viewer, what it would do now when it changes something (a line for each operation: check or change, what it does as its type says, and its operands), and its form, which is its input: text fields with their descriptions, and each switch, dry_run and json among them, a checkbox described in its tooltip. The two written opening sentences are a strip of the context's facts. The page carries a small style block that takes its colours from the skin, with no > or &, which Fossil's Markdown escapes. A field's name reads with its underscores as spaces, muted beside its value; the list's needs is capabilities_needed. A tool that needs no capability changes nothing: its log refuses a change, so the page may run it from any request. The program's description stops at what it is, and the gate counts executables, since a tool is now one of the program's. A tool's own page shows a button back to the list, its answer and its own card, not the whole list again (stone, after eb9e464557: the full list there was superfluous).
  35. A card offers no form that would only be refused, the page knows its own site as Fossil knows its own, and each card links to where its tool is defined (stone, 2026-10-06, after fb21729d4a as served: the accept button was refused from the site's own page). A tool's form is left out when the viewer lacks what it needs or what it would do now stops; its name still leads to its dry run, which says why. Accept stops when the release offered is the one served already, since accepting it again changes nothing, so once a release is accepted its button is gone until the next deploy (stone, after a7a5e719eb as served). A POST is from the site's own page by the check Fossil makes of a POST to its own forms (cgi_same_origin): its Referer is Fossil's base URL or a page under it. Fossil's base is https when its HTTPS is on, which fossil server --https sets behind a proxy that ends TLS while REQUEST_SCHEME stays http, as on ollama.openbeagle.org; the check had compared REQUEST_SCHEME, so every POST from the page was refused. The CGI reads HTTPS and FOSSIL_URI, the repository's path, in its place, so a page of another repository on the same host is not this site's either. 07d7550765 had compared the host alone, which loosened decision 30's check; this keeps it. Because a tool's file is not always named after it, the list gives each tool's defined_in, the file and line that declare it, as the compiler saw them. A card links it as "(src)" to Fossil's file page in the repository the release's source note names, at the release's own check-in, with that line in view.
  36. deploy is renamed stage, and the module that stages a release Staging (the maintainer, 2026-10-07: "It is stage, not deploy in practice"; the name had been questioned since the reset). It never served anything: it checks, builds and stages a release as next, and only accept serves one. The old name also misled: an automated permission check took a staging for a production deploy and stopped it. The ocx tip's deploy and precept A4's "Staged Deployment" keep their names, the one being the tip's, the other naming serving as a step apart from building.
  37. Who sent an artifact is the user the server received it from, by Fossil's receipt. A node whose repository is a clone, such as a build host's, asks the server with OCX's receipt tool, over HTTPS, as its node user, and everything a run or a node writes reaches the server as its writer, from its own clone (docs/protocol-v1.md, section 8). The maintainer chose this, option (a), at the terminal on 2026-10-12: "go with option a". A clone had been found to record everything it pulls as received from its own user, which holds setup there (Fossil 2.27). His first leaning was signatures ("having agents produce a public/private keypair wouldn't be bad"), until he learned what they would need: OpenSSH's ssh-keygen on every node, since Crystal's standard library has no public-key signing (decision 28), and his own key for every run sent to a build host. Accepted cost: the server must run OCX, and a node on a clone decides nothing about an artifact until the server answers for it.
  38. A node user holds the least it needs, and never admin or setup. On the server's host it holds no capability, and no one holds its password, since the node writes into the repository itself and Fossil checks no capability for that. On another host it holds o to pull and i to push (docs/protocol-v1.md, section 10; tried on a scratch server, Fossil 2.27). A ci verdict counts if its run's node user sent it, whatever that user holds, and an audited verdict from a node user never counts. The maintainer asked at the terminal on 2026-10-12, "How is it setup to have least privilege and what are it's roles?" He was shown that the protocol gave a node user forum and ticket write it never used, and i where it needed none. His answer: "yes, make the proposed changes". ocx2 hook --node USER refuses a node user who holds a capability of their own.
  39. The hook acts on the list of artifacts Fossil gives it, and nothing else, reading the repository only to decide what it lists. A write made on the repository itself is acted on at once by the tool that wrote it. What the hook missed or failed on, and what a node's going down left open, is found by a deliberate check, never swept up by a later arrival. A node on a clone runs Fossil's backoffice after each sync, since a pull runs no hook (Fossil 2.27). The session's delivery mark goes with the sweep it served. The maintainer at the terminal, 2026-10-12, answering the three cases a re-read was meant to cover: stale arrivals ("why would we want to trigger a process execution. that sounds more likely to generate surprises than to meet expectations"), local writes ("the point of the hook is to handle the synchronization case, not local execution"), and failed runs ("detecting a failed hook can be a separate, deliberate process"); then "Please, have the hook stick to the list of artifacts it was given unless you have a better reason not to do so. Parsimony." This replaces the protocol's re-read at an interval, and the hook's every-run sweep of slice v1.3.
  40. OCX's code knows no agent. A runner other than command is named by the repository's wiki page sandbox/NAME, whose program, arguments, home files and environment the node runs: how a program such as Claude or Codex is run, its remote control included, is that page's data, and a run carries no field for it. Every program reads its run, {"run", "objective"}, as the first line of its standard input, and a session then its deliveries, a line of JSON each; a run's session alone says how long its program lives, and where a run is posted decides nothing: a task of many forum posts and a ticket's resolution are usage patterns, data in the runs people send. The maintainer at the terminal, 2026-10-12, in turn: "How an agent takes turns should be dependent on the task. I'd say the more typical approach should be to use terminal sessions with remote control for milestone-class tasks with multiple forum posts in the interaction. And for ticket resolution, a single process per turn should be the approach."; of a first form of this decision, which tied the way to a forum thread or a ticket (1016a51a6e): "Just let the OCX message dictate the life of the session ... That's just a usage pattern and doesn't need to live in the code at all. It is just data."; "Get rid of "remote" as an OCX message parameter."; and "there shouldn't be anything claude or codex specific in the CODE ... I don't know what you'd be doing outside of putting in command-line arguments onto the wiki page or putting something in the docs that is claude/codex specific." What is agent-specific, parsing a turn's response, live status and SSE, comes after v1 is complete, and Claude- and Codex-specific tests, outside the source ("I do want claude and codex specific TESTS, but not in our source code today").
  41. ci is no runner but a usage pattern: a session whose checkins names the branches, its program checking each check-in it is given in its own clone and recording a ci verdict on it as its run's user, from whom alone a ci verdict counts. The maintainer at the terminal, 2026-10-12: "Why is "ci" a special runner?", then "don't put into code what is just data." What the node's own checkout of each check-in attested, that a pass came from a checkout of exactly that check-in, goes with it.
  42. A run is written whole: its program and arguments in command, what it adds to its program's environment in env, and the host files it shares, such as an agent's sign-in, in homes. The runner field and the runner pages sandbox/NAME are removed, so a node reads nothing but the run to start its program, and started names no page. A pattern, by convention the wiki page run/NAME, holds such fields as defaults for create; of the served repository's own wiki page, create reads only the newest version that a user holding admin or setup sent, since a pattern names the program a node runs and the host files it binds. A program's environment is HOME, its workspace, USER, the run's user, and PATH, the host's system programs with the program's directory first when it is named by its path, the run's env over the last two, and nothing else. The maintainer, on the forum, 2026-10-13 (c6e8607e39), of patterns: "the wiki was just supposed to provide defaults to be overridden. The OCX message itself should be written fully expanded to make it as clear as possible"; of the environment: "Each variable should be strictly monitored, but I think a few are actually necessary, like PATH, HOME and maybe USER, no?", and at the terminal the same day, that "the blanket statement of clearing the environment was not giving proper consideration", without naming which variables to keep; the three above are the agent's choice. This amends decision 40: OCX's code still knows no agent, and how an agent is run is data, now in the run itself.
  43. A node on a host other than the server's, such as a build machine or a lab board, is OCX's node tool run on that host's clone. Each time it runs, it pulls and acts on the runs and stops among what the pull brought, as the server's node acts on what its hook is given (decision 39), and with --check on every run for it, as at its start; this replaces decision 39's backoffice run after each sync. It learns who sent each artifact from the server's receipt tool, signed in as its node user through Fossil's own login page (a POST to /login, whose cookie signs later requests in), and the tool's answer now carries each artifact's row number, which orders the artifacts of one receipt, so the clone sees the server's order. A run's program signs in as its run user with a password the node's file of passwords holds, readable by the node's account alone, since only the server's node can set a password on the server, and a node user holds neither admin nor setup there (decision 38). A run user works for one node, the node of the first run that an admin or setup sent naming it, so the server's node never resets a password another node holds; every node refuses a run whose user works for another. Each report a node on a clone writes it pushes at once, and goes on only when the server has received it from the node user, so started reaches the server before a launch. A clone records what it pulls with the server's address (Fossil 2.27, tried 2026-10-13), so a node's own reports are still known by their receipts' missing address. The maintainer, at the terminal on 2026-10-13: the reason for the thorough review of the OCX message definition was to add the build machine and lab boards as nodes; on the forum the same day (c6e8607e39), of the receipt service: "As long as you like the design, I guess I'm good with it." The maintainer also questioned naming a node by a Fossil user (c6e8607e39, A.2); the answer given (fc718dc03d) is that the user a receipt names is the only sender Fossil proves, and it stands until the maintainer decides otherwise. This answers items 1 and 2 of docs/review-v1.md's protocol questions.
  44. Protocol v1 is written as tables, and the tables are the standard: docs/protocol-v1.md, with docs/protocol-v1-fossil.md for what it rests on (Fossil as the medium, finding a message, who sent an artifact, verdicts, nodes, tools and versions). A run is built in layers a node processes outer to inner: workspace, a list of steps; sandbox, every field required; limits; and process, holding the command, its environment, manual, the subscriptions, deliveries (feed or start), terminal and keep. A string names something the node knows as $$name$$, every other character literal, and started records each value; the node adds nothing silently. The maintainer at the terminal, 2026-10-13: "If we think about the JSON structure like a network packet, our life might get simpler"; "Let's not allow any silent adds"; "Why not just something like $$VAR$$"; "the terminology in 13 seems mostly fine to me"; and "yes to draft being promoted". Of moving env to the process layer and the budget to the limits layer, out of the sandbox object of 62e45fcde6: "my previous sandbox object approval was just tentative as it looked reasonable. getting it implementable and at the right layer is more important." The draft was reviewed by a fresh reader and a spec-only implementer (docs/review-v1-tables.md), and by the battery, tests 20 and 21 (docs/battery/defs, batch 6). The code still follows the definition as it stood at a38dbeafca, though its comments now cite the new sections; docs/protocol-v1-limits.md and docs/protocol-v1-sessions.md are kept, marked superseded, until it follows the tables. This amends decision 42's fields.
  45. A run's limits layer has files, the largest file a process may write, a size, enforced by a shell's ulimit -f and ended budget by SIGXFSZ. OCX's own jobs in a sandbox, an import's git and fossil, are tasks: their sandbox and limits are written as a run's sandbox and limits layers, as data (src/ocx/tasks.cr), and planned and started by the code that starts a run's process, so bubblewrap's arguments are built in one place from generic fields that another implementation could read as well. An import keeps its limits on CPU, wall clock and its stream's size, and loses its memory cap, ulimit -v, which capped address space and not memory in use, until a node enforces memory with a cgroup, as for a run. The maintainer at the terminal, 2026-10-14: "i hope we have the pattern of calling bwrap in exactly one place and making the calls take the generic arguments that could be used by our own implementation. so, will you modify the custom bwrap environments used for these tasks to use the same implementation, but with specific data tables?", and of adding files: "yes to files". Since a5402d7f33 the code follows the tables, which amends the last sentence of decision 44.
  46. Protocol v1 is wrapped up as stable. docs/protocol-v1.md opens with what it is for, each problem it solves tied to the README virtue it serves, and its section 15 says what may be added within version 1 and what never changes; docs/protocol-v1-fossil.md's versions section now points there. A run with a key version 1 does not define, anywhere in it, is refused naming the key, where before only its workspace, sandbox and limits were and an unknown process key was ignored, so a newer sender's addition is never silently dropped by an older node; a report or stop with an unknown key is still read. The delivery guarantees move into section 9, and docs/protocol-v1-limits.md and docs/protocol-v1-sessions.md, superseded since decision 44, are removed: what a run may write in Fossil (no_password, branch, own_thread) was left out of the tables and stays out. The failures page follows the tables, its case numbers kept for the specs that cite them; the review and slice pages are marked as records; ARCHITECTURE.md places protocol v1 among OCX's layers, local models and their native agent among them, each pointing to where it is defined, so each part's rules are edited in one place. The maintainer at the terminal, 2026-10-14, in KEEP.md's words.
  47. Each topic is written in one place. knowledge-map.json names every document and data file of the tree once, with the question it answers and the topics it alone holds, and docs/knowledge-map.md is generated from it; README.md links the map instead of keeping its own table of documents, and AGENTS.md sends an agent to KEEP.md first and then to the map. A new precept, delineation, holds the map to the tree, every document reached from README.md by links, and every document named in another linked to it (spec/guards/delineation_spec.cr). The battery's records are an archive, kept as written, only its index held to this. Two design files that describe the design before protocol v1, docs/design/events.json and docs/design/sessions.json, are marked stale in the map until the maintainer decides what becomes of them. The maintainer at the terminal, 2026-10-14, in KEEP.md's words.
  48. Test records live outside the tree. The battery of uninitiated readers, its method, findings, every round's prompts, definitions, answers and transcripts, and the harness that ran them, is removed from the tree and read as it stood at check-in f68b57bd52 (the battery), linked from the knowledge map's records kept elsewhere; a new test record is a Fossil tech-note, linked from there. It stays the evidence behind protocol v1's words (decision 44). The maintainer at the terminal, 2026-10-14, in KEEP.md's words.
  49. What no longer describes OCX leaves the tree. docs/design/events.json, the registry of what starts each behavior, repeated the survey's events (docs/survey/functionality.json), and the causation precept now reads the survey, whose schema allows a person, a request, a hook, a session or the host as a cause, never a timer of OCX's own; docs/design/sessions.json and the schemas of state, session and workspace definitions described the design before protocol v1, and go with the guard that held them. AGENTS.md says how to work in a run, points a workspace the ocx release made to its earlier text, and sends an invited agent to the invite page. The maintainer at the terminal, 2026-10-14: "continue clean-up".
  50. PLAN.md is rewritten on protocol v1. It keeps the objective, now naming local models whose lower reasoning OCX tolerates, the precepts and the working rules; says where each function stands as built, pattern, missing, planned or to evaluate; says how each kind of agent works through runs, the native agent for local models and an agent's MCP surface marked as designs to settle with the maintainer, and agents that cannot hold a key, through their providers' MCP tunnels, as the next to design; and orders the phases as the maintainer did on 2026-10-14. What decisions 29 and 39 to 44 replaced goes: work units, the daemon, grants, bindings and the node-sync section, whose hook lesson docs/fossil.md keeps. The maintainer at the terminal, 2026-10-14: "get it done! Yes, rewrite plan.md now."
  51. A run's process may read the release its node runs, never write it: $$release$$ may be named in a sandbox's read_only alone, where before any of read_only, read_write and homes let it through the check that keeps a run off the node's own files, so a run could have rewritten the programs that confine it. The kernel enforces a read-only bind, so the check holds what it says; it is as good as the node's list of its own files. ARCHITECTURE.md and PLAN.md tell a stable definition from a complete implementation: the node builds all of protocol v1 but terminal. Codex's review of d8960f1251, passed on by the maintainer at the terminal, 2026-10-14.
  52. create is practical from the web page: only the run's objective is required; without a title, post or ticket the run opens a new thread the objective titles; without a node, in the pattern, the fields or the input, it goes to this host's node; and without a user, create makes one for it holding gio24, clone, read code, check in, read the forum and post there unmoderated, its password random and unshown. Not p: the node sets the run user's password itself, and a user who could change its own would change it out from under the node; not v, which grants whatever the repository gives developers. A pattern is a wiki page of the served repository by its name, or a URL. The page marks each field required or optional and, after a POST, holds what was submitted. The maintainer at the terminal, 2026-10-14, from use on the cleave project: "If I don't give "title", one should be made so that the default is a new forum thread. If I don't give "node", the CGI node should be used. If I don't give "user", a new account with minimal permissions ("pv4"?) should be used and generated"; "A URL is a URL. Something not a URL is not a URL"; "The required fields vs. optional fields are not clearly indicated on the form"; "The POST result page doesn't populate the previously submitted field contents."
  53. An edit of a post holding an OCX message is a new message, asking again, named by the edit's own hash; the request it edits stands until it is stopped. This is the maintainer's direction from their review of 2026-10-05 (10e85df270: "an artifact never changes, so an edit is a new OCX Record asking again"), which 7c019867e3, an agent's check-in, reversed without their word, making an edit ignored. The maintainer at the terminal, 2026-10-14, after an edited run on cleave did nothing: "I didn't make the check-in that reversed it", and "changing the design isn't the same thing as getting me aligned with the direction."