[epic] Make kdl-specs a first-class standalone specgen product #239

Open
opened 2026-07-23 05:44:44 +00:00 by coilyco-ops · 2 comments
Member

Product thesis

kdl-specs should be usable and understandable as a standalone product: install one driver, author KDL policy plus committed locks, and generate a guarded CLI without owning Go source, a Makefile, Ward, or any coilyco-specific runtime.

This is not a proposal to split another repository for appearances. The engine, policy grammar, code generator, and driver are already tightly coupled and belong together in cli-guard. The missing work is to turn the substantial subsystem that already exists into an explicit, installable, documented product surface.

What already exists

The implementation is much farther along than the current README/product posture suggests:

  • cli-guard#75: KDL Guardfile plus spec-driven runtime engine.
  • cli-guard#89: generated consumer main.go, keeping consumer source policy-only.
  • cli-guard#104: describe model, generated help, and policy annotations.
  • cli-guard#106: uv-style no-code driver.
  • cli-guard#118: materialize a standalone generated binary.
  • cli-guard#131 and #133: exec-dialect members and multiple Guardfiles merged into one binary.
  • cli-guard#164 and #174: consolidated product name kdl-specs.
  • cli-guard#176: ordered credential/value-source fallbacks.
  • cli-guard#196: transport-neutral operation core and inline-operation source.
  • cli-guard#216: fetch overlays for useful non-Swagger HTTP routes.
  • cli-guard#231 and #234: composite query projection and safe aliases for reserved upstream parameters.
  • cli-guard#233: generated binary names independent from the source wrap name.

Today cmd/kdl-specs exposes gen, lock, skew, build, and run; it prunes and commits API locks, freezes the generated Go dependency graph, materializes out of band, supports mixed HTTP/exec members, generates reference docs, and runs offline after locking.

The product gap

Despite that implementation:

  • the repository README presents cli-guard only as a Go security framework and does not introduce kdl-specs;
  • the release contract is tag-only and explicitly describes the repo as a library plus cmd/cli-guard-hook; it does not publish or document installation of the kdl-specs driver;
  • there is no neutral first-run path demonstrating install -> author -> lock -> inspect -> build -> run outside Ward;
  • existing expansion issues are isolated tickets, not a sequenced product roadmap;
  • user-facing stability, compatibility, and artifact contracts are implicit in package tests instead of stated as a standalone tool contract.

Boundary

Standalone specgen means a first-class driver over cli-guard's policy and operation engine. It does not mean cli-guard should absorb deployment policy or become a workflow orchestrator.

  • Keep the engine upstream- and consumer-neutral.
  • Keep generated surfaces deny-by-default and deterministic.
  • Keep domain deployment decisions such as service health and rollback out of the security/spec engine; cli-guard#190 owns that boundary correction.
  • Do not move Ward defaults, fleet configuration, or coilyco-specific auth paths into the product.
  • Do not create a new repository unless a concrete technical boundary later requires it.
  • Treat a rename of cli-guard itself as the separate product decision in cli-guard#200.

Workstreams to scope into discrete child issues

1. Install and release

Choose and ship a supported installation path for kdl-specs itself. At minimum document go install against Forgejo tags; preferably publish versioned cross-platform binaries with checksums through the existing two-stage release pipeline. The installed driver must report its version and the cli-guard ref it will freeze into generated consumers.

2. Neutral quickstart and examples

Add a small vendor-neutral fixture and a canonical journey from an empty directory to a generated binary:

install -> author/select Guardfile -> lock -> describe/dry-run -> build -> run -> skew

It must require no Ward checkout, private infrastructure, SSM parameter, or live destructive API. The example should demonstrate the source-of-truth files, generated/cache artifacts, and expected review diff.

3. Discovery and project layout

Resolve cli-guard#182. A project containing one KDL file or many files across nested directories should have an explicit, deterministic project/binary selection model rather than relying on *.guardfile.kdl beside one selected file. Preserve unambiguous grouping, stable cache keys, per-member locks/docs, and fail-closed duplicate/conflict handling.

4. Generated artifact families

Scope cli-guard#222 as an optional product milestone: typed client/library generation for Go, Python, Node, and Rust from the same policy-reduced operation model. Do not couple the core milestone to all four languages at once. Define whether generated libraries expose only granted operations, how names are derived, and how schema/auth/policy metadata survive projection.

5. Spec gaps and extension model

Resolve cli-guard#223 and document the extension hierarchy for operations not represented by upstream OpenAPI: spec-backed operation, inline operation, fetch overlay, or guarded exec bridge. Support must remain explicit and reviewable; a declared-but-dead bridge is worse than a clear unsupported error.

6. Credentials and secret confinement

Resolve cli-guard#215 after the driver boundary is stable. Generated tools need a documented credential-provider contract that keeps secret values out of generated source, argv, logs, dry-run output, caches, and committed locks.

7. Compatibility and confidence

State compatibility promises for the KDL grammar, lock formats, cache stamps, generated docs, driver exit codes, and generated binary behavior. Add product-level fixtures that exercise upgrades, deterministic regeneration, offline builds, upstream skew, malformed policy, and actionable recovery.

8. Product documentation

Give kdl-specs first-class space in README/docs navigation: what it is, who it is for, how it differs from importing cli-guard as a Go library, the security model, and the quickest path to a useful generated tool.

Epic acceptance

  • A new user can discover and install kdl-specs without already knowing Ward.
  • A neutral checked-in example builds and runs from KDL plus locks with no hand-written Go or Makefile.
  • The supported artifact/install and versioning contract is explicit.
  • Discovery supports the agreed project layout from cli-guard#182 deterministically.
  • Docs explain the extension hierarchy for spec gaps and the secret-provider boundary.
  • Product-level tests prove deterministic generation, offline-after-lock behavior, skew detection, and fail-closed malformed policy.
  • The tracker contains small, dependency-ordered child issues for the work above; this epic remains coordination and acceptance, not one giant implementation PR.

Director commission

Audit current main against these workstreams, reconcile the existing issues named above, and file only the missing discrete children with dependencies and appropriate execution labels. Do not implement the epic as one change and do not duplicate work already landed.

## Product thesis `kdl-specs` should be usable and understandable as a standalone product: install one driver, author KDL policy plus committed locks, and generate a guarded CLI without owning Go source, a Makefile, Ward, or any coilyco-specific runtime. This is not a proposal to split another repository for appearances. The engine, policy grammar, code generator, and driver are already tightly coupled and belong together in cli-guard. The missing work is to turn the substantial subsystem that already exists into an explicit, installable, documented product surface. ## What already exists The implementation is much farther along than the current README/product posture suggests: - cli-guard#75: KDL Guardfile plus spec-driven runtime engine. - cli-guard#89: generated consumer `main.go`, keeping consumer source policy-only. - cli-guard#104: describe model, generated help, and policy annotations. - cli-guard#106: uv-style no-code driver. - cli-guard#118: materialize a standalone generated binary. - cli-guard#131 and #133: exec-dialect members and multiple Guardfiles merged into one binary. - cli-guard#164 and #174: consolidated product name `kdl-specs`. - cli-guard#176: ordered credential/value-source fallbacks. - cli-guard#196: transport-neutral operation core and inline-operation source. - cli-guard#216: fetch overlays for useful non-Swagger HTTP routes. - cli-guard#231 and #234: composite query projection and safe aliases for reserved upstream parameters. - cli-guard#233: generated binary names independent from the source wrap name. Today `cmd/kdl-specs` exposes `gen`, `lock`, `skew`, `build`, and `run`; it prunes and commits API locks, freezes the generated Go dependency graph, materializes out of band, supports mixed HTTP/exec members, generates reference docs, and runs offline after locking. ## The product gap Despite that implementation: - the repository README presents cli-guard only as a Go security framework and does not introduce `kdl-specs`; - the release contract is tag-only and explicitly describes the repo as a library plus `cmd/cli-guard-hook`; it does not publish or document installation of the `kdl-specs` driver; - there is no neutral first-run path demonstrating `install -> author -> lock -> inspect -> build -> run` outside Ward; - existing expansion issues are isolated tickets, not a sequenced product roadmap; - user-facing stability, compatibility, and artifact contracts are implicit in package tests instead of stated as a standalone tool contract. ## Boundary Standalone specgen means a first-class driver over cli-guard's policy and operation engine. It does **not** mean cli-guard should absorb deployment policy or become a workflow orchestrator. - Keep the engine upstream- and consumer-neutral. - Keep generated surfaces deny-by-default and deterministic. - Keep domain deployment decisions such as service health and rollback out of the security/spec engine; cli-guard#190 owns that boundary correction. - Do not move Ward defaults, fleet configuration, or coilyco-specific auth paths into the product. - Do not create a new repository unless a concrete technical boundary later requires it. - Treat a rename of cli-guard itself as the separate product decision in cli-guard#200. ## Workstreams to scope into discrete child issues ### 1. Install and release Choose and ship a supported installation path for `kdl-specs` itself. At minimum document `go install` against Forgejo tags; preferably publish versioned cross-platform binaries with checksums through the existing two-stage release pipeline. The installed driver must report its version and the cli-guard ref it will freeze into generated consumers. ### 2. Neutral quickstart and examples Add a small vendor-neutral fixture and a canonical journey from an empty directory to a generated binary: ```text install -> author/select Guardfile -> lock -> describe/dry-run -> build -> run -> skew ``` It must require no Ward checkout, private infrastructure, SSM parameter, or live destructive API. The example should demonstrate the source-of-truth files, generated/cache artifacts, and expected review diff. ### 3. Discovery and project layout Resolve cli-guard#182. A project containing one KDL file or many files across nested directories should have an explicit, deterministic project/binary selection model rather than relying on `*.guardfile.kdl` beside one selected file. Preserve unambiguous grouping, stable cache keys, per-member locks/docs, and fail-closed duplicate/conflict handling. ### 4. Generated artifact families Scope cli-guard#222 as an optional product milestone: typed client/library generation for Go, Python, Node, and Rust from the same policy-reduced operation model. Do not couple the core milestone to all four languages at once. Define whether generated libraries expose only granted operations, how names are derived, and how schema/auth/policy metadata survive projection. ### 5. Spec gaps and extension model Resolve cli-guard#223 and document the extension hierarchy for operations not represented by upstream OpenAPI: spec-backed operation, inline operation, fetch overlay, or guarded exec bridge. Support must remain explicit and reviewable; a declared-but-dead bridge is worse than a clear unsupported error. ### 6. Credentials and secret confinement Resolve cli-guard#215 after the driver boundary is stable. Generated tools need a documented credential-provider contract that keeps secret values out of generated source, argv, logs, dry-run output, caches, and committed locks. ### 7. Compatibility and confidence State compatibility promises for the KDL grammar, lock formats, cache stamps, generated docs, driver exit codes, and generated binary behavior. Add product-level fixtures that exercise upgrades, deterministic regeneration, offline builds, upstream skew, malformed policy, and actionable recovery. ### 8. Product documentation Give `kdl-specs` first-class space in README/docs navigation: what it is, who it is for, how it differs from importing cli-guard as a Go library, the security model, and the quickest path to a useful generated tool. ## Epic acceptance - A new user can discover and install `kdl-specs` without already knowing Ward. - A neutral checked-in example builds and runs from KDL plus locks with no hand-written Go or Makefile. - The supported artifact/install and versioning contract is explicit. - Discovery supports the agreed project layout from cli-guard#182 deterministically. - Docs explain the extension hierarchy for spec gaps and the secret-provider boundary. - Product-level tests prove deterministic generation, offline-after-lock behavior, skew detection, and fail-closed malformed policy. - The tracker contains small, dependency-ordered child issues for the work above; this epic remains coordination and acceptance, not one giant implementation PR. ## Director commission Audit current main against these workstreams, reconcile the existing issues named above, and file only the missing discrete children with dependencies and appropriate execution labels. Do not implement the epic as one change and do not duplicate work already landed.
Author
Member

Director commission attempted from the read-only surface on 2026-07-23. The issue-scoped director did not launch: Ward hit the attached-role Docker 125 tracked in coilyco-flight-deck/ward#577 (/workspace/coilysiren was passed as a host bind and Docker Desktop rejected it as unshared). The roadmap remains captured here; no scoping director is currently in flight.

Director commission attempted from the read-only surface on 2026-07-23. The issue-scoped director did not launch: Ward hit the attached-role Docker 125 tracked in coilyco-flight-deck/ward#577 (`/workspace/coilysiren` was passed as a host bind and Docker Desktop rejected it as unshared). The roadmap remains captured here; no scoping director is currently in flight.
Author
Member

Decision recorded by Darren (director seat), 2026-08-16, from a full triage pass. Kai's call in a consult round.

The call

The standalone-product thesis stands, sequenced behind #295. Land the specgen to umbra-shroud rename first so the product has a settled name, then decompose the eight workstreams into dependency-ordered children.

Why the sequencing is the substance of the answer

This epic is written against cmd/kdl-specs. The binary is specgen today and becomes umbra-shroud under #295. That is the third name for one thing, and this epic's workstreams are mostly name-bearing surfaces: the install path, the Homebrew formula, the Scoop manifest, the quickstart, the docs navigation, and the compatibility promises all embed the binary name.

Decomposing now would file eight children that each need rewriting after #295. Decomposing after means each child is authored once, against a name that is not going to move again.

What was rejected, and why

  • Narrow it and drop the standalone-product framing, keeping the driver as umbra's own tool and closing the epic in favour of the concrete children worth doing anyway. This was the recommended option and Kai declined it. It would have forfeited external adoption of the driver, which is the thing she is choosing to keep.
  • Park as-is at P4. Declined as a resting state, though note the labels below still park it in practice until #295 lands. The difference is that the direction is now confirmed rather than unexamined.

The stale premise this issue carries

Recording it so the decomposition does not inherit it. The body says the product name was consolidated as kdl-specs in cli-guard#164 and #174. That consolidation was superseded twice over, and #295 sets out why: spec is overloaded four ways across spec, specgen, specverb, and .specgen/, and any name keeping spec keeps the collision. Whoever decomposes this should read #295 first and treat umbra-shroud as the product name throughout.

specverb.lock still carries a field named cliGuard holding the umbra version, which is the same class of residue from the rename before last. #295 owns fixing it.

What unblocks the decomposition

The director commission never launched: Ward hit the attached-role Docker 125 tracked in coilyco-flight-deck/ward#577, where /workspace/coilysiren was passed as a host bind and Docker Desktop rejected it as unshared. That blocker is unaddressed here and is not this epic's to fix. A decomposition pass can equally be run from an interactive seat.

Staying priority/P4 autonomy/epic role/director. P4 because it is deliberately parked behind #295 rather than because the direction is in doubt, and autonomy/epic because its children carry their own ceilings and nothing should dispatch this as one task.

**Decision recorded by Darren (director seat), 2026-08-16, from a full triage pass. Kai's call in a consult round.** ## The call **The standalone-product thesis stands, sequenced behind #295.** Land the `specgen` to `umbra-shroud` rename first so the product has a settled name, then decompose the eight workstreams into dependency-ordered children. ## Why the sequencing is the substance of the answer This epic is written against `cmd/kdl-specs`. The binary is `specgen` today and becomes `umbra-shroud` under #295. **That is the third name for one thing**, and this epic's workstreams are mostly name-bearing surfaces: the install path, the Homebrew formula, the Scoop manifest, the quickstart, the docs navigation, and the compatibility promises all embed the binary name. Decomposing now would file eight children that each need rewriting after #295. Decomposing after means each child is authored once, against a name that is not going to move again. ## What was rejected, and why * **Narrow it and drop the standalone-product framing**, keeping the driver as umbra's own tool and closing the epic in favour of the concrete children worth doing anyway. This was the recommended option and Kai declined it. It would have forfeited external adoption of the driver, which is the thing she is choosing to keep. * **Park as-is at P4.** Declined as a resting state, though note the labels below still park it in practice until #295 lands. The difference is that the direction is now confirmed rather than unexamined. ## The stale premise this issue carries Recording it so the decomposition does not inherit it. The body says the product name was consolidated as `kdl-specs` in cli-guard#164 and #174. That consolidation was superseded twice over, and #295 sets out why: `spec` is overloaded four ways across `spec`, `specgen`, `specverb`, and `.specgen/`, and any name keeping `spec` keeps the collision. Whoever decomposes this should read #295 first and treat `umbra-shroud` as the product name throughout. `specverb.lock` still carries a field named `cliGuard` holding the umbra version, which is the same class of residue from the rename before last. #295 owns fixing it. ## What unblocks the decomposition The director commission never launched: Ward hit the attached-role Docker 125 tracked in `coilyco-flight-deck/ward#577`, where `/workspace/coilysiren` was passed as a host bind and Docker Desktop rejected it as unshared. That blocker is unaddressed here and is not this epic's to fix. A decomposition pass can equally be run from an interactive seat. Staying `priority/P4` `autonomy/epic` `role/director`. P4 because it is deliberately parked behind #295 rather than because the direction is in doubt, and `autonomy/epic` because its children carry their own ceilings and nothing should dispatch this as one task.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
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/umbra#239
No description provided.