Skip to content
Merged

Dev #22

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions .claude/skills/gov/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,12 +94,12 @@ The active work item is durable outcome context. Read it with `govctl work show

### Loop usage

Use a loop only when a task has multiple independently meaningful work items. A loop coordinates durable work; it is not permission to split one cleanup/refactor into mechanical work-item fragments.
Use a loop for non-trivial governed execution that needs local execution memory. This includes single-Work-Item work now that transient journal-style execution trace belongs in loop state and round artifacts. Multi-Work-Item loops add dependency and batch coordination; they are not permission to split one cleanup/refactor into mechanical work-item fragments.

1. Create or activate only the work items that represent durable outcomes a future reader should see.
2. Add `depends_on` edges for hard execution ordering.
3. Run `govctl check` so dependency cycles or missing work item IDs are caught before the loop starts.
4. Start one loop for the batch root set with `govctl loop start <ROOT-WI-ID> [<ROOT-WI-ID>...]`; let govctl generate the `LOOP-YYYY-MM-DD-NNN` ID.
4. Start one loop for the root set with `govctl loop start <ROOT-WI-ID> [<ROOT-WI-ID>...]`; let govctl generate the `LOOP-YYYY-MM-DD-NNN` ID.
5. Run `govctl loop run <LOOP-ID>` to open a local round for ready work.
6. Perform implementation, verification, and any explicit `govctl work move` commands yourself.
7. Fill the opened `.govctl/loops/<LOOP-ID>/rounds/round-NNN.toml` summary evidence.
Expand All @@ -117,7 +117,7 @@ If the scope changes during execution, keep the same loop identity:

`work` is the editable loop work-item field. `wi` is accepted as a short alias, but examples should prefer `work`.

Do not create scattered single-item loops for work that is part of one coherent batch.
Do not create multiple scattered loops for work that belongs in one coherent execution session.

Do not create separate work items for low-level implementation slices such as helper moves, test fixture sharing, module normalization, comment cleanup, snapshot reshaping, or other changes whose only durable record should be the commit diff or one higher-level work item.

Expand Down Expand Up @@ -145,7 +145,7 @@ govctl work list pending

- Matching active item: use it
- Matching queued item: `govctl work move <WI-ID> active`
- No match and the task has one durable outcome: `govctl work new --active "<concise-title>"`
- No match and the task has one durable outcome: `govctl work new --active "<concise-title>"`, then start a loop if the work is non-trivial
- No match and the task has multiple independently reviewable durable outcomes: create that small batch first, wire only hard `depends_on` edges, then start one generated-ID loop for the batch.
- No match and the apparent split is only mechanical implementation steps: create at most one coarse work item, or route trivial cleanup to `/quick`.

Expand Down
3 changes: 2 additions & 1 deletion .claude/skills/wi-writer/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,8 @@ Create multiple work items only when each item is independently meaningful to fu
- For trivial cleanup or docs-only edits, no work item may be the right answer; follow the invoking workflow instead of inventing tracking.
- For one coherent cleanup/refactor, prefer one coarse work item over many narrow slices.
- Use `depends_on` only for hard execution ordering; keep `refs` for informational links.
- Use one batch loop only when there are multiple durable work items; do not use loops to justify creating mechanical work-item fragments.
- Use a loop for non-trivial governed execution that needs local execution memory, including single-work-item execution after journal-style trace moved out of Work Item fields.
- Use one multi-work-item loop only when there are multiple durable work items; do not use loops to justify creating mechanical work-item fragments.
- Let govctl generate the loop ID with `govctl loop start <ROOT-WI-ID> [<ROOT-WI-ID>...]`; use the returned `LOOP-YYYY-MM-DD-NNN` ID for later loop commands.
- Use `govctl loop list open` to discover existing non-terminal loops before resuming interrupted batch work.

Expand Down
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,21 @@ Release entries are curated summaries for readers. Work item traceability remain

## [Unreleased]

### Added

- loop list and show expose stale loop plans without mutating local state (WI-2026-06-09-001)

### Changed

- Writer skills include matching authority tests and examples so authors avoid boundary drift before review (WI-2026-06-07-005)
- Reviewer agents include explicit boundary probes and boundary finding output for RFC, ADR, and Work Item reviews (WI-2026-06-07-005)
- init-skills installs full skill directory bundles, including bundled references and assets (WI-2026-06-08-002)

### Fixed

- cargo-binstall Windows override resolves to govctl-v{ version }-{ target }.zip (WI-2026-06-08-001)
- cargo-binstall Unix pkg-url resolves to govctl-v{ version }-{ target }.tar.gz (WI-2026-06-08-001)
- loop run rejects stale stored dependency closures before opening new work (WI-2026-06-09-001)

## [0.9.3] - 2026-06-07

Expand Down
4 changes: 3 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -99,12 +99,14 @@ insta = { version = "1", features = ["yaml"] }
regex = "1"
chrono = "0.4"

# [[ADR-0041]] governs package.metadata.binstall archive naming, including the Windows override in package.metadata.binstall.overrides.x86_64-pc-windows-msvc.
[package.metadata.binstall]
pkg-url = "{ repo }/releases/download/v{ version }/govctl-v{ version }-{ target }.{ archive-format }"
pkg-url = "{ repo }/releases/download/v{ version }/govctl-v{ version }-{ target }.tar.gz"
bin-dir = "govctl-v{ version }-{ target }/{ bin }{ binary-ext }"
pkg-fmt = "tgz"

[package.metadata.binstall.overrides.x86_64-pc-windows-msvc]
pkg-url = "{ repo }/releases/download/v{ version }/govctl-v{ version }-{ target }.zip"
pkg-fmt = "zip"
Comment thread
coderabbitai[bot] marked this conversation as resolved.

[lints.clippy]
Expand Down
101 changes: 83 additions & 18 deletions build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,36 +11,101 @@ use edit_ops_spec::{
};
use std::error::Error;
use std::fs;
use std::path::Path;
use std::path::{Path, PathBuf};

// Project-local assets installed by `govctl init-skills`.
// Plugin/global-only skills such as `init` are intentionally omitted. [[RFC-0002:C-GLOBAL-COMMANDS]]
const DISTRIBUTED_SKILL_DIRS: &[&str] = &[
"discuss",
"gov",
"quick",
"spec",
"rfc-writer",
"adr-writer",
"wi-writer",
"guard-writer",
"commit",
"migrate",
"decision-analysis",
"detach",
];

fn main() {
// Recompile if any embedded .claude/ assets change
// Skills
println!("cargo:rerun-if-changed=.claude/skills/discuss/SKILL.md");
println!("cargo:rerun-if-changed=.claude/skills/gov/SKILL.md");
println!("cargo:rerun-if-changed=.claude/skills/quick/SKILL.md");
println!("cargo:rerun-if-changed=.claude/skills/spec/SKILL.md");
println!("cargo:rerun-if-changed=.claude/skills/rfc-writer/SKILL.md");
println!("cargo:rerun-if-changed=.claude/skills/adr-writer/SKILL.md");
println!("cargo:rerun-if-changed=.claude/skills/wi-writer/SKILL.md");
println!("cargo:rerun-if-changed=.claude/skills/commit/SKILL.md");
println!("cargo:rerun-if-changed=.claude/skills/migrate/SKILL.md");
println!("cargo:rerun-if-changed=.claude/skills/decision-analysis/SKILL.md");
println!("cargo:rerun-if-changed=.claude/skills/detach/SKILL.md");
// Agents
println!("cargo:rerun-if-changed=.claude/agents/rfc-reviewer.md");
println!("cargo:rerun-if-changed=.claude/agents/adr-reviewer.md");
println!("cargo:rerun-if-changed=.claude/agents/wi-reviewer.md");
println!("cargo:rerun-if-changed=.claude/agents/compliance-checker.md");
println!("cargo:rerun-if-changed=.claude/skills");
println!("cargo:rerun-if-changed=.claude/agents");

// Edit rules SSOT + schema (ADR-0030)
println!("cargo:rerun-if-changed=gov/schema/edit-ops.schema.json");
println!("cargo:rerun-if-changed=gov/schema/edit-ops.json");

generate_skill_assets().expect("failed to generate skill asset manifest");
generate_edit_rules().expect("failed to generate edit rules from SSOT");
generate_codex_agent_templates().expect("failed to generate codex agent templates");
}

fn generate_skill_assets() -> Result<(), Box<dyn Error>> {
let skill_root = Path::new(".claude/skills");
let mut files = Vec::new();
for skill_dir in DISTRIBUTED_SKILL_DIRS {
collect_files(&skill_root.join(skill_dir), &mut files)?;
}
files.sort();

let mut out = String::new();
out.push_str("// @generated by build.rs from distributed .claude/skills/* bundles\n");
out.push_str("// Do not edit manually.\n\n");
out.push_str("pub const SKILL_ASSETS: &[(&str, &str)] = &[\n");
for file in files {
let skill_rel = file
.strip_prefix(skill_root)
.map_err(|e| format!("failed to relativize skill asset {}: {e}", file.display()))?;
let skill_rel = path_to_slash_string(skill_rel)?;
let output_rel = format!("skills/{skill_rel}");
let source_rel = format!("/.claude/skills/{skill_rel}");
out.push_str(&format!(
" ({:?}, include_str!(concat!(env!(\"CARGO_MANIFEST_DIR\"), {:?}))),\n",
output_rel, source_rel
));
}
out.push_str("];\n");

let out_dir = std::env::var("OUT_DIR")?;
let out_path = Path::new(&out_dir).join("skill_assets.rs");
fs::write(out_path, out)?;
Ok(())
}

fn collect_files(root: &Path, files: &mut Vec<PathBuf>) -> Result<(), Box<dyn Error>> {
for entry in
fs::read_dir(root).map_err(|e| format!("failed to read {}: {e}", root.display()))?
{
let entry = entry?;
let path = entry.path();
let file_type = entry.file_type()?;
if file_type.is_dir() {
collect_files(&path, files)?;
} else if file_type.is_file() {
files.push(path);
}
}
Ok(())
}

fn path_to_slash_string(path: &Path) -> Result<String, Box<dyn Error>> {
let mut parts = Vec::new();
for component in path.components() {
let component = component.as_os_str().to_str().ok_or_else(|| {
format!(
"skill asset path is not valid UTF-8: {}",
path.to_string_lossy()
)
})?;
parts.push(component.to_string());
}
Ok(parts.join("/"))
}

fn generate_edit_rules() -> Result<(), Box<dyn Error>> {
let spec_path = Path::new("gov/schema/edit-ops.json");
let schema_path = Path::new("gov/schema/edit-ops.schema.json");
Expand Down
8 changes: 6 additions & 2 deletions docs/guide/recommended-workflows.md
Original file line number Diff line number Diff line change
Expand Up @@ -120,8 +120,8 @@ Moving to `done` runs verification guards when verification is enabled.

## When To Use Loops

Use a loop when execution is bigger than one simple Work Item or when you need
resumable local round evidence.
Use a loop when non-trivial execution needs resumable local round evidence,
including single-Work-Item work.

Good loop use cases:

Expand Down Expand Up @@ -160,6 +160,10 @@ govctl loop remove LOOP-YYYY-MM-DD-NNN work WI-YYYY-MM-DD-002
govctl loop replan LOOP-YYYY-MM-DD-NNN
```

If `loop show` or `loop list` reports a stale plan, the current Work Item
dependency closure differs from the stored loop plan. Run `govctl loop replan
LOOP-YYYY-MM-DD-NNN` before opening another round.

Loop state is local execution memory under `.govctl/loops/`. Work Items remain
the durable task record.

Expand Down
17 changes: 13 additions & 4 deletions docs/rfc/RFC-0002.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
<!-- GENERATED: do not edit. Source: RFC-0002 -->
<!-- SIGNATURE: sha256:f77cd633c97a2b62f7d830fdb04bb0de811727ebe2c3d9abfdc2dd9c4983eed7 -->
<!-- SIGNATURE: sha256:dd126a9195850f89dbb0ba90abee032ce072eb83017a465fd798276b9a7dbd3f -->

# RFC-0002: CLI Resource Model and Command Architecture

> **Version:** 0.10.1 | **Status:** normative | **Phase:** test
> **Version:** 0.10.2 | **Status:** normative | **Phase:** test

---

Expand Down Expand Up @@ -552,8 +552,9 @@ Syntax: `govctl init-skills [--force] [--format <claude|codex>] [--dir PATH]`
Behavior:
- `--dir` overrides the output directory for this invocation. Resolution order: `--dir` flag > `agent_dir` from config > format-implied default (`.claude` for claude, `.codex` for codex)
- `--format` selects the output format for agent definitions (default `claude`):
- `claude`: skills as `skills/*/SKILL.md`, agents as `agents/*.md` with YAML frontmatter (compatible with Claude Code, Cursor, Windsurf, and similar editors)
- `codex`: skills as `skills/*/SKILL.md` (same format), agents as `agents/*.toml` with `developer_instructions` field (compatible with Codex CLI)
- `claude`: skills as full `skills/*/` bundles rooted at `SKILL.md`, agents as `agents/*.md` with YAML frontmatter (compatible with Claude Code, Cursor, Windsurf, and similar editors)
- `codex`: skills as full `skills/*/` bundles rooted at `SKILL.md` (same format), agents as `agents/*.toml` with `developer_instructions` field (compatible with Codex CLI)
- Skill bundle resources under directories such as `references/`, `assets/`, and `scripts/` MUST be installed with their parent skill; agent output remains format-specific
- Skips files that already exist unless `--force` is used
- Reports created/updated/skipped counts
- This command is separate from `init` because plugin users receive skills globally and do not need local copies
Expand Down Expand Up @@ -731,6 +732,14 @@ Search is discovery across the governance corpus, not a resource-specific CRUD o

## Changelog

### v0.10.2 (2026-06-08)

Clarify init-skills skill bundle installation

#### Changed

- init-skills installs full skill bundles rooted at SKILL.md, including bundled references/assets/scripts

### v0.10.1 (2026-06-04)

Set search clause version metadata
Expand Down
5 changes: 3 additions & 2 deletions gov/rfc/RFC-0002/clauses/C-GLOBAL-COMMANDS.toml
Original file line number Diff line number Diff line change
Expand Up @@ -150,8 +150,9 @@ Syntax: `govctl init-skills [--force] [--format <claude|codex>] [--dir PATH]`
Behavior:
- `--dir` overrides the output directory for this invocation. Resolution order: `--dir` flag > `agent_dir` from config > format-implied default (`.claude` for claude, `.codex` for codex)
- `--format` selects the output format for agent definitions (default `claude`):
- `claude`: skills as `skills/*/SKILL.md`, agents as `agents/*.md` with YAML frontmatter (compatible with Claude Code, Cursor, Windsurf, and similar editors)
- `codex`: skills as `skills/*/SKILL.md` (same format), agents as `agents/*.toml` with `developer_instructions` field (compatible with Codex CLI)
- `claude`: skills as full `skills/*/` bundles rooted at `SKILL.md`, agents as `agents/*.md` with YAML frontmatter (compatible with Claude Code, Cursor, Windsurf, and similar editors)
- `codex`: skills as full `skills/*/` bundles rooted at `SKILL.md` (same format), agents as `agents/*.toml` with `developer_instructions` field (compatible with Codex CLI)
- Skill bundle resources under directories such as `references/`, `assets/`, and `scripts/` MUST be installed with their parent skill; agent output remains format-specific
- Skips files that already exist unless `--force` is used
- Reports created/updated/skipped counts
- This command is separate from `init` because plugin users receive skills globally and do not need local copies
Expand Down
12 changes: 9 additions & 3 deletions gov/rfc/RFC-0002/rfc.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,20 @@
[govctl]
id = "RFC-0002"
title = "CLI Resource Model and Command Architecture"
version = "0.10.1"
version = "0.10.2"
status = "normative"
phase = "test"
owners = ["@govctl-org"]
created = "2026-01-19"
updated = "2026-06-04"
updated = "2026-06-08"
tags = [
"cli",
"editing",
"lifecycle",
"validation",
"release",
]
signature = "681093335724498e211e93fb519c9e16f9990da7986a2f50db914b9e60e88339"
signature = "dd126a9195850f89dbb0ba90abee032ce072eb83017a465fd798276b9a7dbd3f"

[[sections]]
title = "Summary"
Expand All @@ -36,6 +36,12 @@ clauses = [
"clauses/C-SEARCH-COMMAND.toml",
]

[[changelog]]
version = "0.10.2"
date = "2026-06-08"
notes = "Clarify init-skills skill bundle installation"
changed = ["init-skills installs full skill bundles rooted at SKILL.md, including bundled references/assets/scripts"]

[[changelog]]
version = "0.10.1"
date = "2026-06-04"
Expand Down
31 changes: 31 additions & 0 deletions gov/work/2026-06-08-fix-cargo-binstall-unix-asset-suffix.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#:schema ../schema/work.schema.json

[govctl]
id = "WI-2026-06-08-001"
title = "Fix cargo-binstall Unix asset suffix"
status = "done"
created = "2026-06-08"
started = "2026-06-08"
completed = "2026-06-08"
refs = [
"ADR-0041",
"RFC-0002",
]

[content]
description = "Align cargo-binstall metadata with the actual GitHub Release asset names: Unix release archives are uploaded as .tar.gz files while cargo-binstall pkg-fmt remains tgz for extraction semantics, so the metadata must not expand to .tgz URLs."

[[content.acceptance_criteria]]
text = "release metadata regression tests pass"
status = "done"
category = "chore"

[[content.acceptance_criteria]]
text = "cargo-binstall Windows override resolves to govctl-v{ version }-{ target }.zip"
status = "done"
category = "fixed"

[[content.acceptance_criteria]]
text = "cargo-binstall Unix pkg-url resolves to govctl-v{ version }-{ target }.tar.gz"
status = "done"
category = "fixed"
29 changes: 29 additions & 0 deletions gov/work/2026-06-08-support-bundled-skill-installation.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#:schema ../schema/work.schema.json

[govctl]
id = "WI-2026-06-08-002"
title = "Support bundled skill installation"
status = "done"
created = "2026-06-08"
started = "2026-06-08"
completed = "2026-06-08"
refs = [
"ADR-0024",
"ADR-0028",
"ADR-0035",
"RFC-0002",
]
tags = ["skills-agents"]

[content]
description = "Support skill directory bundles so init-skills installs all files under explicitly distributed skill roots instead of relying on SKILL.md-only template entries."

[[content.acceptance_criteria]]
text = "init-skills installs full skill directory bundles, including bundled references and assets"
status = "done"
category = "changed"

[[content.acceptance_criteria]]
text = "govctl check and relevant tests pass"
status = "done"
category = "chore"
Loading
Loading