Triage the backlog and assess the plugin model

029ccafbbc63 · AtlantisPleb · · parent cb4d5cc1beb1

Triage the backlog and assess the plugin model

Record the 2026-08-24 triage pass (17 issues closed as not planned on
openagents.com, openagents#13 closed as completed) and the initial
plugin model assessment: Rust reaches the TypeScript CLI as sandboxed
WASM plugins, discovery is semantic over typed manifests with zero
standing prompt cost, invocation is exact-name, runs land as tool.ran
thread events, and payments stay reserved fields. Foreign session
resume (#198) is the pilot.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GoYpb8FEmdxVErsv7ABCYi
Co-Authored-By
Claude Fable 5 <noreply@anthropic.com>

Deploy story

What this commit did to the running system — joined from the forge receipt chain, the part a commit page elsewhere cannot show.

pushed
by user · WAL seq 293 · 2026-08-24T19:07:37.309136Z

Changed files

  • added docs/2026-08-24-triage-and-plugin-model-assessment.md

Diff

1 file changed, +315 -0

docs/2026-08-24-triage-and-plugin-model-assessment.md added +315

@@ -0,0 +1,315 @@

1
# Backlog triage and the plugin model
2
3
Date: 2026-08-24
4
5
Status: initial assessment
6
7
This document records two things done together on 2026-08-24: a triage pass
8
over every open issue in `OpenAgentsInc/openagents.com` and
9
`OpenAgentsInc/openagents`, and an initial assessment of the plugin model —
10
how the coder loads capability it was not born with, how Rust code gets used
11
from the TypeScript CLI without a rewrite, and when a capability enters the
12
model's context. Sources: the open issue set as of this morning, episode
13
transcripts 270–275 plus the 2024 plugin-economy arc (episodes 048–102, 165),
14
`docs/2026-08-23-openagents-coder-cli-spec.md`,
15
`docs/2026-08-23-thread-primitive-audit.md`,
16
`docs/2026-08-24-coder-account-integration-audit.md`,
17
`docs/2026-08-23-agent-tools-zero-base.md`, and the Omega-era plugin tool
18
specification (`openagents/docs/omega-agent/2026-07-27-plugin-tool-spec.md`).
19
20
## 1. Summary
21
22
- **Triage.** 17 issues on `openagents.com` closed as not planned: the
23
  economy and payments cluster, the future fleet-and-verification governance
24
  program, and the Ox Alpha stress cluster. One monorepo issue closed as
25
  completed (#13, the named CLI command families, which shipped). The kept
26
  backlog is now dominated by the current push: coder thread persistence,
27
  forge integrity, and near-term product.
28
- **Rust from TypeScript: yes, and as WASM.** Where a tool already exists as
29
  a well-formed Rust crate (the #198 foreign-session scanners are the model
30
  case), compile it to a sandboxed WASM plugin rather than reimplementing it
31
  in TypeScript or binding it natively. The sandbox is not overhead; it is
32
  the product. It makes the approval ladder enforceable, the artifact
33
  portable and digest-addressable, and the plugin the future marketplace
34
  unit.
35
- **Loading discipline.** A plugin is installed, indexed, and dormant by
36
  default. Discovery is semantic (an embedding match over typed manifests,
37
  never keyword routing); invocation is by exact name from the installed
38
  catalog; nothing enters the standing system prompt. This is the zero-base
39
  tool lesson and the Blueprint selection law applied to plugins.
40
- **Payments stay deferred.** Per-use pricing, usage royalties, and
41
  settlement are reserved fields in the manifest, not build targets. The
42
  transcript record itself gives us usage counters for free the day
43
  settlement resumes.
44
45
## 2. Triage record
46
47
### 2.1 Closed as not planned on `openagents.com`
48
49
The current push is the coder thread and persistence model and the plugin
50
model. Episodes 270–275 also defer payments explicitly ("It's free. For
51
now… We'll do open source ones for free as long as we can", episode 274).
52
Each close carries a comment pointing back to this document.
53
54
| Cluster | Issues | Reason |
55
| --- | --- | --- |
56
| Economy and payments | #78 (sats bounties), #83 (outcomes per kWh), #84 (trace licensing), #90 (skill registry with usage counters), #91 (revenue share for paid skills) | The payments lane is deferred. The non-economic half of #90 — a typed, digest-pinned registry of capabilities — is carried forward by section 4 of this document and will produce its own issues. |
57
| Fleet and verification governance | #67 (coverage manifests), #68 (UX behavior contracts), #69 (receipts on issue timelines), #71 (release notes from receipts), #72 (QA fleet), #74 (between-turn guidance), #75 (FastFollow backlog refill) | A future program layered on receipts and fleets that do not exist yet. #10 remains open as the umbrella for issue-to-receipt linkage. |
58
| Executor standardization | #73 (ACP as the executor contract) | Deferred as written, but the boundary question returns inside the plugin model (section 4.5). |
59
| Ox Alpha stress program | #41 (parallel orchestrator), #42 (aim agents at backlog), #45 (findings), #56 (provider overflow routing) | The free-window stress program is not the current push. Delegation-driven backlog work continues as `OpenAgentsInc/openagents#22`. |
60
61
### 2.2 Closed as completed
62
63
| Issue | Evidence |
64
| --- | --- |
65
| `openagents#13` (named issue and project CLI commands) | Shipped on monorepo `main` (`b93309390b`) and live in the published CLI; verified against production during this triage. |
66
67
### 2.3 Kept open, by lane
68
69
- **Coder and threads:** `openagents.com` #132 (coder epic), #164 (thread
70
  turns show no reasoning, no tools), #160 (silent model substitution),
71
  #198 (foreign session resume — the plugin pilot, section 5);
72
  `openagents` #20 (scoped push credential), #22 (backlog delegation).
73
- **Forge integrity:** #151, #166, #178–#193, #197, #195. These are
74
  correctness and exit-honesty issues; deferring them would let the forge
75
  drift from its own claims.
76
- **Work system and product:** #2, #9, #10, #23, #77, #115, #141.
77
- **Cloud computer platform:** `openagents.com` #37–#38 and `openagents`
78
  #7–#11 stay open. This is a deliberate non-decision: the lane is two days
79
  old and feeds delegation, but it is not the current push. If it should
80
  pause too, close the project in one pass.
81
82
### 2.4 Flag
83
84
`openagents#19` reports that the pre-push ACP conformance gate fails closed
85
on clean `origin/main`, so nothing can be pushed to monorepo `main`. Every
86
coder and plugin change lands in that repository. This is the most urgent
87
open issue in either tracker.
88
89
## 3. Where the current push stands
90
91
The server half of thread persistence is done; the client half is not.
92
93
**Done (server):** the `threads` table with budget, generation fence, and
94
status; append-only `thread_events` as the authoritative transcript
95
(THREAD-001: a grant names a thread or a conversation, never both);
96
transcript routes `GET`/`POST /api/v3/threads/{id}/events` with an `:after`
97
cursor; the payload ceiling lifted so reasoning is recorded whole
98
(`cb4d5cc`). The decided event vocabulary is `turn.user`, `turn.reasoning`,
99
`tool.ran` (call and bounded result as one event), and `turn.assistant`.
100
101
**Open (client and joins):**
102
103
1. The CLI never posts to `thread_events`. `coder-thread.ts` opens and
104
   revokes threads but keeps its transcript in memory; on exit it is gone.
105
   The server copy is decided to be the only copy — the earlier local-JSONL
106
   plan is superseded.
107
2. No `--resume`. The Codex-style shape is decided (`--resume` picker
108
   filtered to the repository, `--resume <id>`, `--resume --last`) and
109
   unbuilt.
110
3. Thread spend does not reach the leaderboard (missing third union arm over
111
   `Inference.Grant.usage`), and the memory planes still hang off the
112
   conversation, not threads.
113
114
Plugin work lands inside this model, not beside it: a plugin run is a
115
`tool.ran` event on the thread transcript, carrying the plugin's digest.
116
That single decision is what lets usage counters, receipts, and eventual
117
settlement come later without a second record.
118
119
## 4. The plugin model
120
121
### 4.1 What history already settled
122
123
This is the second time OpenAgents builds this. The 2024 arc (episodes
124
048–102) ran a complete plugin economy — Extism-hosted WASM plugins,
125
per-use sats pricing set by the author, allowed-hosts declarations, a
126
community Nostr registry proposal (episode 066), and an agent store with
127
daily Bitcoin revenue sharing (episode 092). It failed on demand, not
128
supply: "we didn't really have the use case for which people were willing
129
to actually pay" (episode 165). The Omega plugin tool specification
130
(2026-07-27) already distilled the surviving laws, and this assessment
131
adopts them rather than restating them:
132
133
1. Plugins are WASM in a sandbox, not code in the host process.
134
2. A plugin declares typed input and output schemas, and the boundary
135
   validates both (the DSE/DSPy signature lineage).
136
3. An artifact is immutable and content-addressed; a stable digest names
137
   exactly what ran.
138
4. Plugin runs are decision evidence, not write authority.
139
5. No keyword routing: invocation is an exact name from the installed
140
   catalog.
141
6. A better version is a candidate until an explicit install pins it.
142
143
What is new since 2024: the coder exists, threads give every run a durable
144
transcript, and the forge gives plugins a home with receipts. The buyer
145
this time is the coder itself.
146
147
### 4.2 Rust from TypeScript: WASM, not bindings
148
149
Three ways to reach a Rust crate from the Effect TS CLI:
150
151
| Path | Verdict | Why |
152
| --- | --- | --- |
153
| WASM plugin | **Adopt** | One artifact for every platform and every host (Node CLI, BEAM server, browser). Sandboxed by construction: filesystem access is an explicit read-only mount, network access is an explicit host allowlist, so a plugin's declared capabilities are enforced, not trusted. Dynamically loadable, digest-addressable, and identical to the future marketplace unit. |
154
| napi-rs native addon | Reject for plugins | In-process with full ambient authority, per-platform prebuilds, no dynamic-load story, nothing enforceable to price or approve. Acceptable someday for a first-party hot path; none exists today. |
155
| Rust sidecar process | Reject | A second binary to distribute and supervise per platform; the coder CLI deliberately ships as one npm install. |
156
157
The precedent inside the codebase points the same way: the coder CLI spec
158
records that the `probe` runtime already ships a checked-in synchronous-ABI
159
WASM build precisely so consuming it is an `npm install`.
160
161
**Runtime recommendation: start with Extism.** Extism has first-class SDKs
162
for both hosts we own today — Node for the CLI and Elixir for the Phoenix
163
server — plus PDKs for authoring plugins from Rust with minimal ceremony,
164
and it supports WASI with `allowed_paths` (read-only mounts) and
165
`allowed_hosts`, which are exactly the 2024 upload form's fields and exactly
166
the #198 security constraints. The WebAssembly component model with WIT is
167
the better long-term ABI (real typed interfaces instead of bytes-plus-schema
168
convention), but its Elixir host story is still experimental. Track it;
169
do not wait for it. The typed boundary lives in the manifest schema either
170
way, so the ABI can migrate under a stable contract.
171
172
### 4.3 The manifest
173
174
Every plugin carries a manifest, and the manifest is the unit the registry
175
indexes, the selector embeds, and the approval ladder reads:
176
177
- **Identity:** name, semantic version, content digest of the WASM
178
  artifact, author.
179
- **Interface:** typed input and output schemas (JSON Schema on the wire,
180
  Effect Schema in the CLI), validated on both sides of every call.
181
- **Capabilities:** requested read-only path mounts, requested host
182
  allowlist, memory and time bounds. Absence means denial.
183
- **Discovery:** a description written for semantic matching — what it
184
  does, when to use it, and when not to (the zero-base re-admission
185
  criteria applied to third parties).
186
- **Surfaces:** slash commands the plugin contributes (`/resume`), and the
187
  tools it materializes when loaded.
188
- **Reserved, not implemented:** price per use in sats, license terms.
189
  These fields exist so the economy lane can resume without a schema
190
  migration, and stay empty until it does.
191
192
### 4.4 When a plugin enters context
193
194
The zero-base audit measured the cost of ignoring this: 57 percent of a
195
selection's tool-definition bytes went to tools that could not run. The
196
plugin model must not rebuild that. Three tiers:
197
198
1. **Core, always loaded.** The coder's built-in tools (today: `shell`,
199
   `delegate`, `skill`, `openagents`) plus one `capability` discovery tool.
200
   The standing prompt grows by one tool, ever.
201
2. **Installed, dormant.** An installed plugin is digest-pinned in a local
202
   catalog and indexed for semantic search. It costs zero prompt bytes. Its
203
   slash commands work immediately (a slash command is user-invoked and
204
   needs no model awareness). The model reaches it only through the
205
   `capability` tool: the request is embedded and matched against manifest
206
   descriptions — the workspace's semantic-routing invariant, and the same
207
   mechanism episode 102 shipped in 2024 ("based on a combination of chat
208
   context, plugin metadata, and input descriptions"). The tool returns
209
   candidate names; the model then invokes by exact name, satisfying the
210
   no-keyword-routing law. On selection, the plugin's tool definitions
211
   materialize for the remainder of the session only.
212
3. **Session-loaded.** The user can force a plugin in (`/plugin load`), and
213
   an agent proposal to load one rides the existing approval ladder.
214
215
The ladder gets sharper, not looser, because the sandbox makes declarations
216
enforceable: a plugin whose manifest requests no mounts and no hosts is
217
pure computation and can auto-run; read-only mounts inside the workspace or
218
the declared foreign roots are ask-once; any host access or anything
219
writable is ask-every-time. Approval attaches to the digest, so a version
220
bump re-asks.
221
222
This resolves the tension in the prompt that motivated this assessment: the
223
foreign-session-resume capability is *always there* (installed, indexed,
224
`/resume` works) and *never loaded* (zero standing prompt cost) until the
225
user asks for something it matches.
226
227
### 4.5 Relationship to skills, ACP, and the typed-program lineage
228
229
- **Skills versus plugins.** A skill (a `SKILL.md` under `.agents/skills/`)
230
  is instructions — it changes what the model knows. A plugin is
231
  capability — it changes what the model can do, deterministically, in a
232
  sandbox, with a receipt. The existing skill loader already proves the
233
  discovery pattern (catalog of names and descriptions, bodies on demand);
234
  the plugin catalog generalizes it. Keep the words separate per the
235
  taxonomy.
236
- **ACP.** Closing #73 defers ACP standardization across Work and SCV, but
237
  the boundary question it asked comes back here in a smaller form: the
238
  plugin ABI is the *function* contract (typed call, one result, a receipt)
239
  and ACP remains the *agent* contract (a session, turns, permission
240
  requests). `delegate` hands work to an agent; `plugin` calls a function.
241
  Do not blur them.
242
- **DSPy, DSE, Blueprint.** The manifest's typed interface is a signature
243
  in the DSE sense, and the Blueprint laws above are adopted wholesale.
244
  When optimization returns, the discovery layer is the natural place for
245
  it — which manifests get selected for which requests is a tunable,
246
  eval-scored policy — under the standing law that an optimizer output is a
247
  candidate, never a deployment.
248
- **Micropayments.** Deferred with the rest of the economy lane, by design
249
  rather than by omission: because every plugin run is a `tool.ran` thread
250
  event carrying a digest, usage attribution is already durable. Settlement
251
  (the closed #90/#91 territory) becomes a projection over records that
252
  will already exist, and the open-registry idea (episode 066's
253
  Nostr-signed listings) remains the preferred distribution shape when it
254
  resumes.
255
256
## 5. Pilot: foreign session resume as the first plugin
257
258
Issue #198 is the model case, and its body already states the preference
259
this assessment confirms: use the Rust crates. The `grok-build`
260
foreign-session scanners (bounded, read-only, `ApprovedRoot`-sandboxed
261
readers of `~/.claude` JSONL, `~/.codex` SQLite and zstd rollouts, and
262
Cursor state) are exactly the shape of code that should never be
263
reimplemented in TypeScript: parsing untrusted local state with bounded
264
reads is where Rust earns its keep and rewrites breed defects.
265
266
As a plugin: manifest requests read-only mounts of the three foreign roots
267
and nothing else — no hosts, no writes. Under the ladder that makes it
268
ask-once. It contributes `/resume` (a picker over recent sessions matching
269
the working directory) and a `foreign_sessions` tool the capability
270
selector surfaces when the user says "continue my Claude session." The
271
resumed conversation lands in a new thread whose transcript records the
272
import as events.
273
274
**Known risk to spike first:** SQLite and zstd inside `wasm32-wasip1`.
275
Both compile, but SQLite's VFS and file locking under WASI have friction.
276
Fallback that preserves the architecture: the host reads the raw bytes
277
through the same declared mounts and passes them in; the plugin keeps all
278
parsing. Decide in a one-day spike before committing the interface.
279
280
Second pilot candidate, deliberately trivial: wrap one pure function (for
281
example, the ATIF redaction pass) to prove the manifest, digest pinning,
282
and transcript receipt path with no filesystem story at all — the walking
283
skeleton before the real organ.
284
285
## 6. Proposed next issues
286
287
In order. The first three are the current push; the rest follow.
288
289
1. **Coder writes its transcript.** Post `thread_events` from the CLI turn
290
   loop (`turn.user`, `turn.reasoning`, `tool.ran`, `turn.assistant`);
291
   server copy is the only copy. Closes the client half of persistence.
292
2. **`openagents coder --resume`.** Picker over the account's threads
293
   filtered to the repository, plus `--last` and explicit id, replaying the
294
   transcript through the cursor.
295
3. **Fix the release gate freshness failure** (`openagents#19`) so 1 and 2
296
   can land.
297
4. **Plugin walking skeleton.** Extism host in the CLI, manifest schema,
298
   digest-pinned local catalog, one pure-function plugin, runs recorded as
299
   `tool.ran` events.
300
5. **Capability discovery tool.** The one standing `capability` tool with
301
   embedding-based manifest matching and exact-name invocation; approval
302
   ladder keyed to declared capabilities and digest.
303
6. **Foreign session resume as a plugin** (#198), starting with the
304
   SQLite-under-WASI spike.
305
7. **Leaderboard union arm** for thread grant usage, so coder work counts.
306
307
## 7. What this assessment does not decide
308
309
- Whether the cloud computer lane pauses with the rest of the deferred
310
  program (section 2.3) — owner call.
311
- The remote registry and its trust model (signed listings, review) — not
312
  needed until a plugin exists that anyone else wants.
313
- Component-model migration timing — revisit when the Elixir host story
314
  matures.
315
- Anything priced in sats.

This page updates live while a promote is in flight · changelog