Skip to content

feat(skills): ctl workflow skills foundation (grill/PRD/tasks/TDD/handoff + architecture-review) - #4

Merged
neostfox merged 17 commits into
masterfrom
workflow-skills-foundation
Jun 19, 2026
Merged

feat(skills): ctl workflow skills foundation (grill/PRD/tasks/TDD/handoff + architecture-review)#4
neostfox merged 17 commits into
masterfrom
workflow-skills-foundation

Conversation

@neostfox

Copy link
Copy Markdown
Owner

What

A ctl-native agent workflow skill layer on top of the existing control plane. Skills/agents manage semantic workflow; ctl keeps managing facts, scope, evidence, gates, ledgers and honest disclosure.

Three commits:

  1. feat(skills) — workflow skills foundation
  2. fix(cli) — include handoff/prd/ralph in the architecture check command-surface guard (pre-existing stale list on master too)
  3. feat(skills)ctl-architecture-review skill + wire ctl-diagnose into the workflow

Added

  • .agent/protocols/workflow-skills.md — canonical managed workflow-core (WORKFLOW_PROTOCOL_VERSION = 1): phase map (grill → PRD → tasks → TDD → diagnose → architecture → handoff), First Principles placed in grill, Bayesian in diagnose, cross-cutting invariants, L0 provenance.
  • Six skills × OMP + OpenCode, each embedding the core verbatim: ctl-grill-with-spec, ctl-to-prd, ctl-to-tasks, ctl-tdd-loop, ctl-handoff, ctl-architecture-review. Bodies reference the real shipped CLI (ctl prd init, ctl handoff export, ctl architecture review, --tdd/tdd-red-green interlock, --dry-run).
  • infrastructure/skills.rs — embed OMP skills (ctl init), generalize the control-guard block extractor, add a workflow_skills() registry + workflow_protocol_sync drift tests: core identical across canonical/OMP/OpenCode, version match, marker-corruption + platform-leak detection, OMP/OpenCode phase-body parity, no third-party vendoring, L0 docs.
  • Provenance (NOTICE.md), control-guard routing (outside the managed core), AGENTS.md + README.md honest framing. ctl-diagnose gets a workflow cross-link (kept on its standalone yao-bayesian lineage, OMP-only by design).

Inspiration (L0 references — adapted, not vendored)

  • Matt Pocock's engineering skill workflow → the phase pipeline and skill shapes.
  • Trellis PR #335 → First Principles / Bayesian placement (embedded in the right phases, no floating "think better" skills).

External skill text is treated as L0 reference material; ctl does not vendor third-party skills as an active control plane.

Honesty

These are agent workflow disciplines. They do not prove correctness, do not replace gates/audits/evidence, do not create authenticated reviewer independence, and do not create L3 tamper evidence.

Deliberately not implemented

Third adapter, Web UI, authenticated principals, cryptographic signing, hash-chain ledger, Ralph/overnight loop, cross-ledger WAL/2PC, perf benchmarking, new ontology/confidence scoring. No new ctl core governance semantics.

Verification

cargo fmt --check ✓, cargo clippy --all-targets -D warnings ✓, cargo test 425 passed, cargo run -- architecture check ✓. Developed under governed ctl tasks (workflow-skills-foundation-v1, workflow-skills-followups-v1) with reviewer-labelled audits (actor=ctl-review, distinct from the implementer) and a genuinely-exercised TDD red→green interlock. (Audits are reviewer role labels, not proven independent principals.)

🤖 Generated with Claude Code

neostfox and others added 17 commits June 19, 2026 12:56
ctl-native agent workflow layer (workflow-skills-foundation-v1), adapting the
useful disciplines from Matt Pocock's engineering skill workflow and the First
Principles / Bayesian placement from Trellis PR #335 — without vendoring either.

Skills/agents manage semantic workflow; ctl keeps managing facts, scope,
evidence, gates, ledgers and honest disclosure.

Added:
- .agent/protocols/workflow-skills.md — canonical managed workflow-core
  (WORKFLOW_PROTOCOL_VERSION = 1): phase map (grill -> PRD -> tasks -> TDD ->
  diagnose -> architecture -> handoff), First Principles placed in grill,
  Bayesian in diagnose, cross-cutting invariants, L0 provenance.
- Five skills x OMP + OpenCode (10 SKILL.md), each embedding the core verbatim:
  ctl-grill-with-spec, ctl-to-prd, ctl-to-tasks, ctl-tdd-loop, ctl-handoff.
  Bodies reference the real shipped CLI (ctl prd init, ctl handoff export,
  ctl task create --tdd / tdd-red-green interlock, ctl task create --dry-run).
- infrastructure/skills.rs: embed the OMP skills in all_embedded_files (ship via
  ctl init), generalize the control-guard block extractor, add a workflow_skills
  registry + workflow_protocol_sync drift tests (core identical across
  canonical/OMP/OpenCode, version match, marker-corruption + platform-leak
  detection, OMP/OpenCode phase-body parity, no third-party vendoring, L0 docs).
- NOTICE.md provenance (Matt Pocock skills, Trellis PR #335 as L0 references);
  control-guard routing updated (outside the managed core, both platforms);
  AGENTS.md + README.md honest framing (disciplines, not proofs).

These are agent workflow disciplines. They do not prove correctness, do not
replace gates/audits/evidence, do not create authenticated reviewer independence,
and do not create L3 tamper evidence. External skills are treated as L0
reference material; ctl does not vendor them as an active control plane.

Deferred follow-ups: ctl-architecture-review skill (CLI already exists),
ctl-diagnose v2. Pre-existing, unrelated: `architecture check` command-surface
guard is stale vs shipped prd/ralph/handoff — fixed separately.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…uard

`ctl architecture check` locks the top-level CLI surface, but the expected list
was never updated when `handoff`, `prd`, and `ralph` shipped — so the guard was
red on HEAD. Add the three already-shipped commands to the expected set; no CLI
behavior change. `ctl architecture check` now passes.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…se into the workflow

Follow-ups to the workflow skills foundation (workflow-skills-followups-v1).

- ctl-architecture-review (OMP + OpenCode): a new workflow-foundation skill
  embedding the managed workflow-core verbatim. Read-only by default — it starts
  from `ctl architecture review` (mechanical structural checks) and adds the
  qualitative deepening review (shallow modules, poor locality, hypothetical
  adapter boundaries, duplicated task/run/lease logic, mega-module risk,
  ungloassaried domain terms), outputting a candidate report with no code
  changes. A chosen candidate becomes a NEW governed task. Registered in
  workflow_skills() + shipped via all_embedded_files; auto-covered by the
  workflow_protocol_sync drift + phase-body-parity tests.
- ctl-diagnose: added a "Workflow placement" cross-link tying it to the
  foundation's diagnose phase (Bayesian placed here, not floating). Kept on its
  standalone yao-bayesian lineage and OMP-specific failure-diagnosis.md guide —
  deliberately NOT embedded in the shared workflow-core and NOT mirrored to
  OpenCode (its guide dep is OMP-only and the repo keeps OpenCode minimal).

Dogfooded the TDD red->green interlock: the registry entry was added first
(cargo_test FAIL: missing skill files), then the files (cargo_test PASS).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…tch routing

Bring the omp subagent roster into opencode under opencode-native names and
let the primary agent self-dispatch by phase (host-side orchestration; ctl only
governs the spawns — Division of labor preserved).

- .opencode/agent/{designer,oracle}.md: two new writable subagent roles
  (explore/build are opencode built-ins). designer = design/ADR/spec authoring;
  oracle = falsifiable diagnosis (no fix before a red-capable loop). Each carries
  a phase-tied `description` for autonomous dispatch and a behavioral prompt.
- control-guard SKILL: phase->role routing table; explore is the only read-only
  role, build/designer/oracle are writable and need an active in_progress task.
- six workflow skills: per-phase "Recommended role" annotations (platform
  section only — managed cores untouched).

explore stays the only read-only role, matching omp's gate classification
(verified: omp oracle is writable). Reviewed by an independent high-effort
code-review pass; 2 findings fixed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…floor

Add Step 1.5 to the ctl-spec-bootstrap skill: during project analysis, derive
the project-wide default gate floor and record it in .ctl/config.toml under
[project].default_gates. This is the floor ctl task create applies when a task
omits --gates (wired separately in task-create-gates).

Selection is by what gates catch, not a fixed per-language list:
- always include correctness gates (compile + test)
- include real-problem lint gates (clippy) when the project already uses them
- exclude auto-fixable formatting (cargo fmt --check) from the blocking floor
- no applicable ctl gate templates (Node/Python/Go/Java) -> leave it empty;
  never invent gate IDs. A later bootstrap fills these in.

For a Rust repo that lints with clippy the floor is check + test + clippy.
Writing is idempotent and asks before overwriting a user-tuned floor.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
ctl task create no longer requires --gates. When omitted, gates are derived
from [project].default_gates in .ctl/config.toml (recorded by /ctl-spec-bootstrap,
the bootstrap-project-gates half of this chain). ctl task quick uses the same
resolution instead of its hardcoded ["cargo_check","cargo_test"] default — there
is no hardcoded floor anywhere now.

When neither explicit --gates nor a project floor is present, both commands
error clearly (the application layer still enforces a non-empty gate set, so a
floorless project must pass --gates).

Config has no general TOML reader; add a minimal, targeted parser for the
[project].default_gates string array (single- and multi-line, comment-tolerant)
plus unit tests. Parsed gates are still validated against the gate-template list
by create_task, so a malformed entry surfaces as "unknown gate", never silent
misbehavior.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The blanket `.ctl` write protection blocked agents from writing
.ctl/config.toml, but /ctl-spec-bootstrap is supposed to record the
project default gate floor there ([project].default_gates). Without a
carve-out the bootstrap skill could never write the floor under
governance in a self-governed repo.

Add `.ctl/config.toml` alongside the existing `.ctl/workflow.md` /
`.ctl/scripts` carve-outs (AI-writable control-plane config). The
canonical ledger `.ctl/tasks` stays protected — guarded by the existing
ctl_tasks_still_protected_after_carveout test. The live gate already
allows a write when the path is in the active task's write_allow and
does not re-check is_protected, so this carve-out is sufficient: a task
can now scope .ctl/config.toml and write the floor.

Red->green: added accept_carveout_ctl_config_toml (failed while the path
was protected), then the carve-out (passes).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Policy change: the gate floor mirrors what the project already enforces,
so formatting checks (cargo_fmt_check) belong in it when the project
enforces formatting (CI runs fmt --check, or a fmt config ships) — they
were previously excluded as auto-fixable.

Update ctl-spec-bootstrap Step 1.5: the selection principle now includes
formatting gates under that condition, the template table marks
cargo_fmt_check "yes if the project enforces formatting", and the example
floor is all four cargo gates. This repo's own floor (.ctl/config.toml,
gitignored) is updated to match: check + test + clippy + fmt_check, which
mirrors its CI.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Reformat the project_gates_single_line test string that exceeded the line
width — pre-existing drift committed in ebf3153 before cargo_fmt_check was
a floor gate. Authorized out-of-scope edit under task floor-add-fmt-gate
(ctl apply/grant) since the new fmt gate cannot pass until the tree is
fmt-clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Answers the claude-subagent-dispatch research task: writing stays in the
main agent because (1) .claude defines no subagent roles to route to, and
(2) ctl binds a write to its task via CTL_TASK_ID, which subagents don't
inherit — and it's undocumented whether subagent tool calls even reach the
PreToolUse gate. Inline writes are the safe default, mirroring the Codex
dispatch_mode: inline decision already recorded in .ctl/config.yaml.

Recommendation: adopt read-only research dispatch now (safe); keep writes
inline by default; gate any writable .claude subagent on first verifying —
in a sandbox — whether subagent tool calls fire the gate. Basis is split
into observed / confirmed (docs, via claude-code-guide) / open uncertainty;
the blocking unknown is named, not hidden.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Agents were probing the ctl surface with --help command by command. Add a
ctl-cli-reference skill: the governed task lifecycle (create → ready →
start → submit → commit → gate → review → finish → archive) plus the
commands and key flags for gates, reviews, apply/approval exceptions,
evidence/provenance (research/uncertainty/brainstorm), inspection, and
recovery — the ~80% used daily, with `ctl <cmd> --help` as the fallback
for exhaustive flags. Includes the governance rules agents must know
(protected paths + carve-outs, commit window, independent-actor audit,
multiple_active binding, fail-closed gate).

Embedded via all_embedded_files so `ctl init` ships it (OMP-canonical,
like ctl-spec-bootstrap).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
ctl init previously only ever set up .omp/; the .claude/ and .opencode/
integrations were hand-authored and never embedded for injection. Add
platform selection:

- Embed the Claude Code integration (hooks/ctl-context.py, hooks/ctl-gate.py,
  settings.json) and the opencode integration (ctl-gate.ts plugin, designer +
  oracle agent roles, README, 7-skill mirror) as compiled-in files; opencode
  also gets a generated package.json. The research note subagent-dispatch.md
  and the plugin's .test.ts are excluded (task output / dev tests).
- inject_claude / inject_opencode write-if-absent (never clobber user files);
  inject_all (.omp) unchanged.
- `ctl init --platform <claude|opencode|omp|all>` dispatches to the chosen
  injector(s). With no flag: prompt interactively when attached to a TTY;
  in a non-interactive shell the flag is required (clear error). --dry-run
  reports the target without writing.

Tests: inject_claude/inject_opencode assert the shipped file set, the
exclusions, and idempotency.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude Code had governance hooks but no ctl workflow skills. Mirror the
core subset to .claude/skills/ in Claude Code format: 6 workflow-core
skills (grill, to-prd, to-tasks, tdd-loop, handoff, architecture-review)
+ cli-reference. The managed workflow-core and the shared phase body are
copied byte-identical from the OMP versions; only the integration section
differs (## Claude Code Integration: PreToolUse ctl gate, CTL_TASK_ID
binding, read-only subagent dispatch).

Drift wiring (the .claude copies are now first-class, not silently rotting):
- workflow_skills() gains 6 claude rows (marker "Claude Code Integration")
- workflow_phase_body() cuts at the Claude integration heading
- phase_body_is_identical_across_platforms asserts claude == omp too
- claude_embedded_files() ships the 7 skills; inject_claude test → 10 files

control-guard is split out (claude-control-guard-mirror) — it is coupled to
the adapter registry / adapter doctor and needs its own reconciliation.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add the read-only subagent dispatch routing (the claude-readonly-dispatch
-routing follow-up from the subagent-dispatch research) to the ctl-managed
CLAUDE.md block:
- dispatch read-only work (investigation, search, research, codebase Q&A)
  to read-only subagents (Explore, claude-code-guide) — they preserve
  context and cannot break scope;
- keep writes inline in the main agent, which alone carries CTL_TASK_ID and
  routes Write/Edit/Bash through the gate. Do not dispatch edits to
  subagents (isolated context, no CTL_TASK_ID, gate-reachability unverified).

Wired in two places, kept byte-identical so a bootstrap refresh is a no-op:
- ctl-spec-bootstrap M2 (the canonical managed-block content future runs emit)
- a CLAUDE.md at repo root (this repo's instance, previously absent)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add the first .claude/agents/ role: ctl-oracle, a READ-ONLY diagnostician
(Bayesian root-causing — falsifiable hypotheses, discriminating evidence,
"where is the evidence", observed/confirmed/uncertain split). tools: Read,
Grep, Glob, WebFetch — no Write/Edit/Bash. It returns a ranked diagnosis +
a recommended repro/fix for the MAIN agent to apply inline.

Read-only is the only safe dispatch today: a read-only role never writes, so
it sidesteps the unresolved question of whether subagent tool calls reach the
gate and the fact that subagents do not inherit CTL_TASK_ID. Writable roles
stay deferred until sandbox-verify-subagent-gate resolves U-001.

Embedded + shipped by inject_claude (now 11 files); the inject test asserts
the agent is present AND that its tools line grants no Write/Edit/Bash.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…m adapter

Add the control-guard entry/router skill to .claude/skills/control-guard:
control-guard-core copied byte-identical from OMP (drift-checked), with a
Claude-specific integration section that states the actual posture — the
.claude/hooks/ctl-gate.py PreToolUse enforcement, and READ-ONLY subagent
dispatch only (Explore / claude-code-guide / ctl-oracle), writes inline.
Writable roles stay deferred (host gate-reachability unverified).

Decouple "platform" from "adapter" so Claude can host a drift-checked
control-guard without being a (non-existent) executor adapter:
- PlatformSkill.adapter becomes Option<&str>; the claude row is None.
- platform_skill_for matches Some(adapter), so adapter_doctor (which only
  iterates SUPPORTED_ADAPTERS = omp, opencode) never looks claude up, while
  the control-guard drift tests iterate every row and now cover claude.
SUPPORTED_ADAPTERS is unchanged (its tripwire test stays green); adapter
doctor output is unchanged (verified: still omp + opencode only).

Embedded + shipped by inject_claude (now 12 files); .claude/hooks added to
the control-guard PLATFORM_TOKENS leak-check.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Stop hand-mirroring the 6 workflow skills across 3 platforms. Each now has
ONE source at .agent/skills/<skill>/source.md (frontmatter + shared phase
body + per-platform integration sections). `ctl skills sync` composes every
platform's SKILL.md from: frontmatter + a generated preamble + the canonical
managed core (.agent/protocols/workflow-skills.md, wrapped) + the shared body
+ the platform integration. `ctl skills sync --check` re-derives and fails on
any on-disk drift; the every_workflow_skill_is_in_sync_on_disk test runs it
under cargo test, so CI catches a stale generated file.

The core stays byte-identical to canonical and the body identical across
platforms BY CONSTRUCTION (one source), so the manual copy + drift-authoring
is gone (the existing drift tests remain as belt-and-suspenders and still pass).

Fixes a real bug the hand-copy introduced: the .claude workflow skills'
preamble said "# <skill> (OMP)" / "OMP-specific mechanics" (I had copied the
.omp prefix verbatim, and the drift tests only check the core + body, not the
preamble). Generation emits the correct per-platform preamble.

control-guard is intentionally NOT generated here — its frontmatter is
per-platform and it has no phase body; it stays hand-authored under
control_guard_protocol_sync.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@neostfox
neostfox merged commit df0784f into master Jun 19, 2026
2 of 4 checks passed
neostfox added a commit that referenced this pull request Jul 26, 2026
Fold the accumulated gate-lifecycle doc drift in AGENTS.md + README.md into
one refresh pass (all gate-related, same two files):

- AGENTS Key Conventions #4 (gate allowlist): built-in templates are EXTENDED
  by project-defined [[gate]] templates in .ctl/config.toml (gh5 / issue #5);
  built-in ids reserved, collisions rejected at load.
- AGENTS #7 (gate observe mode): out-of-scope bash file-mutating commands with
  statically-identifiable targets are now DENIED, not observed (best-effort
  classifier, gh7 / issue #7); obfuscated commands still fall through.
- AGENTS + README command lists: add 'approve' (human-only ready, gh6
  proposal-mode Design A).

AGENTS edits are inside the TRELLIS-managed block - re-apply after trellis
update. Doc-only; ctl Rust unchanged.

Resolves gh5-doc-gate-list-refresh (and folds the gh6/gh7 doc drift).
neostfox added a commit that referenced this pull request Jul 26, 2026
…cript

Updates the V1 cognitive-layer bullet (ctl spec fact ✅ -> 'knowledge/memory layer
externalized'), the memory-carrier table (atomic facts writer is now
scripts/knowledge.py fact add), marks #1/S + #2/S done, and reframes the remaining
memory-system backlog (#3/#4/#5/#6) to target scripts/knowledge.py instead of the
removed ctl memory / ctl spec fact commands — consistent with the decision that
ctl Rust stays governance-only and the knowledge layer is workflow-side.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant