Design: AI-native agent workflows (refs #64) b277870b0749
- Author
- Andy McCall @andymccall <[email protected]>
- When
- · 2026-10-03 20:10 UTC
- Signature
- ✔ signed by Andy McCall
- Hash
b277870b074948c7e28655381786d2197c59b152f632e6bb56c595a56f75e40b- Depends on
- ff0af1ee299d
- Depended on by
- 5cde7882d767 ff1a64f81c1c 7ba155f20aa0
- In bookmarks
- agents-in-readme bare-hashes carried-not-removed carry-identical doctor-trust identical-sides keyless-tags main merge-remote-bookmark only-help-103 paths-for-resolutions-and-amend push-notes show-stat subrepo-pin-state switch-says
- In tags
- v0.10.0 v0.11.0 v0.4.0 v0.4.1 v0.4.2 v0.4.3 v0.4.4 v0.4.5 v0.4.6 v0.5.0 v0.5.1 v0.6.0 v0.7.0 v0.8.0 v0.9.0
- Edits
- 1 atom, 1 tree operation, 1 file
Browse the tree at this change
added docs/ai_native_agent_workflows.md +228 −0
| 1 | + | # Oxygen (`oxy`): AI-Native Agent Workflows Specification |
|
| 2 | + | ||
| 3 | + | | | | |
|
| 4 | + | |---|---| |
|
| 5 | + | | **Status** | Draft 1.1 | |
|
| 6 | + | | **Date** | 2026-10-03 | |
|
| 7 | + | | **Audience** | Implementers and AI tooling developers | |
|
| 8 | + | | **Depends on** | spec.md §6 (changes), §9 (conflicts), §12 (operation log, workspaces), §14 (identity, policy), revsets (`revset_query_language.md`) | |
|
| 9 | + | ||
| 10 | + | ## 1. Overview and philosophy |
|
| 11 | + | ||
| 12 | + | Coding agents, such as Aider or Claude Code, or local LLM loops, commit |
|
| 13 | + | at machine speed. A version control system must let them work without |
|
| 14 | + | giving them the keys to the kingdom, and without burying the human's |
|
| 15 | + | history in micro-changes. |
|
| 16 | + | ||
| 17 | + | The guiding principle is **delegated, bounded, reversible autonomy**: |
|
| 18 | + | ||
| 19 | + | - **Delegated:** an agent acts under its human owner's identity, with its |
|
| 20 | + | own key, so every change it makes is attributable to both. |
|
| 21 | + | - **Bounded:** an agent can record changes but cannot move protected |
|
| 22 | + | bookmarks, approve, or seal, whatever its owner may do. |
|
| 23 | + | - **Reversible:** an agent works in its own workspace and bookmark, so |
|
| 24 | + | discarding its session never touches the human's work. |
|
| 25 | + | ||
| 26 | + | None of this weakens what Oxygen already guarantees. The change graph is |
|
| 27 | + | immutable, every change is signed with Ed25519 and ML-DSA-65, policy is |
|
| 28 | + | verified on fetch and push, and the operation log records everything. |
|
| 29 | + | ||
| 30 | + | Each section says what **exists** today and what is **new**. |
|
| 31 | + | ||
| 32 | + | ## 2. Agent identity and delegation |
|
| 33 | + | ||
| 34 | + | **Exists (§14.2):** an identity object has `delegates [8]: [KeyId]`. |
|
| 35 | + | These are keys allowed to sign or seal changes whose `author` is that |
|
| 36 | + | identity. Delegation is one level deep and not transitive, and |
|
| 37 | + | `oxy identity delegate add|remove` manages it. Any change to an identity |
|
| 38 | + | is a rotation: a successor object. |
|
| 39 | + | ||
| 40 | + | - **The agent's own key pair.** An agent generates its own Ed25519 and |
|
| 41 | + | ML-DSA-65 key pair locally. Its identity object's `name` says what it |
|
| 42 | + | is, for example `"aider 0.x on andy-laptop"`. An agent never holds the |
|
| 43 | + | human's secret keys. |
|
| 44 | + | - **Authorship.** Changes the agent records set `author` to the human's |
|
| 45 | + | `KeyId` and are signed with the agent's key. The signature's KeyId |
|
| 46 | + | identifies the agent. **No marker is stored in the change:** `extra |
|
| 47 | + | [9]` is reserved and must stay empty, and the signature already proves |
|
| 48 | + | which agent made the change, which a marker could not. |
|
| 49 | + | ||
| 50 | + | **New: scoped delegation.** Today a delegate moves references as far as |
|
| 51 | + | its delegator may (§14.5). That is right for a hub signing browser edits, |
|
| 52 | + | and wrong for an agent. `delegates` becomes a list of entries: |
|
| 53 | + | ||
| 54 | + | ``` |
|
| 55 | + | delegates [8]: [{ key [0]: KeyId, scope [1]: ["changes" | "refs" | "seal"], expires [2]: u64? }] |
|
| 56 | + | ``` |
|
| 57 | + | ||
| 58 | + | - An agent is added with `--scope changes`. Its signature authenticates |
|
| 59 | + | changes, but a reference or tag attestation, or a seal, signed by it is |
|
| 60 | + | refused. **An agent can never land on a protected bookmark**, even |
|
| 61 | + | when its owner could. |
|
| 62 | + | - A per-delegate `expires` limits an agent to a session or a day |
|
| 63 | + | (`--expires 8h`), without rotating the human's own expiry. |
|
| 64 | + | - Hosts that sign for users keep the current behaviour with |
|
| 65 | + | `--scope changes,refs`. |
|
| 66 | + | - This is a format change to the identity object. That is acceptable |
|
| 67 | + | before 1.0. |
|
| 68 | + | ||
| 69 | + | **New: revocation by the delegator.** Today only the revoked key itself |
|
| 70 | + | or a policy root key may sign `revoke`. An agent's key may be lost on a |
|
| 71 | + | compromised machine, and the policy root is often someone else, so the |
|
| 72 | + | identity that delegated a key may also revoke it. Removing a delegate in |
|
| 73 | + | a successor identity stops future use. Revoking it also marks the changes |
|
| 74 | + | the agent already signed as *valid but revoked* in `oxy verify` and on |
|
| 75 | + | the hub, so they get a second look. |
|
| 76 | + | ||
| 77 | + | ## 3. Isolation: one workspace and bookmark per session |
|
| 78 | + | ||
| 79 | + | **Exists:** `oxy workspace add` creates an extra checkout that shares the |
|
| 80 | + | repository, each with its own current bookmark. |
|
| 81 | + | ||
| 82 | + | **New:** `oxy agent start NAME` does three things: |
|
| 83 | + | 1. creates a workspace under `.oxy/agents/NAME/`; |
|
| 84 | + | 2. creates the bookmark `agents/NAME/<session>` from the human's current |
|
| 85 | + | heads; |
|
| 86 | + | 3. records a session operation carrying the agent's KeyId. |
|
| 87 | + | ||
| 88 | + | The agent works only there. This replaces a session marker in the |
|
| 89 | + | human's operation log: |
|
| 90 | + | ||
| 91 | + | - **The human's working copy is never touched.** Changes commute, so the |
|
| 92 | + | human keeps working on the same files at the same time, and merging |
|
| 93 | + | the agent's bookmark later is an ordinary `oxy merge`. |
|
| 94 | + | - **Discarding a session** is `oxy agent drop NAME`: delete the |
|
| 95 | + | bookmark and the workspace. Nothing the human did is undone, unlike an |
|
| 96 | + | undo in a shared workspace would. |
|
| 97 | + | - **Undo within a session** is the agent's own operation log (§12), |
|
| 98 | + | scoped to its workspace. The new `oxy undo --to OP` returns to any |
|
| 99 | + | earlier operation of that workspace. |
|
| 100 | + | ||
| 101 | + | ## 4. Micro-changes: keep them, show them folded |
|
| 102 | + | ||
| 103 | + | Agents produce many small changes. Oxygen keeps them, because each is |
|
| 104 | + | signed, cheap, and commutes with everything that does not touch the same |
|
| 105 | + | lines. The noise is a display problem first. |
|
| 106 | + | ||
| 107 | + | - **New, display folding:** `oxy log` shows a run of consecutive changes |
|
| 108 | + | signed by the same agent key as one line: "aider: 37 changes, 4 |
|
| 109 | + | files". `--expand` shows them all. The hub does the same. |
|
| 110 | + | - **New, adoption:** when the human wants one change in history, |
|
| 111 | + | `oxy fold -r REVSET` folds the selected changes into one new change. |
|
| 112 | + | It uses the revset language, for example |
|
| 113 | + | `oxy fold -r 'signed_by(aider) & main..agents/aider/s1'`. The folded |
|
| 114 | + | change is authored and signed by the human's own key. It records the |
|
| 115 | + | folded changes' hashes in its description footer, so the trail to the |
|
| 116 | + | agent's work stays verifiable while those changes remain stored. |
|
| 117 | + | The existing `oxy squash` folds one change into a dependency and stays |
|
| 118 | + | as it is. |
|
| 119 | + | - **Folding is optional.** Unfolded agent changes stay valid history. |
|
| 120 | + | Folding is for when a team's convention wants one reviewed change. |
|
| 121 | + | ||
| 122 | + | ## 5. Conflicts as data, for agents |
|
| 123 | + | ||
| 124 | + | **Exists:** conflicts are recorded in states, not raised as errors (§9). |
|
| 125 | + | A conflicted state can be committed and built on, and `oxy resolve` |
|
| 126 | + | reports which conflicts the current files resolve. |
|
| 127 | + | ||
| 128 | + | - **Reading conflicts:** `oxy status --json` lists each conflict: path, |
|
| 129 | + | node, kind (order, name or tree), and the contributing ChangeIds. |
|
| 130 | + | `oxy cat PATH --at CHANGE` gives each side's text for the agent's |
|
| 131 | + | context. |
|
| 132 | + | - **Resolving:** the agent writes the resolved files and runs |
|
| 133 | + | `oxy commit`. **Oxy computes the resolution's dependencies**: a |
|
| 134 | + | resolution must depend on every change that contributed an atom to |
|
| 135 | + | the conflict. An agent never writes `deps` by hand. Correctness of the |
|
| 136 | + | graph is Oxygen's job, not the model's. |
|
| 137 | + | - **A valid resolution is not necessarily a right one.** The graph will |
|
| 138 | + | be well-formed; the code may still be wrong. A policy rule for |
|
| 139 | + | protected bookmarks can require that a resolution signed by an agent |
|
| 140 | + | has a passing Flow receipt and a human approval before it lands. |
|
| 141 | + | ||
| 142 | + | ## 6. Review and policy on the hub |
|
| 143 | + | ||
| 144 | + | - **Badges:** changes signed by a delegate with `changes` scope show |
|
| 145 | + | "agent: NAME on behalf of HUMAN" on the hub and in `oxy log`. |
|
| 146 | + | - **Approvals:** approvals count only signatures by keys that are not |
|
| 147 | + | agent-scoped delegates, so an agent cannot approve its own work or |
|
| 148 | + | anyone else's. |
|
| 149 | + | - **Policy:** a policy rule may name agent rules, for example "agents may |
|
| 150 | + | push `agents/**` bookmarks only" or "an agent-signed change needs a |
|
| 151 | + | passing receipt to land". |
|
| 152 | + | - **Audit:** the trust page and `oxy verify` list agent-signed changes |
|
| 153 | + | separately, with the delegation that authorized each. |
|
| 154 | + | ||
| 155 | + | ## 6a. Optional: a human always lands AI work |
|
| 156 | + | ||
| 157 | + | Whether a human must land every AI-authored change is a **per-project |
|
| 158 | + | choice**. A regulated codebase may insist on it; a personal project or a |
|
| 159 | + | team that trusts its agents and tests may not. Oxygen's job is to make |
|
| 160 | + | the gate easy to turn on and impossible to bypass when it is on. It must |
|
| 161 | + | never impose the gate on everyone. |
|
| 162 | + | ||
| 163 | + | **With scoped delegation (this draft).** The agent is your delegate |
|
| 164 | + | with `--scope changes`, so its changes carry your authorship and its |
|
| 165 | + | signature. The policy decides whether it can land: |
|
| 166 | + | ||
| 167 | + | ``` |
|
| 168 | + | rules: [ |
|
| 169 | + | { pattern: "main", keys: [andy, sam], threshold: 1, require: "signed" }, |
|
| 170 | + | { pattern: "release/*", keys: [andy, sam], threshold: 2, require: "signed" }, |
|
| 171 | + | { pattern: "agents/**", keys: [andy, sam], threshold: 1 }, |
|
| 172 | + | ] |
|
| 173 | + | ``` |
|
| 174 | + | ||
| 175 | + | - **Gate on:** an agent-scoped delegate can never sign a reference |
|
| 176 | + | attestation, so only Andy or Sam can move `main`. Approvals count only |
|
| 177 | + | keys that are not agent-scoped, so a human approved and a human landed. |
|
| 178 | + | The agent's changes keep their own signatures, so the landed history |
|
| 179 | + | still shows which agent wrote what. |
|
| 180 | + | - **Gate off:** delegate the agent with `--scope changes,refs` instead. |
|
| 181 | + | It then moves references as far as its owner may, and can land on its |
|
| 182 | + | own where the policy allows. The project chooses this per agent, and |
|
| 183 | + | the trust page and `oxy verify` still show every agent-signed change and |
|
| 184 | + | every agent-signed bookmark move. |
|
| 185 | + | - **Per bookmark:** the usual setup gates `main` and `release/*` and |
|
| 186 | + | leaves `agents/**` open, so agents push and move their own bookmarks |
|
| 187 | + | freely while a human lands everything else. That needs refs scope |
|
| 188 | + | that reaches only the open rules: a policy rule field naming agents |
|
| 189 | + | explicitly, which is part of the §14.5 change. |
|
| 190 | + | ||
| 191 | + | **With today's spec (no scoped delegation).** A delegate moves |
|
| 192 | + | references as far as its owner, so the gate needs a different setup: |
|
| 193 | + | 1. Give the agent its **own identity**, not a delegate. |
|
| 194 | + | 2. List only human keys in the `main` rule, and the agent's key in an |
|
| 195 | + | `agents/**` rule. |
|
| 196 | + | 3. Policy checks each change a bookmark move adds, so the agent's changes |
|
| 197 | + | cannot reach `main` directly at all. A human adopts the work by folding |
|
| 198 | + | or re-committing it under their own key. |
|
| 199 | + | ||
| 200 | + | This gate is strict and works now. The cost is that the landed history |
|
| 201 | + | records the human as signer, not the agent. |
|
| 202 | + | ||
| 203 | + | **On the hub: agent-scoped tokens.** Policy governs keys, but landing on |
|
| 204 | + | the hub is done with an account's token. An agent using a human's token |
|
| 205 | + | lands *as that human*, and no policy can tell. The hub therefore needs |
|
| 206 | + | **agent tokens**: |
|
| 207 | + | - tied to an agent key and its human owner; |
|
| 208 | + | - allowed to push `agents/**`, open and update proposals, and comment; |
|
| 209 | + | - refused for landing, approving, changing settings or policy, and |
|
| 210 | + | creating tokens, whatever the owner may do. |
|
| 211 | + | ||
| 212 | + | Hub actions taken with an agent token are recorded as "AGENT on behalf of |
|
| 213 | + | HUMAN" in the audit log and on the proposal. A project with the gate off |
|
| 214 | + | may still let agent tokens land, as a repository setting that mirrors the |
|
| 215 | + | policy, never by default. |
|
| 216 | + | ||
| 217 | + | ## 7. Summary of new work |
|
| 218 | + | ||
| 219 | + | | Item | Spec section to change | |
|
| 220 | + | |---|---| |
|
| 221 | + | | Scoped, expiring delegates | §14.2 identity object, §14.5 policy | |
|
| 222 | + | | Revocation by the delegator | §14.2 | |
|
| 223 | + | | `oxy agent start` / `drop`, session operation | §12, CLI | |
|
| 224 | + | | `oxy undo --to OP` | §12, CLI | |
|
| 225 | + | | Display folding, `oxy fold -r` | CLI, hub | |
|
| 226 | + | | Agent-aware approvals and policy rules, optional human gate (§6a) | §14.5, hub spec | |
|
| 227 | + | | Agent-scoped hub tokens | hub spec (API tokens) | |
|
| 228 | + | | `oxy status --json` conflict listing (check what exists) | §9, CLI | |