OXYGENHUB
# 7ba155f20aa0 oxygen / docs / ai_native_agent_workflows.md
10.9 KiB · Markdown · last changed Scoped, expiring delegates, and revocation by the delegator 1 month ago renderedsource blame history raw
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
**Scoped delegation (§14.2, implemented 2026-10-04).** Before it, a
51
delegate moved references as far as its delegator may (§14.5). That is
52
right for a hub signing browser edits, and wrong for an agent. `delegates`
53
is a list of entries:
54
55
```
56
delegates [8]: [{ key [0]: KeyId, scope [1]: ["changes" | "refs" | "seal"], expires [2]: u64? }]
57
```
58
59
- An agent is added with `--scope changes`. Its signature authenticates
60
  changes, but a reference or tag attestation, or a seal, signed by it is
61
  refused. **An agent can never land on a protected bookmark**, even
62
  when its owner could.
63
- A per-delegate `expires` limits an agent to a session or a day
64
  (`--expires 8h`), without rotating the human's own expiry.
65
- Hosts that sign for users keep the current behaviour with
66
  `--scope changes,refs`.
67
- A bare KeyId in an older identity means every scope.
68
69
**Revocation by the delegator (implemented 2026-10-04).** Before it,
70
only the revoked key itself or a policy root key could 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 (done 2026-10-04) | §14.2 identity object, §14.4, §14.5 policy |
222
| Revocation by the delegator (done 2026-10-04) | §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 |