[tracking] Slim ward to the product layer (migrate engine/policy code to cli-guard) #265

Open
opened 2026-06-24 07:46:04 +00:00 by coilyco-ops · 6 comments
Member

Umbrella for concern #1 of the launch (milestone 7): ward is fat. The audit found ~60% of cmd/ward non-test LOC is reusable engine/policy that belongs in cli-guard, not in the product binary. cli-guard is already a clean standalone engine (no reverse import, builds without ward present) - so this is migration, not untangling a cycle.

Sub-issues (this repo unless noted):

  • Container sandbox + bootstrap + substrate -> cli-guard.
  • Collapse ward agent onto cli-guard dispatch.Dispatcher (+ cli-guard: make it pluggable).
  • Extract credential seeding -> cli-guard.
  • Extract the small reusable helpers (junk-scan, settings-installer, hook tables, attribution, flock, semver, owner-trust, issue-ref) -> cli-guard.

Not launch-blocking (the launch leads with warded-the-product, not "cli-guard the reusable core"), but the cleaner the split, the more the 3-layer story holds under inspection.

Umbrella for concern #1 of the launch (milestone 7): ward is **fat**. The audit found ~60% of `cmd/ward` non-test LOC is reusable engine/policy that belongs in cli-guard, not in the product binary. cli-guard is **already a clean standalone engine** (no reverse import, builds without ward present) - so this is migration, not untangling a cycle. Sub-issues (this repo unless noted): - Container sandbox + bootstrap + substrate -> cli-guard. - Collapse `ward agent` onto cli-guard `dispatch.Dispatcher` (+ cli-guard: make it pluggable). - Extract credential seeding -> cli-guard. - Extract the small reusable helpers (junk-scan, settings-installer, hook tables, attribution, flock, semver, owner-trust, issue-ref) -> cli-guard. Not launch-blocking (the launch leads with `warded`-the-product, not "cli-guard the reusable core"), but the cleaner the split, the more the 3-layer story holds under inspection.
Author
Member

Sub-issues

Slim ward (concern #1 - migrate engine/policy to cli-guard):

  • ward#266 - container sandbox + PID-1 bootstrap + substrate (interactive, high risk)
  • ward#267 - collapse ward agent onto cli-guard dispatch.Dispatcher (interactive, high risk)
  • cli-guard#162 - make dispatch.Dispatcher pluggable (prereq for #267)
  • ward#268 - extract credential seeding
  • ward#269 - extract the small reusable helpers (batch)
  • cli-guard#163 - neutralize consumer names in engine comments/fixtures

ward-kdl legibility (concern #2 - launch-adjacent):

  • ward#270 - de-Go-ify cmd/ward-kdl/, rename ward ops namespace, mark generated copies
  • ward#271 - authoritative docs/ward-kdl.md + README/AGENTS framing
  • cli-guard#164 - rename the generator naming soup (specverb-gen/specdrv/specgen)

Sequencing: cli-guard#162 lands+releases before ward#267. The legibility set (#270/#271/cli-guard#164) is the launch-relevant slice; the migrations are post-launch. None are hard launch blockers - the launch leads with warded-the-product. Audit basis: ward docs/architecture.md (the 3-layer model).

## Sub-issues **Slim ward (concern #1 - migrate engine/policy to cli-guard):** - ward#266 - container sandbox + PID-1 bootstrap + substrate (interactive, high risk) - ward#267 - collapse `ward agent` onto cli-guard dispatch.Dispatcher (interactive, high risk) - cli-guard#162 - make dispatch.Dispatcher pluggable (prereq for #267) - ward#268 - extract credential seeding - ward#269 - extract the small reusable helpers (batch) - cli-guard#163 - neutralize consumer names in engine comments/fixtures **ward-kdl legibility (concern #2 - launch-adjacent):** - ward#270 - de-Go-ify cmd/ward-kdl/, rename ward ops namespace, mark generated copies - ward#271 - authoritative docs/ward-kdl.md + README/AGENTS framing - cli-guard#164 - rename the generator naming soup (specverb-gen/specdrv/specgen) **Sequencing:** cli-guard#162 lands+releases before ward#267. The legibility set (#270/#271/cli-guard#164) is the launch-relevant slice; the migrations are post-launch. None are hard launch blockers - the launch leads with `warded`-the-product. Audit basis: ward `docs/architecture.md` (the 3-layer model).
coilyco-ops added
P3
and removed
P2
labels 2026-06-24 17:20:13 +00:00
Author
Member

Re-triage (goose-triage method, claude-macos-kais-macbook-pro-2 as the judgment engine, 2026-06-24)

  • P3 - Umbrella tracking issue for the slim-ward epic, low actionability on its own.
  • consult - A tracking parent, not directly dispatchable, an agent should not start it as work.
<!-- goose-triage --> **Re-triage** (goose-triage method, claude-macos-kais-macbook-pro-2 as the judgment engine, 2026-06-24) - **P3** - Umbrella tracking issue for the slim-ward epic, low actionability on its own. - **consult** - A tracking parent, not directly dispatchable, an agent should not start it as work.
Author
Member

Re-triage (goose-triage method, claude-macos-kais-macbook-pro-2 as the judgment engine, 2026-06-24)

  • P3 - Umbrella tracking issue for the slim-ward epic, low actionability on its own.
  • consult - A tracking parent, not directly dispatchable, an agent should not start it as work.
<!-- goose-triage --> **Re-triage** (goose-triage method, claude-macos-kais-macbook-pro-2 as the judgment engine, 2026-06-24) - **P3** - Umbrella tracking issue for the slim-ward epic, low actionability on its own. - **consult** - A tracking parent, not directly dispatchable, an agent should not start it as work.
Author
Member

Stays consult: tracking umbrella, not directly dispatchable - the children carry the work. Canonical for #479 and #200 (merged). Recorded by Claude Code (Fable) during the 2026-07-01 ward launch triage session with Kai.

Stays consult: tracking umbrella, not directly dispatchable - the children carry the work. Canonical for #479 and #200 (merged). Recorded by Claude Code (Fable) during the 2026-07-01 ward launch triage session with Kai.
Owner

Cross-link: the ward-mcp inline-authoring work is filing the engine-general core as a transport-neutral cli-guard capability (cli-guard#196) - inline-operation source + input-schema exposure + guarded-execute, pulled out from behind the urfave/cli projection so any consumer drives one engine.

That core is the shared substrate this issue wants for ward too: once cli-guard exposes descriptor build + guarded execution transport-neutrally, ward's own spec/guard/request code becomes a thin consumer of it rather than a parallel copy. ward-mcp is being built thin-from-birth on that boundary (ward-mcp#6); the same seam is what lets ward shed its engine code here. Respects cli-guard#190 - only the engine core migrates down, not orchestration.

Cross-link: the ward-mcp inline-authoring work is filing the engine-general core as a **transport-neutral cli-guard capability** (cli-guard#196) - inline-operation source + input-schema exposure + guarded-execute, pulled out from behind the urfave/cli projection so any consumer drives one engine. That core is the shared substrate this issue wants for ward too: once cli-guard exposes descriptor build + guarded execution transport-neutrally, ward's own spec/guard/request code becomes a thin consumer of it rather than a parallel copy. ward-mcp is being built thin-from-birth on that boundary (ward-mcp#6); the same seam is what lets ward shed its engine code here. Respects cli-guard#190 - only the engine core migrates down, not orchestration.
Owner

Measured the layers (2026-07-07) - the premise holds, the diagnosis sharpens

              src LOC   packages   shape
cli-guard     23,592    61         factored (biggest pkg specverb 4.7k)
ward          22,682     9         cmd/ward = 21.2k in ONE package main (77 files)
ward-mcp           0     0         thin shell by design (SSE + opcore glue)

The premise holds - ward is fat, ~= cli-guard in total src. But the first-order problem is not "60% belongs in cli-guard." It is that cmd/ward is a 77-file, 21.2k-LOC package main monolith with no internal seams. The biggest files - agent.go (1762), container_bootstrap (1477), agent_director (1229), container_compute (1023), container_reap (883) - are the agent/container product, all package-private to each other.

The work is two things this umbrella conflates

  1. De-monolith cmd/ward into internal packages (agent/, container/, ops/, ...). Pure ward-internal structure, valuable even if nothing migrates, and the prerequisite that gives the migrations something to cut along. Filed as ward#630.
  2. Migrate only the engine-general slices down - and here the boundary we have sharpened since this issue was written (cli-guard#190 / #196) becomes the per-slice test. Engine primitive (guardfile/spec handling, the reusable helpers, cred seeding, consolidating dispatch/sandbox onto cli-guard's existing cli/dispatch + cli/sandbox) migrates down. Ward-specific orchestration/policy stays ward's product and just gets packaged. Worth re-checking ward#266 (sandbox) and ward#267 (dispatch collapse) against cli-guard#190 explicitly - some targets may reduce to "package within ward" rather than "migrate down."

ward-mcp is the reference shape

A brand-new consumer on the shared engine lands at ~0-2k because opcore does the parse/guard/schema/request work. The gap between "what ward-mcp costs to add" and "what ward costs to change" is the argument for this epic in one line. And the opcore extraction (cli-guard#197-199, all landed today) is the exact move-pattern ward's internal slices need: name the concern, give it a package, move it, aliases keeping tests green.

On closing this

My recommendation is keep it. The goal is unchanged and the sub-issue tree is usable - this is a refinement (package-first, then apply the #190 test per slice), not a reversal. The sequence: land ward#630 (the de-monolith prerequisite), then re-scope #266 / #267 against #190, rather than nuking the umbrella and orphaning its tree. If you would rather restart clean with the corrected framing, say so and I will close this and open a fresh tracker that carries the two-phase structure - but I do not think the reframe earns a close on its own.

## Measured the layers (2026-07-07) - the premise holds, the diagnosis sharpens ``` src LOC packages shape cli-guard 23,592 61 factored (biggest pkg specverb 4.7k) ward 22,682 9 cmd/ward = 21.2k in ONE package main (77 files) ward-mcp 0 0 thin shell by design (SSE + opcore glue) ``` **The premise holds** - ward is fat, ~= cli-guard in total src. But the first-order problem is not "60% belongs in cli-guard." It is that `cmd/ward` is a **77-file, 21.2k-LOC `package main` monolith** with no internal seams. The biggest files - `agent.go` (1762), `container_bootstrap` (1477), `agent_director` (1229), `container_compute` (1023), `container_reap` (883) - are the agent/container **product**, all package-private to each other. ## The work is two things this umbrella conflates 1. **De-monolith `cmd/ward`** into internal packages (`agent/`, `container/`, `ops/`, ...). Pure ward-internal structure, valuable **even if nothing migrates**, and the prerequisite that gives the migrations something to cut along. Filed as **ward#630**. 2. **Migrate only the engine-general slices down** - and here the boundary we have sharpened *since* this issue was written (cli-guard#190 / #196) becomes the **per-slice test**. Engine primitive (guardfile/spec handling, the reusable helpers, cred seeding, consolidating dispatch/sandbox onto cli-guard's existing `cli/dispatch` + `cli/sandbox`) migrates down. Ward-specific orchestration/policy stays ward's product and just gets packaged. Worth re-checking ward#266 (sandbox) and ward#267 (dispatch collapse) against cli-guard#190 explicitly - some targets may reduce to "package within ward" rather than "migrate down." ## ward-mcp is the reference shape A brand-new consumer on the shared engine lands at ~0-2k because opcore does the parse/guard/schema/request work. The gap between "what ward-mcp costs to add" and "what ward costs to change" is the argument for this epic in one line. And the opcore extraction (cli-guard#197-199, all landed today) is the exact move-pattern ward's internal slices need: name the concern, give it a package, move it, aliases keeping tests green. ## On closing this My recommendation is **keep it**. The goal is unchanged and the sub-issue tree is usable - this is a **refinement** (package-first, then apply the #190 test per slice), not a reversal. The sequence: land ward#630 (the de-monolith prerequisite), then re-scope #266 / #267 against #190, rather than nuking the umbrella and orphaning its tree. If you would rather restart clean with the corrected framing, say so and I will close this and open a fresh tracker that carries the two-phase structure - but I do not think the reframe earns a close on its own.
coilyco-ops added
P4
and removed
P3
labels 2026-07-14 06:50:34 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
coilyco-flight-deck/ward#265
No description provided.