@wairon/cli 5.1.1-dev.107 → 5.1.1-dev.109

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,167 @@
1
+ # Teaching the connecting agent — the MCP entrypoint
2
+
3
+ > Status: 7.1–7.5 all shipped. Written against wairon 5.1.0.
4
+ > Source request: "Teaching the connecting agent: wairon needs the entrypoint,
5
+ > packs only adjust it" (2026-07-27).
6
+
7
+ ---
8
+
9
+ ## The governing principle
10
+
11
+ **wairon owns the SDD model, so wairon must teach it.** If an agent connecting to
12
+ a wairon MCP server does not know what SDD is, what the stereotypes mean, or in
13
+ what order to use the `sdd_*` tools, supplying that is wairon's default — not
14
+ each wrapper's. A pack appends its **platform delta** ("and here is what each of
15
+ those means in Make.com") and never restates the model, which would drift on
16
+ every wairon release.
17
+
18
+ Every item below is shaped by that split.
19
+
20
+ ---
21
+
22
+ ## Shipped
23
+
24
+ ### 7.1 — `instructions` on `initialize`
25
+
26
+ `createMcpServer` returns MCP `instructions`, the protocol's field for "how to
27
+ use this server", which clients inject into the agent's system prompt. Composed
28
+ by `instructions_specialist` (`src/core/instructions.ts`), it carries the L0→L5
29
+ tree shape, the authoring order by tool name, the fact that the `sdd_*` schemas
30
+ are self-describing, the bound project's governing `projectType`/profile, the
31
+ loaded packs, and the directive to read `wairon-skill://sdd-architect` **before**
32
+ authoring — with a pointer per published skill resource.
33
+
34
+ Deliberately short and pointer-heavy (~2.9 KB for this repo; a test pins a 6 KB
35
+ ceiling): the depth lives in `templates/skills/*.md`, and this is the map that
36
+ sends an agent to read them.
37
+
38
+ Composed **per `createMcpServer` call**, so the hosted per-request scoped server
39
+ (`server/request.ts:652`) reports its own bound project rather than a snapshot.
40
+ Never throws — a failed pack load or an uninitialized project degrades to
41
+ wairon's own briefing, because a connecting agent must always be taught
42
+ something.
43
+
44
+ Path: `mcp_server` → `mcp_skills_adapter` → `skills_portal` →
45
+ `skills_resource_orchestrator` → `instructions_specialist`. `sdd_mcp` stays a
46
+ transport subsystem.
47
+
48
+ ### 7.2 — pack-contributed instruction blocks
49
+
50
+ `DeclarativePackSchema.instructions` accepts a bare string, one block, or a list,
51
+ normalized to `PackInstructionBlock[]`:
52
+
53
+ ```yaml
54
+ instructions:
55
+ - text: Applies to every project this pack governs.
56
+ - text: Router branches never appear in a spec — model them as narrative branch steps.
57
+ profile: [make-automation]
58
+ ```
59
+
60
+ Appended after wairon's text under `## From pack "<name>"`, in **pack load
61
+ order** — the one merged field whose order is semantic, so blocks are never
62
+ deduped or overwritten. `profile` scopes a block to the governing profile exactly
63
+ as declarative assertions scope theirs; a block scoped to a profile that cannot
64
+ be resolved is **withheld**, so platform doctrine never leaks into an unrelated
65
+ project.
66
+
67
+ ---
68
+
69
+ ## Shipped (continued)
70
+
71
+ ### 7.4 — skills as MCP prompts — SHIPPED
72
+
73
+ Resources are pull-only; prompts are what makes a skill *discoverable* to a human
74
+ driving an agent (as a slash command or attachable context).
75
+
76
+ - Register a prompts capability mirroring `listSkillResources()` — the SDK
77
+ exposes `registerPrompt`, so the set cannot drift from the resource mirror.
78
+ - Prompt name = skill id (`sdd-architect`, `appenser-make-implementer`); the
79
+ handler returns the skill markdown as a message.
80
+ - Resources stay for programmatic reads. Hosted inherits this via the shared
81
+ factory, as the resource mirror already does.
82
+ - Test over an in-memory transport (`client.listPrompts()` / `getPrompt()`),
83
+ matching `tests/mcp/skill-resources.test.ts`.
84
+
85
+ ### 7.5 — variant guidance over MCP — SHIPPED
86
+
87
+ `agent_resolver.buildVariantGuidance` (`src/core/agent_resolver.ts:216`) is the
88
+ right hook for platform implementation guidance — it attaches to the component
89
+ the implementer is holding, with no doctrine duplication. But it only reaches
90
+ **generated agent files**, so hosted/cloud agents never see it.
91
+
92
+ - **Lift the composition into `src/core/variants.ts`** so the agent renderer and
93
+ the MCP path share one implementation instead of a second copy that drifts.
94
+ - `sdd_get_spec` on a variant-tagged component returns the resolved variant
95
+ guidance and its same-variant siblings as a clearly-derived, **read-only**
96
+ field, documented in the tool description as not part of the spec.
97
+ - Naming the active variants in the `initialize` instructions was **not** built —
98
+ see the outcome note below. The request said "and/or", and the `sdd_get_spec`
99
+ half is the substantive one.
100
+
101
+ ### 7.3 — pack skills that EXTEND a builtin — SHIPPED
102
+
103
+ Today `PackSkillSchema` is `{id, source, targets}` and pack skills are namespaced
104
+ `<pack>-<id>` so they cannot shadow `sdd-*`. A platform delta can therefore only
105
+ exist as a **parallel** skill (`appenser-make-implementer` beside `sdd-implement`),
106
+ leaving the agent to notice both and reconcile them — and tempting every wrapper
107
+ to fork the builtin wholesale, which is worse for everyone.
108
+
109
+ ```yaml
110
+ skills:
111
+ - extends: sdd-implement # builtin skill name
112
+ source: skills/make-implementer/SKILL.md
113
+ - id: make-control-plane # unchanged: a genuinely new skill
114
+ source: skills/make-control-plane/SKILL.md
115
+ ```
116
+
117
+ - `PackSkillSchema` becomes a union; `extends` must name a builtin
118
+ (`SKILL_NAMES`), and an unknown target **fails the pack load loudly** — the
119
+ `assertions` precedent: an old wairon must never silently not-apply a newer
120
+ pack's doctrine.
121
+ - The pack section is appended to the builtin under `## Platform: <pack>`
122
+ (multiple packs in load order), on install **and** on `resources/read`. The
123
+ builtin stays wairon's, so an upgrade still updates it.
124
+ - An extending skill contributes **no separate resource** — it composes into the
125
+ builtin's descriptor.
126
+
127
+ **The trap:** `checkSkillFreshness` (`src/core/skills.ts:166`) byte-compares the
128
+ installed file against the raw builtin template. Left alone, every extended skill
129
+ reports permanently **stale** in `wairon doctor`. It must compare against the
130
+ *composed* expectation.
131
+
132
+ Also touched: `exportSddSkills` (write composed), `readSkillResource` /
133
+ `readResource` (return composed), `listSkillResources` (descriptors), and the
134
+ `pack_skill` type spec.
135
+
136
+ ---
137
+
138
+ ## Sequencing (as built)
139
+
140
+ 7.4 → 7.5 → 7.3, in ascending order of blast radius, after the pack-scoping work
141
+ (`docs/design/pack-scoping.md`) had settled the selection model — 7.3's
142
+ composition runs over whatever pack set resolution yields.
143
+
144
+ ---
145
+
146
+ ## Outcome notes
147
+
148
+ **7.5 — one half deliberately not built.** The request said "include the resolved
149
+ variant guidance in `sdd_get_spec` … **and/or** name the active variants in the
150
+ `initialize` instructions". The first is done. The second is not: reading the
151
+ variant registry from the instructions composer would be an `sdd_skills` →
152
+ `sdd_core` hop onto an internal Adapter, which the boundary rules refuse, and
153
+ routing it through the core portal would mean a barrel import cycle for what is
154
+ only a pointer. The substantive requirement — guidance reaching a hosted agent —
155
+ is satisfied by the tool that hands an implementer its component.
156
+
157
+ **7.3 — the trap was real.** `checkSkillFreshness` byte-compared installed skills
158
+ against the raw builtin template. Left alone, every extended skill would have
159
+ reported permanently *stale* in `wairon doctor`, telling users to run `generate`
160
+ on a loop. It now compares against what `exportSddSkills` would write.
161
+
162
+ **A latent bug found while testing 7.5.** `requireSpecs()` in `mcp/server.ts`
163
+ lazily required a relative path, which does not resolve under the test runner — so
164
+ every `sdd_*` tool built on it failed with a module error instead of running. No
165
+ test had ever driven one through an MCP client, so nothing caught it. The
166
+ remaining lazy requires in that file (loader / validation / provision) are the
167
+ same latent landmine for any future test that exercises those tools.
@@ -0,0 +1,199 @@
1
+ # Execution budgets — the resource axis of the topology
2
+
3
+ > Status: **implemented**. Written against wairon 5.1.x. The measurements below
4
+ > come from three archived Claude Code sessions of this project's own
5
+ > development, read out of the session transcripts rather than estimated.
6
+
7
+ ---
8
+
9
+ ## The problem
10
+
11
+ The derived topology answered one question about each agent — *what does it own*
12
+ — and nothing about a second one that turns out to cost real money: *what does
13
+ its work cost to do*.
14
+
15
+ In a delegating workflow that gap has a specific, measurable shape. A Claude
16
+ Code subagent's `model` field defaults to `inherit`. An agent file that omits it
17
+ silently adopts the parent session's model. With a frontier-tier parent and no
18
+ agent files on disk at all, **1,860 of 2,176 subagent turns ran on the most
19
+ expensive tier** across the three sessions measured — not by anyone's decision,
20
+ but by a default nobody had reason to look at.
21
+
22
+ Two things are worth stating because they are commonly assumed and were both
23
+ wrong here:
24
+
25
+ - **Per-spawn startup duplication is not the problem.** Subagents do reload
26
+ CLAUDE.md and tool schemas from scratch — measured at 13.5k–32.5k tokens
27
+ against a main session's 44–46k. But the whole CLAUDE.md chain came to ~2,400
28
+ tokens: 8% of a subagent's startup and **0.2% of subagent spend**. Eliminating
29
+ it entirely would save ~2%.
30
+ - **Delegation was still correct.** Running the same work inline in a session
31
+ already averaging 271k context would have added a large context-carry
32
+ surcharge on every turn, and would have forced repeated compaction. The
33
+ problem was never *whether* to delegate; it was that every delegation was
34
+ constituted by default.
35
+
36
+ A default that expensive cannot be fixed by instruction text. A prompt asking an
37
+ orchestrator to choose models deliberately competes for attention with the task,
38
+ and loses — the sessions measured had exactly such a policy, stated by the
39
+ maintainer, and it lost 85% of the time. It has to be configuration.
40
+
41
+ ---
42
+
43
+ ## The model
44
+
45
+ Four layers, tool-agnostic until the last. The split is what lets one derivation
46
+ serve a local Claude Code session, a hosted MCP client, and a tool that cannot
47
+ select models at all.
48
+
49
+ | Layer | File | Holds |
50
+ |-------|------|-------|
51
+ | **Execution profile** | `models/execution.ts`, `core/execution_profile.ts` | What the work *is like*: `breadth`, `writes`, `reasoningDepth`, `delegates`. Says nothing about models. |
52
+ | **Budget policy** | `core/budget_policy.ts` | What that *earns*: capability tier, effort, turn ceiling, tool class, delegation rights, MCP access. Named in tiers, never vendor models. |
53
+ | **Target emitter** | `exporters/claude.ts` | The per-tool *encoding*. Deliberately not generic. |
54
+ | **Brief** | `core/agent_resolver.ts` | The same budget, carried advisory to whoever spawns from it. |
55
+
56
+ ### Derivation needs no spec authoring
57
+
58
+ Every input already exists on a resolved `AgentRecord`:
59
+
60
+ - `reasoningDepth` reads the **component stereotype**, which the vocabulary
61
+ already encodes. A Store, Index, Registry or Adapter is plumbing that its L3
62
+ contract and L5 narrative fully describe. An Orchestrator, Supervisor or
63
+ Specialist carries the decisions. Inventing a second classification alongside
64
+ the stereotype would have meant two things to keep in agreement.
65
+ - `breadth` reads owned-path spread and whether `readPaths` sweeps the tree.
66
+ - `writes` reads the **role**, not the path count — see the reversals below.
67
+ - `delegates` reads the template.
68
+
69
+ ### Tiers, not model names
70
+
71
+ `ExecutionBudget.modelTier` is `small | standard | large | frontier`. Mapping a
72
+ tier onto a real model is the *consumer's* job, because only the consumer knows
73
+ what its host tool understands. The Claude Code exporter maps to model
74
+ **aliases** (`haiku`, `sonnet`, `opus`, `fable`) rather than pinned ids, so
75
+ generated files keep working across model releases.
76
+
77
+ ### The dial
78
+
79
+ `execution.tier` defaults to `off`, and each step is a strict superset of the
80
+ constraints below it — raising it can only tighten a budget, never loosen one.
81
+ That property is what makes the dial safe to turn without auditing every agent.
82
+
83
+ `free` is defined as having *no* quality tradeoff, which is why it expresses no
84
+ model choice at all: picking a model is a quality decision. An absent
85
+ `modelTier` is not the same as a default one, and the exporter omits the field
86
+ rather than substituting.
87
+
88
+ ---
89
+
90
+ ## Enforce versus advise
91
+
92
+ Both delivery paths carry the budget, and they are not equivalent:
93
+
94
+ - A **generated agent file** can *enforce*. Front-matter binds: `model`,
95
+ `effort`, `maxTurns`, `tools`, `mcpServers` are read by the host before the
96
+ agent runs.
97
+ - A **live brief** can only *advise*. The caller spawning from the brief is what
98
+ applies it.
99
+
100
+ That asymmetry is deliberate rather than a gap — a brief is consumed by tools
101
+ wairon does not control. It also matters practically: `materializeAgentFiles`
102
+ defaults to **off**, so the brief is the path most projects actually use, and a
103
+ budget that only reached generated files would have reached almost nobody.
104
+
105
+ The same line explains the hosted story. Budgets are declarative data and travel
106
+ fine over the hosted MCP surface as an advisory block on the brief. Front-matter,
107
+ hooks and settings are filesystem artifacts and only the local CLI can write
108
+ them. This is the same split hosted pack management already draws — declarative
109
+ over the API, code packs via filesystem — rather than a second rule.
110
+
111
+ ---
112
+
113
+ ## Two things derivation deliberately never produces
114
+
115
+ ### `frontier` is not an owner tier
116
+
117
+ Derivation caps deep reasoning at `large`, at every dial setting including
118
+ `aggressive`. `frontier` is reachable only by an explicit per-agent override.
119
+
120
+ The reasoning is that a frontier-capable model is a **sparring partner** for a
121
+ question the specs do not settle, not a way to operate a component day to day.
122
+ Given a tree that is already specced and decided, an owner that genuinely needs
123
+ frontier capability to function is usually a component doing too much — the same
124
+ smell `GOD_COMPONENT` reports, arrived at from a different direction. So it stays
125
+ a decision only the user can make, and `wairon execution show` surfaces every
126
+ agent pinned there.
127
+
128
+ ### `orchestrate` is not derived either
129
+
130
+ The `orchestrate` tool class — the thin grant that withholds bulk-content tools
131
+ from a pure router — exists because a manager that can read files will read
132
+ them, and then it accumulates context exactly like a main session, which is the
133
+ whole thing delegation was supposed to avoid.
134
+
135
+ But **every agent in a wairon topology owns and authors something**. Domain
136
+ owners write the specs and source they own; even a chained-subproject owner
137
+ writes its mount spec. Stripping their write tools would not make them cheaper,
138
+ it would make them broken. The genuine pure router in this workflow is the
139
+ human's own main session, which is not a wairon agent at all.
140
+
141
+ So `orchestrate` stays in the vocabulary as an override-selectable class for a
142
+ manager someone defines by hand, and derivation never assigns it.
143
+
144
+ ---
145
+
146
+ ## Reversals worth recording
147
+
148
+ Both were found by generating into a real project rather than by reading the
149
+ code, and both are pinned by regression tests.
150
+
151
+ **`writes` was inferred from owned-path count.** An implementer whose source
152
+ path could not be inferred came out with zero owned paths, therefore
153
+ `writes: false`, therefore `tools: Read, Grep, Glob` — an implementer that
154
+ cannot implement, produced silently. `writes` is now a property of the role. A
155
+ missing path is a topology gap to fix, not a reason to demote an agent.
156
+
157
+ **Budget front-matter leaked into other targets.** `cursor`, `copilot` and
158
+ `codex` all reuse `ClaudeExporter` for the agent-file shape. Enabling budgets
159
+ therefore wrote `model`, `maxTurns` and `mcpServers` into files for tools that do
160
+ not implement Claude Code's subagent contract. Those keys would be ignored, which
161
+ is worse than absent: a budget sitting in the file reads as enforced when nothing
162
+ enforces it. The shape is still shared; the encoding is now per-tool, opt-in at
163
+ the exporter registry once a target's own fields are verified.
164
+
165
+ ---
166
+
167
+ ## Deliberately out of scope
168
+
169
+ **Session-hygiene hooks and a context statusline.** Both would cut real tokens —
170
+ rewriting noisy commands so their output does not enter context verbatim, and
171
+ showing live context size instead of periodically re-measuring it. Neither
172
+ belongs here. They are identical for every project regardless of its spec tree,
173
+ so wairon would be deriving them from nothing, and wiring them means writing into
174
+ a hand-maintained `settings.json` with no marker-based reconcile available,
175
+ unlike every other file wairon generates. Generated skills are not a precedent:
176
+ those *are* wairon's domain.
177
+
178
+ **A conformance rule for frontier overrides.** `validate` gates the spec tree;
179
+ an override lives in project config, and `lint.allow` attaches to specs. The
180
+ finding actually wanted — "this component is doing too much" — is already
181
+ `GOD_COMPONENT`. The override warning lives in `wairon execution show`, where the
182
+ config it reports on lives.
183
+
184
+ ---
185
+
186
+ ## Open
187
+
188
+ - **Precedence between an agent file's `model:` and the
189
+ `CLAUDE_CODE_SUBAGENT_MODEL` environment variable is unverified.** The env var
190
+ short-circuits Claude Code's model-resolution chain when set to anything but
191
+ `inherit`; whether explicit front-matter still wins decides whether a global
192
+ floor and per-role pinning compose or conflict.
193
+ - **Whether `effort`, `maxTurns` and `mcpServers` in agent front-matter are
194
+ honoured** by a given Claude Code build. Documented, not yet measured.
195
+ - **Topology scale.** A large project generates 30–50 subsystem agents (and would
196
+ generate 1000+ with component implementers on). Because briefs resolve on
197
+ demand by id, nothing needs a materialized catalog — but agent *discovery*
198
+ still enumerates everything, which argues for scoping discovery to a domain.
199
+ Separate concern from budgets.