diff --git a/.cursorrules b/.cursorrules new file mode 100644 index 0000000..2302ec4 --- /dev/null +++ b/.cursorrules @@ -0,0 +1,24 @@ +# Unbound Force — managed by uf init + +This project follows coding conventions defined in +AGENTS.md and enforced through convention packs. Before +writing or reviewing code, read the applicable convention +pack(s) from .opencode/uf/packs/ and apply all rules +marked [MUST]. + +Available packs: +- .opencode/uf/packs/default.md +- .opencode/uf/packs/severity.md +- .opencode/uf/packs/content.md +- .opencode/uf/packs/go.md + +For engineering philosophy and coding principles, read +.opencode/agents/cobalt-crush-dev.md. + +When reviewing code, consult the applicable reviewer +checklist from .opencode/agents/: +- divisor-guard.md — intent drift, constitution +- divisor-architect.md — structure, patterns, DRY +- divisor-adversary.md — security, error handling +- divisor-testing.md — test quality, assertions +- divisor-sre.md — operations, performance diff --git a/.opencode/agents/background-worker.md b/.opencode/agents/background-worker.md new file mode 100644 index 0000000..c4454f3 --- /dev/null +++ b/.opencode/agents/background-worker.md @@ -0,0 +1,24 @@ +--- +name: background-worker +description: Runs background tasks without MCP tool access. +mode: subagent +hidden: true +--- + +# Background Worker + +For tasks that don't need MCP tools: doc edits, formatting, summaries. + +## Constraints + +- No MCP tools available +- No file reservations +- No comms messaging +- Use for static content only + +## Suitable Tasks + +- Documentation updates +- Code formatting +- Report generation +- Static analysis summaries diff --git a/.opencode/agents/coordinator.md b/.opencode/agents/coordinator.md new file mode 100644 index 0000000..ba0b590 --- /dev/null +++ b/.opencode/agents/coordinator.md @@ -0,0 +1,22 @@ +--- +name: coordinator +description: Orchestrates forge coordination and supervises worker agents. +mode: subagent +--- + +# Forge Coordinator + +Orchestrates work: decomposes tasks, spawns workers, monitors progress, reviews results. + +## Rules + +- Always initialize comms first (`comms_init`) +- Never reserve files (workers reserve their own) +- Review every worker completion (`forge_review`) +- Store learnings after forge completion (`hivemind_store`) +- Check inbox regularly for blocked workers (`comms_inbox`) +- Use `forge_broadcast` to share context updates with all workers + +## Available Tools + +All `org_*`, `comms_*`, `forge_*`, and `hivemind_*` tools. diff --git a/.opencode/agents/worker.md b/.opencode/agents/worker.md new file mode 100644 index 0000000..d1d189f --- /dev/null +++ b/.opencode/agents/worker.md @@ -0,0 +1,27 @@ +--- +name: worker +description: Executes a single subtask with file reservations and progress reporting. +mode: subagent +hidden: true +--- + +# Forge Worker + +Executes scoped subtasks and reports to coordinator. + +## Checklist + +1. `comms_init` — initialize comms first +2. `hivemind_find` — check for prior learnings before coding +3. `comms_reserve` — reserve assigned files exclusively +4. Implement changes to reserved files +5. `forge_progress` — report at 25%, 50%, 75% milestones +6. `hivemind_store` — store any learnings discovered +7. `forge_complete` — mark subtask as done + +## Constraints + +- Only edit files you have reserved +- Report progress at regular intervals +- Store learnings for future agents +- Never modify files outside your assignment diff --git a/.opencode/commands/address-feedback.md b/.opencode/commands/address-feedback.md new file mode 100644 index 0000000..f44c40c --- /dev/null +++ b/.opencode/commands/address-feedback.md @@ -0,0 +1,495 @@ +--- +description: "Triage and address PR review feedback with structured assessment" +--- + + + +# Address Feedback + +You are a token-efficient feedback analyst. The user will provide a PR number or you will auto-detect it from the current branch. Fetch all unresolved review feedback from GitHub, classify each item with evidence from project standards, present to the author for triage, then execute decisions as a batch: group related fixes into logical commits, review-council gate, push, reply comments, and artifact production. + +The command follows four sequential phases (Ingest → Assess → Triage → Execute). Phases are not independently invocable — run all four in sequence every invocation. + +## Arguments + +- **PR number** (optional): The pull request number to address feedback for (e.g., `42`). If omitted, auto-detect the open PR for the current branch. + +**Argument parsing** (before any tool calls): Check the user's message for a PR number argument. If present, set `PR_NUMBER` to that value immediately. All subsequent steps use `` — no auto-detection commands are needed or permitted. + +--- + +## Phase 1: Ingest + +Fetch all review feedback from GitHub and build the item list. + +### 1.0 Prerequisites + +Verify the `gh` CLI is available and authenticated: + +```bash +which gh +``` + +If not found: **STOP** with error: +> "`gh` CLI is not installed. Install with +> `dnf install gh` (Fedora/RHEL), +> `brew install gh` (macOS), or see +> https://cli.github.com/ for other platforms." + +```bash +gh auth status +``` + +If not authenticated: **STOP** with error: +> "GitHub CLI not authenticated. Run `gh auth login` to authenticate." + +### 1.1 Resolve PR Number + +**If `PR_NUMBER` was already set from the argument**: skip this step entirely. Do NOT run `gh pr view` or any branch detection. + +**Only if no PR number was provided**: + +```bash +gh pr view --json number --jq '.number' +``` + +If no open PR: **STOP** with error: +> "No open PR found for the current branch. Specify a PR number: `/address-feedback 42`" + +### 1.2 Fetch PR Metadata + +```bash +gh pr view --json number,url,title,body,headRefName,baseRefName,author +``` + +Record PR number, URL, branch name, description (for linked issue parsing), and author login (to filter self-comments). + +### 1.3 Fetch Reviews and Comments + +Determine `{owner}/{repo}` from `gh repo view --json owner,name --jq '.owner.login + "/" + .name'`. + +Fetch all three data sources. Handle pagination — append `--paginate` or follow `Link` headers to ensure complete data: + +```bash +# Reviews (approval state + inline comments) +gh api repos/{owner}/{repo}/pulls//reviews --paginate + +# Review comments (inline, threaded) +gh api repos/{owner}/{repo}/pulls//comments --paginate + +# Issue comments (general PR-level) +gh api repos/{owner}/{repo}/issues//comments --paginate +``` + +**On API failure** (network error, HTTP 5xx, 403 rate limit): report the specific error and **STOP**. Do NOT proceed with partial data. If 403, suggest: +> "GitHub API error (403): rate limit exceeded. Wait and retry." + +### 1.4 Determine Reviewer Authority + +For each reviewer, map `author_association` to authority tier: + +| `author_association` | Authority | +|---|---| +| `OWNER`, `MEMBER` | maintainer | +| `COLLABORATOR` | collaborator | +| `CONTRIBUTOR`, `FIRST_TIMER`, `FIRST_TIME_CONTRIBUTOR` | contributor | +| `NONE` (no bot indicators) | external | +| `NONE` (bot indicators) | bot | + +**Bot detection**: login ending in `[bot]` OR account `type` is `Bot`. + +### 1.5 Filter and Group + +**Filter out**: +- Already-resolved review threads (check `isResolved` or thread state) +- The PR author's own top-level comments +- Pure approval reviews with no inline comments + +**Group**: Threaded conversations (a review comment and its replies) into a single feedback item. The assessment considers the latest state of the full thread, not just the opening comment. + +**Detect**: GitHub suggestion blocks (` ```suggestion `) — preserve as structured data for the triage phase. + +### 1.6 Cache Check + +Check local cache at `.uf/feedback/pr-/state.json`: + +- **Cache exists, thread unchanged** (same comment count, same last comment ID): reuse cached assessment — skip Assess for this item +- **Cache exists, thread has new comments**: mark cached assessment stale — re-assess +- **Cache exists, code at referenced lines changed** (compare current file content at line range against cached content): mark stale — re-assess +- **Thread resolved on GitHub since last run**: skip entirely +- **Cache missing**: assess from scratch (correct but slower) + +On crash-recovery re-entry: items marked as fully executed (`comment-posted`) in the cache MUST be skipped to prevent duplicate comments. + +If no items remain after filtering: report "No unresolved feedback to address" and **STOP**. + +--- + +## Phase 2: Assess + +Classify each feedback item with evidence and produce a recommendation. + +### 2.1 Load Project Context + +Load context for evidence-based classification (D10, FR-010): + +1. Convention packs from `.opencode/uf/packs/*.md` +2. Constitution from `.specify/memory/constitution.md` +3. `AGENTS.md` coding and testing conventions +4. Spec artifacts for the PR branch: + - Speckit: `specs/NNN-*/` matching branch pattern + - OpenSpec: `openspec/changes/*/` matching branch +5. Linked issues from PR description (`Fixes #N`, `Closes #N`, `Resolves #N`) — load acceptance criteria +6. Invoke the `skill` tool with name `review-context` to load standardized context discovery (spec artifacts, linked issues, path classification). + +### 2.2 Tiered Assessment + +For each feedback item, determine the assessment tier: + +**Tier 1 (direct)** — assess using loaded context when ALL conditions are met: +- Single file affected +- Clear match to a convention pack rule (or purely subjective, no rule applies) +- No security implications +- No architectural implications +- Reviewer feedback and project standards do not conflict + +**Tier 2 (Divisor escalation)** — delegate to the relevant Divisor agent via Task tool when ANY condition is met: +- Security concern raised → `divisor-adversary` +- Architectural change suggested → `divisor-architect` +- Multi-file impact → `divisor-architect` +- Feedback contradicts a convention pack rule → `divisor-guard` +- Ambiguous classification → route by primary domain +- Test strategy or coverage concern → `divisor-testing` +- Performance or operational concern → `divisor-sre` +- Multiple domains → invoke multiple agents in parallel + +**Fallback**: If no Divisor agents are available (not deployed), all items fall back to Tier 1. Set `tier2_unavailable: true` in the assessment output. + +### 2.3 Classify Each Item + +For each item, produce: + +| Field | Value | +|---|---| +| **Classification** | `DATA-DRIVEN` or `SUBJECTIVE` | +| **Evidence** | Specific convention pack section, constitution principle, or coding standard reference | +| **Reviewer authority** | maintainer / collaborator / contributor / external / bot | +| **Recommendation** | `ACCEPT` or `AUTHOR-DECIDES` (from authority matrix below) | +| **Suggested approach** | Concrete implementation description (if recommendation is ACCEPT) | +| **Conflict flag** | True if another item provides contradictory guidance on overlapping file/line range | + +**Classification rules**: +- `DATA-DRIVEN`: grounded in a verifiable project rule (convention pack, constitution, coding standard, lint rule) or identifies a demonstrable defect (logic error, missing error handling, security vulnerability) +- `SUBJECTIVE`: personal preference, stylistic choice, or alternative approach not mandated by project rules + +### 2.4 Apply Authority Matrix + +| Authority | Data-Driven | Subjective | +|---|---|---| +| Maintainer | ACCEPT (MUST fix) | AUTHOR-DECIDES (SHOULD consider) | +| Collaborator | ACCEPT (MUST fix) | AUTHOR-DECIDES | +| Contributor | ACCEPT (MUST fix) | AUTHOR-DECIDES | +| External | ACCEPT if validated | AUTHOR-DECIDES | +| Bot | ACCEPT if validated | AUTHOR-DECIDES (informational) | + +**Bot/external validation**: cross-reference the finding against project convention packs. If the pack confirms the rule → ACCEPT. If no matching rule → AUTHOR-DECIDES with note that the rule is not backed by project standards. + +### 2.5 Conflict Detection + +Compare items referencing overlapping file and line ranges. If two or more items provide contradictory guidance for the same code section, flag both with `CONFLICT`. Present conflicting items together in Phase 3 so the author can choose one approach. + +### 2.6 Cache Assessment Results + +Write assessment results to `.uf/feedback/pr-/state.json`: +- Per-thread: classification, tier, evidence, recommendation, comment count, last comment ID, content snapshot at referenced lines +- Timestamp: ISO 8601 last-fetched time + +**Permissions**: files `600`, directories `700`. + +--- + +## Phase 3: Triage + +Present each item to the author one-by-one for a decision. + +### 3.1 Present Items + +For each feedback item, display: + +``` +─── Item N of M ────────────────────────── +Reviewer: @ () +File: : (or "General PR comment") +Classification: +Evidence: +Recommendation: +Conflict: +Tier: <1|2> <(Divisor agents: ...)> + +── Thread ── + + +── Suggested Approach ── + +───────────────────────────────────────── +``` + +If the item has a GitHub suggestion block, display it clearly as an applicable code change. + +### 3.2 Author Decision + +For each item, use the **AskUserQuestion tool** with +options `["Accept", "Modify", "Reject", "Ask"]`. The +author chooses exactly one: + +| Decision | Follow-up | Queued action | +|---|---|---| +| **Accept** | (none) | Code change using suggested approach | +| **Modify** | Use **AskUserQuestion tool** (open-ended, no preset options) to collect the alternative approach | Code change using author's approach | +| **Reject** | Use **AskUserQuestion tool** (open-ended, no preset options) to collect evidence-based reasoning | Reply comment with reasoning | +| **Ask** | Use **AskUserQuestion tool** (open-ended, no preset options) to collect the clarification question | Reply comment with question | + +**No item may be skipped or deferred.** Every item MUST receive a decision before the triage phase completes. + +### 3.3 Conflicting Items + +When presenting items flagged with CONFLICT, present both conflicting items together. The author chooses one approach. The non-chosen reviewer receives a reply comment explaining the decision. + +### 3.4 Triage Summary + +After all items are decided, display a summary: + +``` +─── Triage Summary ────────────────────── +ACCEPT: N items (code changes queued) +MODIFY: N items (code changes queued) +REJECT: N items (reply comments queued) +ASK: N items (reply comments queued) +Total: N items +───────────────────────────────────────── +``` + +List each item with its decision. Use the +**AskUserQuestion tool** with options `["Confirm -- +proceed with execution", "Revise -- change decisions"]` +before execution proceeds. + +--- + +## Phase 4: Execute + +Implement all queued actions as a batch. + +### 4.1 Implement Code Changes + +For each ACCEPT and MODIFY item, implement the code change: +- ACCEPT: apply the suggested approach +- MODIFY: apply the author's alternative approach +- GitHub suggestion blocks: apply the exact suggestion diff + +**If a code change cannot be applied cleanly** (e.g., referenced code has changed since the review): skip that item with a clear report, note the failure for the reply comment, and continue with remaining items. + +### 4.2 Commit Changes + +Group related fixes into logical commits. For example, multiple naming changes in the same file or related error-handling fixes across a package belong together. Unrelated fixes get separate commits. Use conventional commit format: + +``` +fix(): + +Addresses PR # review feedback from @. + +Signed-off-by: +Assisted-by: +``` + +Where `` is the model family name you are +currently running as. To resolve the model name: +(1) read your model identifier from the system prompt +or runtime environment; (2) remove everything before +and including the last `/`; (3) remove everything +after and including the first `@`; (4) remove any +trailing date suffix matching `-YYYYMMDD` (a hyphen +followed by exactly 8 digits); (5) repeatedly remove +any trailing version segment matching `-N` (a hyphen +followed by a single digit at the end) until no more +remain; (6) validate the result +contains only `[a-zA-Z0-9._-]` characters. If the +result is empty, contains invalid characters, or +cannot be determined, use the literal string +`unknown-model` and warn the user (e.g., "Could not +determine AI model name — using 'unknown-model' in +attribution"). + +The `` is the package or directory of the changed files. The description summarizes the logical group of fixes. + +### 4.3 Review-Council Gate + +After all code changes are committed locally, run `/review-council` on the cumulative changes. + +- **If passes**: continue to push +- **If fails**: enter fix loop (same behavior as `/unleash`). Fix findings and re-run council. +- **If fix loop exhausts iterations**: **STOP** and report persistent findings. Do NOT push until council passes. + +### 4.4 Push Changes + +Before pushing, fetch the remote branch state: + +```bash +git fetch origin +git status +``` + +**If branch has diverged** (another contributor pushed +commits): warn the author and use the +**AskUserQuestion tool** with options `["Rebase onto +remote and push", "Abort -- preserve local commits"]`. + +Push all commits: + +```bash +git push origin +``` + +**If push fails** (network error, branch protection rejection): preserve local commits and report which commits are stranded. Provide guidance: +> "Push failed. Local commits preserved. Retry with `git push origin ` after resolving the issue." + +### 4.5 Post Reply Comments + +After push succeeds (or if there are no code changes), +post reply comments to the PR. Before posting, use the +**AskUserQuestion tool** with options `["Yes -- post +reply comments", "No -- skip posting"]`. + +For each item, compose the reply: + +| Decision | Reply content | +|---|---| +| ACCEPT | "Addressed in \`\`: " | +| MODIFY | "Addressed in \`\` (modified approach): " | +| REJECT | Evidence-based reasoning referencing convention pack rules or constitution principles | +| ASK | Author's clarification question | + +Post replies to the correct review thread. Always write the comment body to a temporary file and use `--input` to prevent shell injection from AI-generated or reviewer-authored text: + +```bash +# Write reply body to temp file (never interpolate into shell args) +REPLY_FILE=$(mktemp) +cat > "$REPLY_FILE" << 'REPLY_EOF' + +REPLY_EOF + +# For review comments (inline threads) +gh api repos/{owner}/{repo}/pulls//comments//replies \ + --method POST --input "$REPLY_FILE" + +# For issue comments (general) +gh api repos/{owner}/{repo}/issues//comments \ + --method POST --input "$REPLY_FILE" + +# Clean up +rm -f "$REPLY_FILE" +``` + +**Crash recovery**: Track each comment's posting status in the cache (`comment-posted` flag). If posting fails partway (e.g., API rate limit after 3 of 6 comments), report partial progress: +> "Posted 3 of 6 reply comments. Items 4-6 pending. Re-run `/address-feedback ` to retry." + +Record progress in `.uf/feedback/pr-/state.json` for idempotent retry. + +### 4.6 Resolve Threads + +After posting reply comments for accepted items, offer to resolve those threads: + +```bash +# GraphQL mutation to resolve a thread +gh api graphql -f query='mutation { resolveReviewThread(input: {threadId: ""}) { thread { isResolved } } }' +``` + +Use the **AskUserQuestion tool** with options +`["Yes -- resolve accepted threads", "No -- leave +threads open"]` before resolving. + +### 4.7 Produce Feedback-Triage Artifact + +Write the artifact to `.uf/artifacts/feedback-triage/pr--round-.json`. + +**Round number**: scan existing files for the highest round number and add 1 (not a file count — handles gaps from deleted files). + +**Atomic write**: write to a temp file first, then rename to the final path. + +**Envelope wrapper** (standard schema): + +```json +{ + "hero": "cobalt-crush", + "version": "1.0.0", + "timestamp": "", + "artifact_type": "feedback-triage", + "schema_version": "1.0.0", + "context": { + "branch": "", + "commit": "", + "backlog_item_id": "" + }, + "payload": { + "pr_number": 42, + "pr_url": "https://github.com/...", + "branch": "", + "round": 1, + "items": [ + { + "thread_id": "...", + "reviewer": "", + "reviewer_role": "maintainer|collaborator|contributor|external|bot", + "file": "internal/foo/bar.go", + "line": 42, + "classification": "data-driven|subjective", + "tier": 1, + "evidence": ["go.md CS-001: ..."], + "recommendation": "accept|author-decides", + "decision": "accept|modify|reject|ask", + "decision_reasoning": "...", + "commit_sha": "abc1234", + "divisor_agents_used": [], + "tier2_unavailable": false, + "conflict_flag": false + } + ], + "summary": { + "total_items": 6, + "accepted": 3, + "modified": 1, + "rejected": 1, + "asked": 1, + "tier1_count": 4, + "tier2_count": 2, + "divisor_agents_invoked": ["adversary", "architect"] + } + } +} +``` + +Fields `file`, `line`, `decision_reasoning`, and `commit_sha` may be `null` (general PR comments have null file/line; REJECT/ASK items have null commit_sha). + +--- + +## Guardrails + +1. **No auto-merge**: This command addresses feedback. It NEVER merges the PR, approves the PR, or dismisses reviews. + +2. **No code changes without triage**: Code is only modified after the author explicitly decides ACCEPT or MODIFY for each item. No autonomous fixes. + +3. **No comments without confirmation**: Every PR comment is shown to the author before posting. No autonomous PR communication. + +4. **No push without review-council**: Code changes MUST pass `/review-council` before pushing. No bypass. + +5. **No partial data processing**: If GitHub API fails during ingestion, STOP. Do not assess or triage based on incomplete feedback. + +6. **Cache is disposable**: The command MUST produce correct results even if `.uf/feedback/` is deleted. Never treat cache as authoritative — GitHub is the source of truth. + +7. **Gatekeeping integrity**: MUST NOT modify quality gates, coverage thresholds, CI flags, or convention pack rules while addressing feedback. If a feedback item requests weakening a gate, classify as SUBJECTIVE with AUTHOR-DECIDES and note the gatekeeping constraint. + +8. **Shell injection prevention**: Always write AI-generated or reviewer-authored text to temporary files and use `--input` for `gh api` calls. Never interpolate untrusted text into shell arguments. + +9. **File permissions**: Cache files `600`, cache directories `700`. The `.uf/feedback/` directory MUST be in `.gitignore`. + +10. **Commit scope**: Only commit files directly related to addressing the specific feedback item. Do not bundle unrelated changes into feedback fix commits. diff --git a/.opencode/commands/agent-brief.md b/.opencode/commands/agent-brief.md new file mode 100644 index 0000000..1f07292 --- /dev/null +++ b/.opencode/commands/agent-brief.md @@ -0,0 +1,548 @@ +--- +description: > + Create, validate, and improve AGENTS.md -- the project briefing + for AI coding agents. Auto-detects mode: creates from scratch + when no AGENTS.md exists, audits and suggests improvements when + one is present. Also ensures cross-tool bridge files (CLAUDE.md, + .cursorrules) are properly configured. +--- + + +# Command: /agent-brief + +## Description + +Manage the AGENTS.md lifecycle: create, audit, and improve the +project briefing that AI coding agents read at session start. + +AGENTS.md is the API contract between humans and AI agents. It +tells agents how to build, test, and lint the project, what +conventions to follow, and what constraints to respect. Without +a good AGENTS.md, every agent session starts from cold context. + +**Modes**: +- No AGENTS.md → **Create mode** (analyze project, generate file) +- AGENTS.md exists → **Audit mode** (score, report, suggest) +- `/agent-brief create` → Force create mode (overwrite) +- `/agent-brief audit` → Force audit mode (read-only) + +## Instructions + +### Step 1: Mode Detection + +1. Check if AGENTS.md exists at the repository root. + +2. Parse the user's argument (if any): + - `create` → force create mode + - `audit` → force audit mode + - No argument → auto-detect based on file existence + +3. Route to the appropriate mode: + - **Create mode**: No AGENTS.md exists, or user passed `create` + - **Audit mode**: AGENTS.md exists, or user passed `audit` + +4. Announce the selected mode: + - Create: `"No AGENTS.md found. Analyzing project to generate one..."` + - Audit: `"Found AGENTS.md (N lines). Running quality audit..."` + - Force create: `"Force-creating AGENTS.md. Existing file will be replaced after your review."` + +### Step 2: Project Analysis + +Analyze the project to understand its characteristics. Read the +following files (skip any that do not exist): + +**Language & Dependencies**: +1. `go.mod` → Go project (extract module name, Go version, key deps) +2. `package.json` → Node/TypeScript project (extract name, scripts, key deps) +3. `Cargo.toml` → Rust project (extract name, edition, key deps) +4. `pyproject.toml` → Python project (extract name, version, key deps) +5. `tsconfig.json` → TypeScript confirmation + +**Build System** (read only in Create mode or when refreshing +Build & Test section in Audit mode): +6. `Makefile` or `justfile` → extract build/test/lint targets +7. `.github/workflows/` → read CI workflow files to find exact + build, test, vet, and lint commands (these are the source of + truth for build commands) + +**Linter Configuration**: +8. `.golangci.yml` → Go linter rules +9. `ruff.toml` or `pyproject.toml [tool.ruff]` → Python linter +10. `.eslintrc*` or `eslint.config.*` → JavaScript/TypeScript linter + +**Project Context**: +11. `README.md` → project description (first paragraph or heading) +12. `LICENSE` → license type +13. `.git/config` → remote URL for project/org name +14. Top-level directory listing → project structure + +**Governance & Context Detection**: +15. `.specify/memory/constitution.md` → constitution exists + (triggers Behavioral Rules section) +16. `specs/` → check for `NNN-*/` subdirectories (Speckit) +17. `openspec/config.yaml` or `openspec/` → OpenSpec configured + (triggers Specification Workflow section) +18. `.opencode/uf/packs/` → convention packs deployed + (respect existing Convention Packs section from Go binary) +19. `opencode.json` → check for Dewey MCP server + (triggers Knowledge Retrieval section) + +Record what was detected. This informs both create and audit +modes. + +### Step 3: Create Mode + +If in create mode, generate AGENTS.md using the project analysis. + +The target AGENTS.md has 10 sections. Sections 1-5 and 10 are +LLM-generated from project data. Sections 6-8 are verbatim +templates inserted conditionally. Section 9 is detected and +respected from the Go binary. + +#### Section 1: Project Overview (LLM-generated) + +Generate 2-5 lines from README first paragraph, plus a bullet +list of key attributes: + +- What the project is (from README) +- **Type**: project type (CLI, library, web app, API, monorepo) +- Key domain context (heroes, tooling, etc.) +- **License**: license type +- **Mission**: one-line mission statement if available + +#### Section 2: Build & Test Commands (LLM-generated) + +- Extract exact commands from Makefile targets or CI workflows +- Include the flags that matter (e.g., `-race -count=1` for Go) +- Use fenced code blocks (```) for all commands +- Group as: Build, Test, Lint (and any other common targets) +- If CI workflows define additional structure (workflow names, + purposes), include a CI Workflow Structure sub-table + +#### Section 3: Project Structure (LLM-generated) + +- Generate a directory tree showing major directories +- Focus on top-level and one level deep +- Annotate each directory with its purpose +- Use the `text` code fence format + +#### Section 4: Coding Conventions (LLM-generated) + +- Derive from linter config if present +- Include language-specific defaults: + - Go: gofmt, goimports, error wrapping, import grouping + - TypeScript: prettier, ESLint rules, naming conventions + - Python: ruff/black, type hints, docstring style + - Rust: clippy, formatting, error handling +- Include naming conventions, comment style, error handling +- Include spec writing conventions: RFC 2119 language + (MUST/SHOULD/MAY), Given/When/Then scenarios, FR-NNN + numbering, line length < 72 + +#### Section 5: Testing Conventions (LLM-generated) + +- Framework and version +- Test naming pattern (e.g., `TestXxx_Description`) +- Assertion style (stdlib vs. assertion library) +- Isolation strategy (e.g., `t.TempDir()` for filesystem) +- Special requirements (e.g., drift detection for embedded + assets) + +#### Section 6: Behavioral Rules (verbatim template, conditional) + +**Condition**: Insert ONLY when `.specify/memory/constitution.md` +exists. If no constitution is detected, omit this section entirely. + +Insert this verbatim: + +```markdown +## Behavioral Rules + +These rules are non-negotiable. Violations are CRITICAL severity. + +- **Gatekeeping**: MUST NOT modify quality/governance gates + (coverage thresholds, CRAP scores, severity definitions, + CI flags, agent settings, constitution MUST rules, review + limits, workflow markers). Stop and report instead. +- **Phase boundaries**: MUST NOT cross workflow phase boundaries. + Spec phases: spec artifacts only. Implement: source code. + Review: fixes only. Violation = process error, stop immediately. +- **CI parity**: MUST replicate CI checks locally before marking + tasks complete. Derive commands from `.github/workflows/`. +- **Review council**: MUST run `/review-council` before PR + submission. Resolve all REQUEST CHANGES. No code changes + between APPROVE and PR. Exempt: constitution amendments, + docs-only, emergency hotfixes. +- **Branch protection**: MUST NOT commit directly to `main`. + All changes via feature branches and PRs. +- **Documentation gate**: Before marking a task complete, + assess documentation impact: `CHANGELOG.md` for change + entries, `AGENTS.md` for structural updates (project + structure, conventions, build commands), `README.md` for + description changes. +- **Documentation gate**: MUST file a documentation issue + against the current repo for user-facing changes before + PR merge. Exempt: internal refactoring, test-only, + CI-only, spec artifacts. +- **Zero-waste**: No orphaned specs, unused standards, or + aspirational documents that do not map to actionable work. + +### PR Review Commands + +| Command | When | Scope | +|---------|------|-------| +| `/review-council` | Pre-PR (local) | 5+ Divisor agents | +| `/review-pr [N]` | Post-PR (GitHub) | Single agent, CI analysis | +``` + +#### Section 7: Specification Workflow (verbatim template, conditional) + +**Condition**: Insert ONLY when `specs/` directory has numbered +subdirectories (`NNN-*/`) OR `openspec/` directory exists. If +neither is detected, omit this section entirely. + +Insert this verbatim: + +```markdown +## Specification Workflow + +All non-trivial changes MUST be preceded by a spec workflow. + +| Tier | Tool | When | Artifacts | +|------|------|------|-----------| +| Strategic | Speckit | >= 3 stories, cross-repo | `specs/NNN-*/` | +| Tactical | OpenSpec | < 3 stories, single-repo | `openspec/changes/*/` | + +Pipeline: `constitution → specify → clarify → plan → tasks → +analyze → checklist → implement` + +**Ordering**: Constitution before specs. Spec before plan. Plan +before tasks. Tasks before implementation. Spec artifacts MUST +be committed/pushed before implementation begins. + +**Branches**: Speckit: `NNN-`. OpenSpec: `opsx/`. + +**Task bookkeeping**: Mark checkboxes `[x]` immediately on +completion. `[P]` marks parallel-eligible tasks. + +**When in doubt**: Start with OpenSpec. Escalate to Speckit if +scope grows beyond 3 stories or crosses repo boundaries. + +**What requires a spec**: New features, refactoring that changes +signatures, test additions across multiple functions, agent +changes, CI changes, data model changes. + +**Exempt**: Constitution amendments, typo fixes, emergency +hotfixes (retroactively documented). +``` + +#### Section 8: Knowledge Retrieval (verbatim template, conditional) + +**Condition**: Insert ONLY when `opencode.json` contains a Dewey +MCP server configuration. If Dewey is not configured, omit this +section entirely. + +Insert this verbatim: + +```markdown +## Knowledge Retrieval + +Prefer Dewey MCP tools over grep/glob/read for cross-repo +context and architectural patterns. + +| Intent | Tool | +|--------|------| +| Conceptual | `dewey_semantic_search` | +| Keyword | `dewey_search` | +| Navigation | `dewey_traverse`, `dewey_get_page` | +| Discovery | `dewey_find_connections`, `dewey_similar` | + +**Fallback**: Use Read/Grep/Glob when Dewey is unavailable, +for exact string matching, known file paths, or non-Markdown +content (Go source, JSON, YAML). +``` + +#### Section 9: Convention Packs (detected, not generated) + +**Condition**: If `.opencode/uf/packs/` directory exists and +contains `.md` files, check if AGENTS.md already has a +`## Convention Packs` section (written by the Go binary's +`ensureAGENTSmdPackSection`). + +- If the section already exists → keep it as-is, do not + regenerate. +- If the directory exists but no section → generate a + section listing the pack files found, using the same format + as the Go binary: + +```markdown +## Convention Packs + +This repository uses convention packs scaffolded by +unbound-force. Agents MUST read the applicable pack(s) +before writing or reviewing code. + +- `.opencode/uf/packs/.md` +- `.opencode/uf/packs/.md` +... +``` + +- If no `.opencode/uf/packs/` directory exists → omit section. + +#### Section 10: Architecture (LLM-generated) + +- Describe the dominant design patterns in the project +- Key architectural patterns (e.g., Options/Result structs, + embed.FS scaffold, Cobra CLI delegation) +- Keep concise: 5-10 lines max + +#### 3a: CHANGELOG.md Handling + +If `CHANGELOG.md` does not exist at the repository root, +create it with just a heading: + +```markdown +# Changelog +``` + +Do NOT add entries -- just the heading. Entries are added +by the Scribe and `update-agent-context.sh`. + +#### 3b: Present and Write + +1. Show the complete generated AGENTS.md to the user. +2. Ask: "Does this look good? I can write it now, or you can + suggest changes first." +3. On confirmation, write the file to `AGENTS.md` at repo root. +4. If CHANGELOG.md was created, mention it in the summary. +5. Proceed to Step 5 (Bridge Files). + +### Step 4: Audit Mode + +If in audit mode, read the existing AGENTS.md and evaluate it +against the flat section taxonomy. + +#### 4a: Section Detection + +Scan the file for section headers matching these patterns. A +section is "found" if any of its patterns match a `##` header +line (case-insensitive): + +| # | Section | Detection Patterns | Conditional | +|---|---------|--------------------|-| +| 1 | Project Overview | `overview`, `about` | No | +| 2 | Build & Test Commands | `build`, `development` | No | +| 3 | Project Structure | `structure`, `layout`, `directory` | No | +| 4 | Coding Conventions | `convention`, `coding standard`, `style guide`, `coding convention` | No | +| 5 | Testing Conventions | `test` | No | +| 6 | Behavioral Rules | `behavioral`, `rule`, `constraint` | Constitution | +| 7 | Specification Workflow | `specification`, `spec framework`, `speckit`, `openspec`, `spec workflow` | specs/openspec | +| 8 | Knowledge Retrieval | `knowledge`, `retrieval`, `dewey` | Dewey MCP | +| 9 | Convention Packs | `convention pack` | Packs dir | +| 10 | Architecture | `architect`, `pattern`, `design` | No | + +Record which sections are found and which are missing. +For conditional sections, only flag as missing if their +trigger condition is met (e.g., don't flag missing +Behavioral Rules if no constitution exists). + +#### 4b: Selective Refresh + +Re-derive these sections from the current filesystem and +compare against what AGENTS.md contains: + +**Build & Test Commands**: Read Makefile and CI workflow files. +Compare extracted commands/targets against what the Build +section lists. Flag specific deltas: +- Missing Makefile targets not in AGENTS.md +- CI workflow names/files that changed +- Command flags that differ + +**Project Structure**: List the actual top-level directories. +If the section contains a directory tree (lines with `├`, `└`, +`│`, or indented paths ending with `/`), verify each listed +directory exists. Flag: +- Directories in AGENTS.md that no longer exist +- New directories not listed in AGENTS.md + +#### 4c: Quality Metrics + +1. **Line count**: Count total lines. Flag if >300. +2. **Build code blocks**: Check if the Build section contains + at least one fenced code block (triple backtick). Flag if + the section exists but has no code blocks. +3. **Constitution reference** (only when + `.specify/memory/constitution.md` exists): Check if AGENTS.md + has a Behavioral Rules section. Flag if absent. +4. **Spec framework reference** (only when `specs/` has numbered + subdirs or `openspec/` exists): Check if AGENTS.md describes + the spec framework. Flag if absent. +5. **Branch protection**: Check if AGENTS.md contains explicit + instructions prohibiting direct commits to `main`. Look for + co-occurrence of "main" with "MUST NOT"/"never"/"prohibited" + in Behavioral Rules or similar section. Flag if absent. +6. **Governance rule completeness** (only when Behavioral Rules + section exists): Verify all 8 rules are present: Gatekeeping, + Phase boundaries, CI parity, Review council, Branch protection, + Documentation gate, Website gate, Zero-waste. Flag any missing. + +#### 4d: Scoring + +Calculate the overall effectiveness label. Count the 5 core +sections (1-5) as essential. Count conditional sections (6-8) +only when their triggers are detected. Section 9 (Convention +Packs) and 10 (Architecture) are recommended. + +| Label | Criteria | +|-------|----------| +| Excellent | All essential + all triggered conditional + all recommended | +| Strong | All essential + all triggered conditional | +| Adequate | 4-5/5 essential | +| Weak | 2-3/5 essential | +| Missing | 0-1/5 essential | + +#### 4e: Generate Report + +Produce a structured report: + +``` +## /agent-brief: Audit Report + +### Section Coverage + +| # | Section | Status | Notes | +|---|---------|:------:|-------| +| 1 | Project Overview | ✅ | [notes] | +| 2 | Build & Test | ✅ | [notes] | +| 3 | Project Structure | ✅/⚠ | [stale dirs if any] | +| 4 | Coding Conventions | ✅ | [notes] | +| 5 | Testing Conventions | ✅ | [notes] | +| 6 | Behavioral Rules | ✅/⊘ | [conditional] | +| 7 | Specification Workflow | ✅/⊘ | [conditional] | +| 8 | Knowledge Retrieval | ✅/⊘ | [conditional] | +| 9 | Convention Packs | ✅/⊘ | [detected] | +| 10 | Architecture | ✅ | [notes] | + +### Selective Refresh + +[List specific deltas found in Build & Test and Project +Structure sections, or "No staleness detected."] + +### Quality Metrics + +| Metric | Value | Status | +|--------|-------|--------| +| Total lines | N | ✅/⚠ | +| Essential sections | N/5 | ✅/❌ | +| Conditional sections | N/N | ✅/⚠ | +| Build code blocks | N | ✅/⚠ | +| Governance rules | N/8 | ✅/⚠ | +| Bridge: CLAUDE.md | present/missing | ✅/⚠ | +| Bridge: .cursorrules | present/missing | ✅/⚠ | + +### Improvement Suggestions + +[numbered list of specific, actionable suggestions with +generated content for missing sections] + +### Overall Score: [Label] ([N/N] essential, [N/N] conditional, [N/N] recommended) +``` + +#### 4f: Offer Improvements + +If improvements were suggested: +1. Ask: "Would you like me to apply these improvements?" +2. On confirmation, apply the changes: + - Insert missing sections at appropriate locations + - Update stale directory references + - Do NOT modify existing project-specific sections +3. After applying, re-run the audit to show updated score. + +### Step 5: Bridge File Verification + +After creating or improving AGENTS.md, verify cross-tool bridge +files exist. Bridge file creation is owned by `uf init` +(`ensureCLAUDEmd()` and `ensureCursorrules()`). This command +only checks their status and suggests running `uf init` if +they are missing or misconfigured. + +**CLAUDE.md**: +1. Check if CLAUDE.md exists at repo root. +2. If it exists, check if it contains `@AGENTS.md`. +3. If missing or lacking the import: + - Report: `"⚠ CLAUDE.md: missing or does not import AGENTS.md"` + - Suggest: `"Run: uf init to create bridge files"` +4. If already configured: + - Report: `"⊘ CLAUDE.md: already imports AGENTS.md"` + +**.cursorrules**: +1. Check if .cursorrules exists at repo root. +2. If it exists, check if it references AGENTS.md. +3. If missing or lacking the reference: + - Report: `"⚠ .cursorrules: missing or does not reference AGENTS.md"` + - Suggest: `"Run: uf init to create bridge files"` +4. If already configured: + - Report: `"⊘ .cursorrules: already references AGENTS.md"` + +**Note**: `uf init` is the canonical owner of bridge file +creation. It generates CLAUDE.md with `@AGENTS.md` plus +convention pack `@` imports, and .cursorrules with AGENTS.md +reading instructions. Do NOT create bridge files with a +different marker -- defer to `uf init`. + +### Step 6: Summary Report + +Display a final summary: + +**Create mode**: +``` +## /agent-brief: Complete + +### Created + ✅ AGENTS.md: generated (N lines) + ✅ CHANGELOG.md: created (if newly created) + [bridge file statuses] + +### Next Steps + Review the Architecture section and add project-specific + patterns. Then run `uf init` to deploy convention packs + and agents. +``` + +**Audit mode**: +``` +## /agent-brief: Audit Complete + +### Score: [Label] + [section coverage summary] + [selective refresh results] + [quality metrics summary] + [improvements applied or suggested] +``` + +## Guardrails + +- **NEVER modify files outside AGENTS.md, CLAUDE.md, + .cursorrules, and CHANGELOG.md** -- this command manages + agent context files only. +- **NEVER modify CHANGELOG.md content beyond initial + creation** -- only create the file with a `# Changelog` + heading if it does not exist. Do not add, edit, or remove + entries. +- **NEVER implement code, modify source files, update tests, + or change configuration** -- this command produces + documentation artifacts. +- **ALWAYS present generated content to the user before + writing** -- never auto-write without confirmation. +- **ALWAYS respect existing project-specific sections** -- when + improving, insert missing sections but do not rewrite or + remove sections the user has customized. +- **NEVER remove content** -- only add missing sections or + update stale references. If a section should be condensed, + suggest it but do not apply without confirmation. +- **Use actual project data** -- in create mode, fill sections + from real files (README, Makefile, go.mod, CI config). Do + not use placeholder text or generic examples. +- **Respect Convention Packs ownership** -- the Go binary's + `ensureAGENTSmdPackSection` owns this section. Detect and + preserve it; do not regenerate if it already exists. diff --git a/.opencode/commands/cobalt-crush.md b/.opencode/commands/cobalt-crush.md index 6547c0f..30679ea 100644 --- a/.opencode/commands/cobalt-crush.md +++ b/.opencode/commands/cobalt-crush.md @@ -3,12 +3,9 @@ description: > Invoke the Cobalt-Crush developer persona for implementation tasks. With arguments: delegates to the cobalt-crush-dev agent. Without arguments: detects active workflow and runs /speckit.implement or - /opsx:apply. + /opsx-apply. --- - - - # Command: /cobalt-crush @@ -90,9 +87,11 @@ implementation command to the `cobalt-crush-dev` agent: > No active implementation context detected. Which workflow > should I execute? > + > - `/unleash` — Autonomous pipeline (parallel swarm, + > recommended for multi-task changes) > - `/speckit.implement` — Strategic spec implementation > (requires a feature branch with `specs/NNN-*/tasks.md`) - > - `/opsx:apply` — Tactical change implementation + > - `/opsx-apply` — Tactical change implementation > (requires an active change in `openspec/changes/`) ## Branch Safety Guardrails diff --git a/.opencode/commands/constitution-check.md b/.opencode/commands/constitution-check.md index 704389e..f9440ba 100644 --- a/.opencode/commands/constitution-check.md +++ b/.opencode/commands/constitution-check.md @@ -3,10 +3,6 @@ description: "Check a hero constitution's alignment with the Unbound Force org c agent: constitution-check --- - - - - # Command: /constitution-check @@ -54,7 +50,7 @@ parent constitution reference. - If a second argument is provided, use it as the org constitution path. - Otherwise, check if the current repository is the unbound-force - meta repo (look for `unbound-force.md` at the repo root). If so, + meta repo (look for `docs/heroes.md` at the repo root). If so, use `.specify/memory/constitution.md` as the org constitution. - If the current repo is NOT the meta repo, look for the org constitution at `../unbound-force/.specify/memory/constitution.md` diff --git a/.opencode/commands/finale.md b/.opencode/commands/finale.md index dad5e3c..f132e6c 100644 --- a/.opencode/commands/finale.md +++ b/.opencode/commands/finale.md @@ -1,12 +1,11 @@ --- description: > Finalize a branch: commit, push, create PR, watch CI - checks, rebase-merge, and return to main. One command - to wrap up any feature or OpenSpec branch. + checks, and return to main. The PR stays open for + review. One command to wrap up any feature or OpenSpec + branch. --- - - # Command: /finale @@ -20,9 +19,9 @@ $ARGUMENTS Automate the end-of-branch workflow. Stages all changes, generates a conventional commit message, pushes, creates -a PR, watches CI checks, rebase-merges, and returns to -`main`. Works with both Speckit (`NNN-*`) and OpenSpec -(`opsx/*`) branches. +a PR, watches CI checks, and returns to `main`. The PR +stays open for human review. Works with both Speckit +(`NNN-*`) and OpenSpec (`opsx/*`) branches. ## Usage @@ -101,6 +100,36 @@ b. Generate a conventional commit message: changes are staged - If `$ARGUMENTS` is not empty, use it as a hint or directly as the summary if it's already well-formed +- Append AI attribution after the commit body, + separated by a blank line: + 1. A git trailer: `Assisted-by: ` + 2. A human-readable footer: + `Generated with AI assistance ()` + + Where `` is the model family name you are + currently running as. To resolve the model name: + (1) read your model identifier from the system + prompt (e.g., "You are powered by the model named + X") or runtime environment; (2) remove everything + before and including the last `/` character; + (3) remove everything after and including the first + `@` character; (4) remove any trailing date suffix + matching `-YYYYMMDD` (a hyphen followed by exactly + 8 digits); (5) repeatedly remove any trailing + version segment matching `-N` (a hyphen followed by + a single digit at the end) until no more remain; + (6) validate the result contains only + `[a-zA-Z0-9._-]` characters. If the result is empty, + contains invalid characters, or cannot be determined, + use the literal string `unknown-model` and warn the + user (e.g., "Could not determine AI model name — + using 'unknown-model' in attribution"). + + Examples: + - `google-vertex-anthropic/claude-sonnet-4-20250514@default` → `claude-sonnet` + - `claude-opus-4-20250514` → `claude-opus` + - `gpt-4o` → `gpt-4o` + - `gemini-2.5-pro` → `gemini-2.5-pro` c. Show the proposed message to the user: @@ -111,10 +140,17 @@ c. Show the proposed message to the user: > > - Create finale.md command definition > - Add scaffold asset and update file count test +> +> Assisted-by: claude-sonnet +> Generated with AI assistance (claude-sonnet) > ``` > > Approve, edit, or provide your own? +The user MAY edit or remove the attribution during +the approval step. If the user removes it, use their +edited message without re-adding attribution. + d. Commit with the approved message. ### 4. Push to Remote @@ -140,22 +176,171 @@ gh pr view --json number,url 2>/dev/null creation. - **If no PR**: create one: - a. Generate PR title from commit history: + a. **Fork detection**: Check if this repo is a fork: + ```bash + gh repo view --json isFork,parent + ``` + If `isFork` is `true`, ask the user: + + > "This repo is a fork of `/`. + > Where should the PR target? + > + > 1. Upstream (`/` main) + > 2. Fork (`/` main)" + + Use the answer to set `--repo` on `gh pr create`. + If not a fork, proceed without asking. + + b. Generate PR title from commit history: ```bash git log main..HEAD --oneline ``` Use the most descriptive commit message as the title, or synthesize from multiple commits. - b. Generate PR body: summarize all commits on the - branch with a `## Summary` section and bullet points. + c. **PR template detection**: Before generating the + PR body, check for a PR template: - c. Create: ```bash - gh pr create --title "" --body "<body>" + ls .github/PULL_REQUEST_TEMPLATE.md \ + .github/pull_request_template.md 2>/dev/null ``` - d. Report the PR URL. + - **If a template is found**: read the template and + use its `##` heading structure as the skeleton for + the PR body. Map generated content to template + sections using case-insensitive substring matching: + + | Generated Section | Matches Template Headings | + |---|---| + | Summary | Description, Summary, Overview, What | + | How to Test | Testing, Test, Test Plan, Verification | + | How to Demo | Demo, How to Demo | + | Key Files Changed | Files Changed, Changes | + + Template sections that do not match generated + content are preserved as-is for the user to fill + in during the approval step. Generated content for + sections without a template match is appended at + the end. + + If the template contains no `##` headings (empty, + malformed, or non-Markdown), fall back to the + default structured format and warn the user that + the template could not be parsed. + + - **If no template is found**: use the default + structured format below. + + d. Generate PR body with structured sections: + + Analyze the branch commits, diff, and available spec + artifacts to produce a PR body with these sections: + + - `## Summary` — what was done. Summarize the logical + changes from commit history. Focus on the "why" and + user-visible impact, not implementation details. + - `## How to Test` — verification steps for reviewers. + If on an `opsx/*` branch, read + `openspec/changes/*/specs/*.md` for acceptance + scenarios and translate them into concrete + verification commands. If on an `NNN-*` branch, + check for `quickstart.md` in the feature directory. + Otherwise, synthesize test steps from the diff. + - `## How to Demo` — walkthrough for demonstrating + the change. Describe what to do and what to observe. + For trivial changes (e.g., typo fixes), use a brief + note like "Trivial fix — no demo required." + - `## Key Files Changed` — file listing from + `git diff --stat main..HEAD` with brief descriptions + of what changed in each file. + + Each section MUST contain substantive content. For + trivial changes with insufficient source material, + sections SHOULD contain a brief explanatory note + rather than fabricated content. + + Append the attribution footer as the last line of + the PR body: + + ``` + _This PR was generated by /finale (AI-assisted)._ + ``` + + e. **Review-council findings**: Check the conversation + context for prior `/review-council` output. If + unresolved findings exist (findings that were + acknowledged but not fixed during the session), add a + `## Known Issues` section to the PR body between + `## Key Files Changed` and the attribution footer. + + Each finding MUST include its severity and a brief + description. Example: + + ``` + ## Known Issues + + The following findings from the review council were + acknowledged but not resolved: + + - **LOW**: Unused variable in config parser + - **MEDIUM**: Missing error context in HTTP handler + ``` + + If no `/review-council` was run in the session, or no + unresolved findings exist, omit this section entirely. + + Note: findings come from session context and may be + stale if code changes were made after the review. The + user SHOULD verify accuracy during the approval step. + + f. Show the proposed PR content to the user: + + > **Proposed PR:** + > + > **Title:** `<title>` + > + > **Body:** + > ``` + > <body> + > ``` + > + > Approve, edit, or provide your own? + + Use the approved (or edited/replaced) title and body + for creation. + + g. Create: + + Write the approved PR body to a temporary file to + avoid shell injection from AI-generated content: + + ```bash + BODY_FILE=$(mktemp) + chmod 600 "$BODY_FILE" + ``` + + Write the approved PR body content to `$BODY_FILE`. + + ```bash + # If targeting upstream fork parent: + gh pr create --repo <parent> --title "<title>" \ + --body-file "$BODY_FILE" + # Otherwise (not a fork, or user chose fork target): + gh pr create --title "<title>" --body-file "$BODY_FILE" + ``` + + Clean up the temp file in ALL exit paths (success, + failure, user abort): + + ```bash + rm -f "$BODY_FILE" + ``` + + If `mktemp` fails, report the error and **STOP**. + Do NOT fall back to inline `--body` interpolation. + + h. Report the PR URL. ### 6. Watch CI Checks @@ -177,22 +362,11 @@ gh pr checks <number> --watch > 2. Re-run the checks > 3. Stop here and fix manually" - Ask the user how to proceed. Do NOT auto-merge a - PR with failing checks. + Ask the user how to proceed. -### 7. Merge PR +### 7. Return to Main -```bash -gh pr merge <number> --rebase --delete-branch -``` - -- If merge fails (e.g., merge conflict, branch - protection): report error and **STOP**. -- If merge succeeds: proceed. - -### 8. Return to Main - -After merge, verify the branch switch: +Return to main so the developer can start other work: ```bash git checkout main 2>/dev/null # may already be on main @@ -206,29 +380,35 @@ git rev-parse --abbrev-ref HEAD Should be `main`. -### 9. Summary +### 8. Summary Display a completion report: ``` ## Finale Complete -**Branch:** opsx/finale-command (deleted) +**Branch:** opsx/finale-command (pushed) **Commit:** feat: add /finale slash command -**PR:** #65 — merged via rebase +**PR:** #65 — CI passed, ready for review **Checks:** passed **Status:** on main, up to date + +Next: Request reviewers on the PR, then merge after +approval with: gh pr merge --rebase --delete-branch ``` ## Guardrails - **NEVER run on `main`** — the command is for feature branches only -- **NEVER merge with failing checks** — stop and report +- **NEVER merge the PR** — /finale creates PRs for + review, not for immediate merge. Users merge manually + after reviewer approval. - **NEVER stage secret files without warning** — always prompt - **NEVER commit without user approval** of the message -- **ALWAYS use rebase merge** — no squash or merge commit +- **NEVER create a PR without user approval** of the + title and body - **ALWAYS report the PR URL** so the user can review it - **If any step fails**, stop immediately with context and options — do not attempt to continue or recover @@ -241,5 +421,5 @@ the OpenSpec and Speckit workflows: - Checks `git status` before any destructive operation - All changes are committed before any branch switch -- The branch is deleted only via `--delete-branch` on - merge (remote deletion handled by GitHub) +- The remote branch is NOT deleted — it stays open with + the PR until a reviewer merges diff --git a/.opencode/commands/forge-status.md b/.opencode/commands/forge-status.md new file mode 100644 index 0000000..54146d4 --- /dev/null +++ b/.opencode/commands/forge-status.md @@ -0,0 +1,24 @@ +--- +description: Check forge coordination status - workers, messages, cells +--- + +# /forge:status + +Show active forge state. + +## Workflow + +1. `forge_status(epic_id, project_key)` — worker progress summary +2. `comms_inbox()` — pending messages from workers +3. `org_cells(status="in_progress")` — active cells + +## Interpreting Results + +- **Workers**: Each subtask shows completion percentage and status +- **Messages**: Unread messages may indicate blocked workers +- **Cells**: In-progress cells are actively being worked on + +## Quick Health Check + +Run all three tools to get a complete picture of forge state. +If any workers are blocked, read their messages and respond. diff --git a/.opencode/commands/forge.md b/.opencode/commands/forge.md new file mode 100644 index 0000000..a786f04 --- /dev/null +++ b/.opencode/commands/forge.md @@ -0,0 +1,67 @@ +--- +description: Decompose task into subtasks and coordinate parallel agents +--- + +# /forge + +Decompose a task and spawn parallel workers. + +## Task + +$ARGUMENTS + +## Workflow + +1. Initialize comms: `comms_init(project_path=".", task_description="Forge: <task>")` +2. Check prior learnings: `hivemind_find(query="<task keywords>")` +3. Decompose: `forge_decompose(task="<task>", context="<learnings>")` +4. Create epic: `org_create_epic(epic_title="<task>", subtasks=[...])` +5. For each subtask: `forge_spawn_subtask(bead_id, epic_id, subtask_title, files)` +6. Monitor: check `comms_inbox()` every few minutes +7. Review: `forge_review(task_id, files_touched)` for each completed worker +8. Complete: `forge_complete(bead_id, summary, files_touched)` +9. Store learnings: `hivemind_store(information="...", tags="forge,<topic>")` + +## Rules + +- Always create a forge, even for small tasks +- Coordinator orchestrates, workers execute +- Workers reserve their own files via `comms_reserve` +- Check inbox regularly for blocked workers +- Review every worker's output before marking complete +- Store learnings after completion + +## Strategy Selection + +Before decomposing, check historical success rates: + +``` +forge_get_strategy_insights(task="<task>") +``` + +Choose from: `file-based`, `feature-based`, `risk-based`, or `auto`. + +## Monitoring + +While workers are active: + +1. `comms_inbox()` — check for messages from workers +2. `forge_status(epic_id, project_key)` — check worker progress +3. `org_cells(status="in_progress")` — see active cells + +## Completion + +After all workers finish: + +1. `forge_complete(bead_id, summary, files_touched)` — mark epic done +2. `forge_record_outcome(bead_id, duration_ms, success)` — record for learning +3. `hivemind_store(information="...", tags="forge,<topic>")` — store learnings +4. `org_sync()` — persist state to git + +## Error Recovery + +If a worker is blocked: + +1. Read the worker's message: `comms_read_message(message_id)` +2. Acknowledge: `comms_ack(message_id)` +3. Either unblock or reassign the subtask diff --git a/.opencode/commands/handoff.md b/.opencode/commands/handoff.md new file mode 100644 index 0000000..5cc5707 --- /dev/null +++ b/.opencode/commands/handoff.md @@ -0,0 +1,25 @@ +--- +description: End a session cleanly - release reservations, sync state, generate handoff note +--- + +# /handoff + +Wrap up a session cleanly. + +## Workflow + +1. Summarize completed work and open blockers +2. `comms_release_all()` — free all file reservations +3. `org_update()` / `org_close()` — update cell statuses +4. `org_sync()` — persist state to git +5. `org_session_end(handoff_notes="...")` — save handoff for next session + +## Handoff Note Template + +Include in your handoff notes: + +- **Completed**: What tasks were finished +- **In Progress**: What was started but not finished +- **Blocked**: What is waiting on external input +- **Next Steps**: What the next agent should do first +- **Gotchas**: Any surprises or edge cases discovered diff --git a/.opencode/commands/inbox.md b/.opencode/commands/inbox.md new file mode 100644 index 0000000..3a9ca90 --- /dev/null +++ b/.opencode/commands/inbox.md @@ -0,0 +1,26 @@ +--- +description: Check comms inbox for messages from other agents +--- + +# /inbox + +Check your message inbox. + +## Workflow + +1. `comms_inbox()` — get message headers (max 5) +2. `comms_read_message(message_id)` — read full message body +3. `comms_ack(message_id)` — acknowledge when handled + +## Filtering + +- `comms_inbox(urgent_only=true)` — show only urgent messages +- `comms_inbox(limit=3)` — limit results + +## Sending + +To send a message to another agent: + +``` +comms_send(to=["worker-1"], subject="...", body="...", importance="normal") +``` diff --git a/.opencode/commands/org.md b/.opencode/commands/org.md new file mode 100644 index 0000000..072ea07 --- /dev/null +++ b/.opencode/commands/org.md @@ -0,0 +1,36 @@ +--- +description: Query and manage work items (cells) +--- + +# /org + +Manage cells with `org_*` tools. + +## Common Actions + +- List ready: `org_ready()` +- Query by status: `org_cells(status="open")` +- Create: `org_create(title="...", type="task", priority=1)` +- Update: `org_update(id="...", status="in_progress")` +- Close: `org_close(id="...", reason="Done")` +- Start: `org_start(id="...")` + +## Usage + +- `/org` — show ready cells +- `/org create "Fix auth bug"` — create a cell +- `/org close <id> "Done"` — close a cell +- `/org status` — show in-progress cells + +## Epics + +Create an epic with subtasks in one call: + +``` +org_create_epic(epic_title="...", subtasks=[{title: "...", files: [...]}]) +``` + +## Sessions + +- `org_session_start()` — begin a work session, get previous handoff notes +- `org_session_end(handoff_notes="...")` — end session with context for next agent diff --git a/.opencode/commands/review-council.md b/.opencode/commands/review-council.md index 49f752e..55680d2 100644 --- a/.opencode/commands/review-council.md +++ b/.opencode/commands/review-council.md @@ -2,9 +2,6 @@ description: Run the reviewer governance council to audit codebase or spec compliance. --- <!-- scaffolded by uf vdev --> -<!-- scaffolded by uf vdev --> -<!-- scaffolded by uf vdev --> -<!-- scaffolded by uf vv0.6.1 --> # Command: /review-council ## User Input @@ -126,32 +123,50 @@ Review the current codebase for compliance with the Behavioral Constraints in `A ### Instructions 1. **Run local quality gates before delegating to - council agents.** This step has two phases that - MUST execute in order. Both phases apply only to - Code Review Mode -- Spec Review Mode skips them. - - #### Phase 1a -- CI Checks (mandatory, hard gate) - - a. Read all files in `.github/workflows/` to - identify the exact commands CI runs. Do not - rely on a memorized list -- the workflow files - are the source of truth. - - b. Execute each CI command locally in the order - they appear in the workflow (typically: - `go build ./...`, `go vet ./...`, - `go test -race -count=1 ./...`, plus any - coverage ratchet steps). - - c. **If any command fails**: **STOP immediately.** - Report each failure as a CRITICAL finding with - the full error output. Do NOT proceed to Phase - 1b or to step 2 (Divisor agent delegation). - The rationale: reviewing code that doesn't - compile or pass tests is wasted work. - - d. **If all commands pass**: report success and - proceed to Phase 1b. + council agents.** This step has three phases that + MUST execute in order. All three phases apply only + to Code Review Mode -- Spec Review Mode skips them. + + #### Phase 1a -- Pre-flight Checks (mandatory, soft gate) + + Load the `pre-flight` skill and run in `soft-gate` + mode: + + a. Invoke the `skill` tool with name `pre-flight` to + load the shared pre-flight check instructions. + + b. Execute the pre-flight skill's phases in order: + 1. CI Workflow Parsing — discover commands from + `.github/workflows/` + 2. Local Tool Detection — check for config files + and verify binary availability + 3. CI Coverage Matrix — display the matrix (in + soft-gate mode, all tools are marked "Run + locally = Yes") + 4. Execution — run all detected and available + tools in soft-gate mode (do NOT stop on first + failure; record all results) + 5. Baseline Establishment (Phase 4a) — if any + tools failed, establish a baseline for `main` + using the two-tier strategy (CI API first, + worktree fallback) + 6. Causality Classification (Phase 4b) — classify + each failure as branch-caused, pre-existing, + or unknown + + c. **If the pre-flight verdict is FAIL + (branch-caused)**: **STOP immediately.** Report + each branch-caused failure as a CRITICAL finding + with the full error output. Do NOT proceed to + Phase 1b or to step 2 (Divisor agent delegation). + The rationale: reviewing code that doesn't compile + or pass tests is wasted work. + + d. **If the pre-flight verdict is PASS** (including + when pre-existing failures exist): report success. + If pre-existing failures were detected, record + them for inclusion in the final report (Step 6). + Proceed to Phase 1b. #### Phase 1b -- Gaze Quality Analysis (conditional) @@ -170,31 +185,114 @@ Review the current codebase for compliance with the Behavioral Constraints in `A c. **If `gaze` is NOT available**: skip with an informational note: - > "Gaze not installed -- skipping quality - > analysis. Install with - > `brew install unbound-force/tap/gaze`." + > "Gaze not installed -- skipping quality + > analysis. Install with + > `brew install unbound-force/tap/gaze` + > (or on Fedora/RHEL: + > `go install github.com/unbound-force/gaze/cmd/gaze@latest`)." Proceed to step 2 without Gaze data. -2. Delegate the review to all **discovered** reviewer agents in parallel using the Task tool. For each discovered agent, use the focus area from the Known Reviewer Roles reference table to provide targeted context. For any discovered agent not in the table, use a generic prompt: "Review the current changes for quality, correctness, and compliance. Return your verdict (APPROVE or REQUEST CHANGES) along with all findings." - - **When Gaze data is available** (from Phase 1b): - append a "Quality Context" section to each Divisor - agent's review prompt containing the Gaze Report - summary. This gives agents -- particularly - `divisor-testing` -- access to concrete CRAP - scores, coverage percentages, quadrant - distributions, and prioritized recommendations. - Instruct agents to reference this data in their - findings where relevant. + #### Phase 1c -- Discover Review Context (mandatory) + + Load the `review-context` skill for spec artifact + discovery, path classification, and walkthrough + generation: + + a. Invoke the `skill` tool with name `review-context` + to load the shared context discovery instructions. + + b. Execute the skill's protocols in order: + 1. Protocol 1 (Spec Artifact Discovery) — locate + the specification matching the current branch + using the branch name from auto-detection and + the changed file list. + 2. Protocol 2 (Issue Linking) — **skip**. This + protocol requires a PR body; + `/review-council` is a local pre-PR command + with no PR body to parse. + 3. Protocol 3 (Path-Based Focus Heuristics) — + classify each changed file from the + auto-detection step for review emphasis. + 4. Protocol 4 (Walkthrough Generation) — generate + per-file change summaries from the branch + diff (`git diff main...HEAD`). + + c. **Record results**: Use the skill's Review Context + output format (Specification, File Classification, + Walkthrough). This context is used in step 2 + (Divisor agent delegation) and step 6 (final + report). + + d. **If the skill fails to load**: **STOP + immediately.** Report the error as a CRITICAL + finding. Do NOT proceed to step 2. The + `review-context` skill is a hard dependency, + consistent with the `pre-flight` skill + consumption pattern — no inline fallback. - **When Gaze data is NOT available**: use the - standard prompt without a "Quality Context" - section. Agents review based on file reading only. - - For each agent, instruct it to review the current changes and return its verdict (**APPROVE** or **REQUEST CHANGES**) along with all findings. +2. Delegate the review to all **discovered** reviewer agents in parallel using the Task tool. For each discovered agent, use the focus area from the Known Reviewer Roles reference table to provide targeted context. For any discovered agent not in the table, use a generic prompt: "Review the current changes for quality, correctness, and compliance. Return your verdict (APPROVE or REQUEST CHANGES) along with all findings." -3. Collect all **REQUEST CHANGES** findings from the discovered reviewers. If all discovered reviewers return **APPROVE**, report the result and stop. + **CRITICAL — Review Scope Rule**: The review scope is + ALWAYS the **full branch diff** (`git diff main...HEAD`), + meaning ALL files changed on the branch relative to + `main`. Do NOT narrow the scope to only recent commits, + only uncommitted changes, or only files touched in the + current session. Every agent MUST be instructed to read + and review ALL changed files from the branch diff. The + list of changed files from auto-detection step 2 MUST + be included in each agent's prompt. Violating this rule + produces incomplete reviews that miss findings in + earlier commits on the branch. + + **Review context enrichment**: Append the following + context sections to each Divisor agent's review + prompt: + + - **Review Context** (from Phase 1c): Include the + spec artifact summary, file classifications, and + walkthrough from the `review-context` skill output. + This gives agents spec alignment context and + per-file focus heuristics. Instruct agents to + reference spec requirements and file + classifications in their findings where relevant. + + - **Quality Context** (from Phase 1b, when Gaze data + is available): Include the Gaze Report summary. + This gives agents -- particularly + `divisor-testing` -- access to concrete CRAP + scores, coverage percentages, quadrant + distributions, and prioritized recommendations. + Instruct agents to reference this data in their + findings where relevant. + + **When Gaze data is NOT available**: include only + the Review Context section. Agents review based on + file reading plus spec/classification context. + + For each agent, instruct it to review the full branch diff (all changed files vs `main`) and return its verdict (**APPROVE** or **REQUEST CHANGES**) along with all findings. + +3. Collect all **REQUEST CHANGES** findings from the + discovered reviewers. If all discovered reviewers + return **APPROVE**, report the result and stop. + + **Cross-persona finding consolidation**: Before + proceeding to the fix loop, group findings from + different personas that (a) affect the same + component, file, or pipeline stage, (b) share a + common root cause, and (c) together produce a risk + greater than any individual finding. Merge each + group into a single consolidated finding: + - Apply compound severity escalation from + `severity.md` to determine the combined severity. + - Preserve per-persona attribution (e.g., + "Adversary: missing checksum + SRE: privileged + blast radius → consolidated MEDIUM"). + - Present the consolidated finding with one unified + recommendation addressing the root cause. + + Findings with independent root causes MUST remain + separate even if they affect the same file. 4. If there are **REQUEST CHANGES**, address the findings by making the necessary code fixes. Then re-run all discovered reviewers to verify the fixes. Repeat this loop until all discovered reviewers return **APPROVE** or the process has exceeded 3 iterations. @@ -202,6 +300,30 @@ Review the current codebase for compliance with the Behavioral Constraints in `A 6. Provide a final report to the user: - **Discovery summary**: how many reviewer agents were discovered, which were invoked, and which known reviewer roles were absent (informational, non-blocking) + - **Pre-existing CI Failures** (if any were detected + in Phase 1a): include an informational section + between the discovery summary and the review + context summary: + + ``` + ### Pre-existing CI Failures (informational) + + The following failures exist on `main` and are + unrelated to the current branch: + + | Tool | Exit code | Baseline method | + |------|-----------|-----------------| + | ... | ... | ... | + + These do not block the review verdict. + ``` + + Omit this section when no pre-existing failures + were detected in Phase 1a. + - **Review context summary**: specification found + (type, path) or "no spec found", and the + walkthrough table from Phase 1c (review-context + skill, Protocol 4) - What was found in each iteration - What was fixed - If stopped early, the current set of outstanding **REQUEST CHANGES** @@ -241,7 +363,16 @@ step, determine which artifacts to review: For each agent, instruct it to **operate in Spec Review Mode**: review the spec artifacts identified in the review scope above (not code), plus `.specify/memory/constitution.md` and `AGENTS.md`. Include the workflow tier (Speckit/OpenSpec) in the agent prompt so it can tailor its review accordingly. Instruct the agent to return its verdict (**APPROVE** or **REQUEST CHANGES**) along with all findings. -2. Collect all **REQUEST CHANGES** findings from the discovered reviewers. If all discovered reviewers return **APPROVE**, report the result and stop. +2. Collect all **REQUEST CHANGES** findings from the + discovered reviewers. If all discovered reviewers + return **APPROVE**, report the result and stop. + + **Cross-persona finding consolidation**: Apply the + same consolidation rule as Code Review Mode Step 3 + — group findings from different personas that share + a root cause, apply compound severity escalation + from `severity.md`, and present as consolidated + findings with per-persona attribution preserved. 3. If there are **REQUEST CHANGES**, apply the **hybrid fix policy**: diff --git a/.opencode/commands/review-pr.md b/.opencode/commands/review-pr.md new file mode 100644 index 0000000..8f482e4 --- /dev/null +++ b/.opencode/commands/review-pr.md @@ -0,0 +1,933 @@ +--- +description: "Review a pull request for alignment, security, and constitution compliance" +--- +<!-- scaffolded by uf vdev --> + +# Review Pull Request + +You are a token-efficient code reviewer. The user will provide a PR number or you will auto-detect it from the current branch. Delegate deterministic checks to local tools and CI results first, then apply AI judgment only where tools cannot reach: intent alignment, security patterns, and architectural concerns. + +## Arguments + +- **PR number** (optional): The pull request number to review (e.g., `42`). If omitted, the command auto-detects the open PR for the current branch. + +**Argument parsing** (before any tool calls): Check the +user's message for a PR number argument. If present, set +`PR_NUMBER` to that value immediately. All subsequent steps +use `<PR_NUMBER>` — no auto-detection commands are needed +or permitted. + +## Execution Steps + +### 0. Prerequisites + +Verify the `gh` CLI is available and authenticated before proceeding: + +```bash +which gh +``` + +If `gh` is not found: **STOP** with error: +> "`gh` CLI is not installed. Install it from https://cli.github.com/ or via your package manager." + +If `gh` is found, verify authentication: + +```bash +gh auth status +``` + +If not authenticated: **STOP** with error: +> "`gh` is installed but not authenticated. Run `gh auth login` to authenticate." + +#### Execution Mode Check + +This command requires running local tools (build, test, +lint) as part of the review. Verify you can execute +commands by running a harmless probe: + +```bash +echo "mode-check-ok" +``` + +If the probe cannot be executed (the agent runtime +returns a tool-access-denied error, or you are in plan +mode, read-only mode, or otherwise restricted from +running commands): **STOP** with message: + +> "This review requires running local tools (build, +> test, lint) to verify the PR. I am currently in +> plan/read-only mode which prevents executing these +> checks. Switch to a mode that allows command +> execution (e.g., full mode / auto mode) and +> re-invoke `/review-pr <N>`." + +Do NOT proceed with a partial review that skips local +tool execution. The local tool results are the +foundation of the review — without them, AI-only +findings lack verification and the review does not +meet the command's quality standard. + +### 1. Resolve PR Number + +**If `PR_NUMBER` was already set from the argument**: skip +this step entirely. Do NOT run `gh pr view`, +`git branch --show-current`, or any branch/PR detection +commands. + +**Only if no PR number was provided**: auto-detect from +the current branch: + +```bash +gh pr view --json number --jq '.number' +``` + +If no open PR exists for the current branch: **STOP** with error: +> "No open PR found for branch '`<branch>`'. Provide a PR number: `/review-pr 42`" + +### 2. Fetch PR Metadata (Minimal) + +Retrieve PR metadata first — avoid loading the full diff until needed: + +```bash +gh pr view <PR_NUMBER> --json title,body,files,additions,deletions,baseRefName,headRefName,labels,milestone,commits,reviewDecision,reviewRequests +``` + +Record the PR title, description, branch name, base branch, changed file list, current review decision (`REVIEW_REQUIRED`, `APPROVED`, `CHANGES_REQUESTED`), and pending review requests. **Do NOT fetch the full diff yet** — later steps determine which files need AI analysis. + +### 3. Fetch CI Check Results + +Retrieve the CI/CD check suite status for the PR: + +```bash +gh pr checks <PR_NUMBER> --json name,state,description,link +``` + +Categorize each check as: +- **PASS**: Check succeeded +- **FAIL**: Check failed +- **PENDING**: Check still running +- **SKIPPED**: Check was skipped + +If checks are still PENDING, inform the user and use +the **AskUserQuestion tool** with options +`["Wait for checks to complete", "Proceed with +available results"]`. + +**If all checks pass**: Record this and move to Step 4. No CI triage needed. + +**If any checks fail**: Proceed to Step 3a for causality determination. + +#### 3a. CI Failure Causality Determination + +For each failing check, determine whether the failure is caused by the PR's changes or is a pre-existing issue on the base branch. + +**Method**: Check if the same test/check also fails on the base branch: + +```bash +# Get the base branch name (from Step 2 metadata, e.g., "main") +BASE_BRANCH="<baseRefName from Step 2>" + +# Check the latest CI status on the base branch +# Use --jq with $ENVIRON or --arg to avoid injection from check names containing quotes +gh api repos/{owner}/{repo}/commits/${BASE_BRANCH}/check-runs \ + --jq --arg name "<FAILING_CHECK_NAME>" '.check_runs[] | select(.name == $name) | {name, conclusion}' +``` + +**Classification**: + +| Base branch status | PR check status | Classification | +|--------------------|-----------------|----------------| +| Pass | Fail | **PR-caused** — the PR introduced the failure | +| Fail | Fail | **Pre-existing** — failure exists independently of the PR | +| No data | Fail | **Unknown** — treat as PR-caused (conservative) | + +Record the classification for each failing check. This feeds into Step 8 (AI review) and Step 10 (fix-branch). + +### 4. Run Local Deterministic Tools (Pre-flight) + +Load the `pre-flight` skill and run in `ci-aware` mode: + +1. Invoke the `skill` tool with name `pre-flight` to + load the shared pre-flight check instructions. + +2. Execute the pre-flight skill's phases in order: + a. CI Workflow Parsing — discover commands from + `.github/workflows/` + b. Local Tool Detection — check for config files + and verify binary availability + c. CI Coverage Matrix — build the matrix using the + CI check results from Step 3. Apply ci-aware + decision rules: + - CI PASS → skip locally (CI already verified) + - CI FAIL → skip locally (failure already + captured in Step 3a) + - CI NONE → MUST run locally + - No CI checks at all → MUST run ALL detected + local tools + d. Execution — run only tools marked "Yes" in the + coverage matrix + +3. **Record results**: Use the pre-flight result format + (CI Coverage Matrix, Execution Results, Verdict). + If tools pass, skip those categories in the AI + review entirely. If tools fail, include the failure + output as context for Step 8 (AI review). + +4. **If no tools are detected**: Note this and proceed + to AI-based review for all categories. + +### 5. Fetch Diff (Scoped) + +Now fetch the diff, being token-conscious: + +```bash +gh pr diff <PR_NUMBER> +``` + +**Large diff handling** (500+ lines): + +`gh pr diff` does not support file path filters. For +large diffs, save the output to a temp file and +navigate it with targeted reads: + +1. Save the full diff once: + ```bash + gh pr diff <PR_NUMBER> > /tmp/pr<PR_NUMBER>.diff + ``` + (The tool runtime auto-saves truncated output to a + file — use that path if available instead.) + +2. Find file boundaries in the saved diff: + ```bash + grep -n '^diff --git' /tmp/pr<PR_NUMBER>.diff + ``` + This returns line numbers for each file's diff + section. + +3. Read specific file sections using offset/limit on + the saved file. Skip these files entirely: + - Lock files: `package-lock.json`, `go.sum`, + `yarn.lock`, `bun.lock` + - Auto-generated: `*.pb.go`, `vendor/` contents + - Binary files + - CRAP baselines: `.gaze/baseline.json` + +4. For very large PRs (2000+ lines or 50+ files), + warn the user and use the **AskUserQuestion tool** + with options `["Review all files", "Focus on + specific files"]`. If the user selects "Focus on + specific files", follow up with the + **AskUserQuestion tool** (open-ended, no preset + options) to ask which files or directories to + focus on. + +**Do NOT attempt**: +- `gh pr diff <N> -- <path>` (unsupported, will fail) +- `git show <remote>/<branch>:<path>` (PR branch may + not be on any configured remote) +- `git fetch <remote> <branch>` (PR may come from a + fork or push directly to PR refs) + +#### Accessing full file contents from the PR branch + +If you need to read a complete file from the PR branch +(not just the diff), use the GitHub API. The PR branch +may not exist on any locally configured remote: + +```bash +gh api repos/{owner}/{repo}/contents/<path>?ref=<headRefName> \ + --jq '.content' | base64 -d +``` + +Use `<headRefName>` from the Step 2 metadata. If the +API call returns 404, 403, or empty content (files +>1 MB), fall back to reading from the saved diff file +and note in the review that full file content was +unavailable. + +For accessing files on the PR branch, the agent MUST +use `gh api` exclusively. Any `git` subcommand +targeting the PR's head ref (`git show`, `git fetch`, +`git checkout`, `git diff` with remote refs) is +prohibited. + +### 6. Discover Review Context + +Load the `review-context` skill for spec artifact +discovery, issue linking, path classification, and +walkthrough generation: + +1. Invoke the `skill` tool with name `review-context` + to load the shared context discovery instructions. + +2. Execute the skill's protocols in order: + a. Protocol 1 (Spec Artifact Discovery) — locate + the specification matching this PR using branch + name from Step 2 metadata, PR description, and + changed file list. If a spec is found in the + changed file list, read from the saved diff + (Step 5) rather than the filesystem. + b. Protocol 2 (Issue Linking) — parse the PR body + from Step 2 metadata for linked issues, validate, + fetch, sanitize, and extract acceptance criteria. + c. Protocol 3 (Path-Based Focus Heuristics) — + classify each changed file from the Step 2 + metadata for review emphasis. + d. Protocol 4 (Walkthrough Generation) — generate + per-file change summaries while analyzing the + diff from Step 5. + +3. **Record results**: Use the skill's Review Context + output format (Specification, Linked Issues, File + Classification, Walkthrough). This context is used + in Step 8 (AI review) and Step 9 (output). + +### 7. Load Convention Packs (Optional) + +Check if convention packs are available for enhanced review precision: + +```bash +test -d .opencode/uf/packs && echo "PACKS=yes" +``` + +**If packs are available**: +1. Always read `.opencode/uf/packs/default.md` (language-agnostic rules) +2. Detect language and load the appropriate pack: + - `go.mod` exists → read `.opencode/uf/packs/go.md` + - `tsconfig.json` or `package.json` exists → read `.opencode/uf/packs/typescript.md` +3. Read corresponding `-custom.md` files if they exist (e.g., `go-custom.md`) +4. Read `.opencode/uf/packs/severity.md` if it exists — use its severity definitions instead of the inline fallback in Step 8 +5. Do NOT load `content.md` or `content-custom.md` — these contain writing standards for documentation agents, not code quality rules + +Use pack rules (CS-001, AP-001, SC-001, TC-001, DR-001, etc.) alongside the constitution for more specific, actionable findings. Reference the specific rule ID in each finding. + +**If packs are NOT available**: proceed without them. Use the constitution and inline severity definitions only. No error or warning needed. + +### 7.5. Fetch Existing Review State + +Fetch existing PR reviews and inline comments to prevent +duplicate findings and provide context for the AI review. + +#### 7.5a. Fetch Reviews + +```bash +gh api repos/{owner}/{repo}/pulls/<PR_NUMBER>/reviews \ + --jq '[.[] | {id: .id, user: .user.login, state: .state, body: .body, submitted_at: .submitted_at, commit_id: .commit_id}]' +``` + +Record each review's user, state (`APPROVED`, +`CHANGES_REQUESTED`, `COMMENTED`, `DISMISSED`), body, +and commit ID. + +#### 7.5b. Fetch Inline Comments + +```bash +gh api repos/{owner}/{repo}/pulls/<PR_NUMBER>/comments \ + --jq '[.[] | {path: .path, line: .line, body: .body, user: .user.login, created_at: .created_at}]' +``` + +Record each inline comment's file path, line number, +body, and author. + +#### 7.5c. Identify Current User + +```bash +gh api user --jq '.login' +``` + +Record the authenticated user's login for duplicate +review detection in Step 11. + +#### 7.5d. Token Budget + +Existing review comments passed to Step 8 MUST be capped +at 3000 characters total to prevent token bloat. When the +combined comment text exceeds this limit: +1. Filter to comments on files changed in this PR +2. Sort by `created_at` descending (most recent first) +3. Include comments until the 3000-character budget is + exhausted +4. Truncate the remainder with a note: "N additional + prior comments truncated for token budget" + +#### 7.5e. Error Handling + +If any `gh api` call in this step returns 403, 404, or +times out: +- Log the error +- Skip the failed sub-step +- Proceed to Step 8 without the missing context + +The review continues without blocking. All review state +data is additive context — its absence does not reduce +the review's capability, only its deduplication accuracy. + +### 8. AI Review (Judgment-Based Only) + +Focus AI analysis exclusively on what deterministic tools and CI cannot check. Skip any category where local tools or CI already passed. + +**Existing review deduplication** (using Step 7.5 data): +Before generating findings, cross-reference existing +inline comments from Step 7.5b against the current +analysis. For each finding: +- If an existing inline comment covers the same file and + line range with a similar concern: **annotate** the + finding as "previously raised by @user" rather than + presenting it as new. Include the annotation in the + output. +- If an existing review thread appears resolved (the + author pushed fixes after the comment): **acknowledge** + this in the finding context. +- If prior reviewer discussions provide relevant context + for a finding: **reference** them (e.g., "Related to + @user's comment on the same file"). +- Do NOT fully suppress findings — the current review may + have additional context or a different severity + assessment. Annotate, don't hide. + +**Path-based review focus and walkthrough**: Use the +file classifications and walkthrough summaries from +Step 6 (review-context skill, Protocols 3 and 4). +When reviewing each file, apply the matched focus +instruction as additive review context. Step 8b +(Security Review) applies to ALL changed files +regardless of path heuristic. + +#### 8a. Alignment Check + +Compare the PR intent (title + description + linked spec + linked issues) against the actual code changes: + +- **Scope alignment**: Do the changed files match what the spec/description says should change? Flag files modified outside the stated scope. +- **Requirement coverage**: For each requirement in the spec (if found), verify the code changes address it. Flag uncovered requirements. +- **Completeness**: Are there partial implementations that could leave the system in an inconsistent state? +- **Drift detection**: Does the code do anything NOT described in the intent/spec? Flag undocumented behavioral changes. +- **Issue criteria coverage**: For each acceptance criterion from linked issues (Step 6, Protocol 2), verify the code changes address it. Report uncovered criteria as MEDIUM findings with per-criterion status (COVERED / NOT COVERED / PARTIAL). +- **Issue suggestion gap detection**: After checking + acceptance criteria, scan each linked issue body for + explicit code suggestions — fenced code blocks + (` ``` `), inline code spans, or clearly proposed + one-line fixes. For each suggestion found: + - Check whether the PR implemented the suggested + change. + - If implemented: no finding needed. + - If not implemented: flag as a finding. Assess + severity based on the risk of the gap (e.g., a + missing guard clause on a destructive operation is + HIGH; a missing style preference is LOW). + +#### 8b. Security Review + +Examine the diff for security vulnerabilities that linters cannot catch: + +- **Input sanitization**: Are external inputs (user input, API parameters, file paths, environment variables, command arguments) validated before use in: + - SQL queries (injection risk) + - Shell commands (command injection) + - File paths (path traversal) + - HTML/template output (XSS) + - YAML/JSON parsing (deserialization attacks) +- **Unexpected workflows**: Can the code be executed in an unintended order or context? + - Missing authentication/authorization checks + - Race conditions or TOCTOU vulnerabilities + - State machine violations (skipping steps) + - Error handling that exposes sensitive information +- **Privilege escalation**: Does the code grant permissions or elevate privileges without proper validation? +- **Secrets and credentials**: Are there hardcoded secrets, tokens, or API keys? Are secrets logged or exposed in error messages? +- **Dependency risks**: Are new dependencies well-maintained and from trusted sources? + +**Adversarial input enumeration**: For each new input, +parameter, secret, or configuration value introduced +by the PR, enumerate: +- What values can a caller pass? (valid range, type, + format) +- What happens for each edge case: empty string, wrong + type, wrong case (e.g., `"True"` vs `"true"`), + excessively long value, injection payload, + null/undefined? +- Does validation exist? Is it sufficient? Is it + applied before the value reaches any security- + sensitive operation? +- If the input controls a security-relevant behavior + (e.g., `skip_org_check`, `disable_verification`), + is there an audit trail when the input is used to + bypass a control? + +Flag missing or insufficient validation as findings +with severity based on the blast radius of the +unvalidated input. + +#### 8c. Constitution Compliance (AI-only items) + +Read `.specify/memory/constitution.md` if it exists. Extract all principles and their MUST/SHOULD rules. For each principle, check whether the PR's changes comply. **Only check items that local tools and CI did NOT already verify.** + +If no constitution file exists, note this and review against general software engineering best practices. Do NOT hardcode specific principle names or numbers — each project defines its own constitution. + +**Skip if already covered by local tools or CI**: naming conventions, line length, lint issues, formatting, file headers. + +#### 8d. CI Failure Analysis + +For each CI failure classified in Step 3a, provide analysis: + +**PR-caused failures**: Include as HIGH or CRITICAL findings: +- Which check failed and what the error output says +- Which PR change likely caused the failure (map failing test to changed file/function) +- Suggested fix or direction + +**Pre-existing failures**: Report separately with clear labeling: +- Confirm the failure also exists on the base branch +- Brief root cause analysis if determinable from the error output +- Note that this will be addressed in Step 10 (fix-branch offer) + +#### 8e. CI Bot Annotation Cross-referencing + +Before proceeding to consolidation, cross-reference the +inline comments from Step 7.5b against the findings +generated in Steps 8a–8d. Identify comments from CI +bots (Scorecard, Trivy, `github-advanced-security[bot]`, +Dependabot, CodeQL, etc.) that address the same files +or concern classes as your findings. + +For each match: +- **Cite the bot finding** in your own finding as + corroborating evidence (e.g., "Scorecard flagged the + same step for unpinned dependencies"). +- **Use the bot finding to strengthen** your severity + classification — if a bot already flagged a concern + and your analysis confirms it, the combined evidence + supports a higher confidence level. +- Do NOT dismiss bot findings as "related but different" + when they address the same class of problem (e.g., + dependency integrity, secrets exposure, container + misconfig) in the same pipeline stage or file. + +#### 8f. Finding Consolidation + +After generating all findings from Steps 8a–8e, perform +a consolidation pass before formatting output. + +**Consolidation rule**: Group findings that (a) affect +the same component, pipeline stage, or file cluster, +(b) share a common root cause, and (c) together produce +a risk greater than any individual finding. Merge each +group into a single finding. + +For each consolidated finding: +1. Use the highest individual severity as the floor, + then apply the compound severity escalation rule from + `severity.md` to determine if the combined severity + is higher. +2. List each contributing factor as a sub-point in the + finding description. +3. Cite the original category (alignment, security, + constitution) for each contributing factor so + traceability is preserved. +4. Present one unified recommendation that addresses + the root cause, not separate fixes for each symptom. + +**When NOT to consolidate**: Findings with independent +root causes and independent blast radii MUST remain +separate even if they appear in the same file. + +#### 8g. Severity Calibration + +After consolidation, perform a calibration pass over +every finding (including consolidated findings from +Step 8f). This step counters anchoring bias — the +tendency to compress all severities toward a "feels +right" level based on overall PR quality impressions. + +For each finding: +1. Re-read the `severity.md` definition for the + currently assigned severity level. +2. Quote the specific definition clause or example + that matches the finding. If no clause matches, + check the adjacent severity levels (one above, one + below). +3. If the quoted definition maps to a **different** + severity than the current assignment, adjust the + severity and note the change (e.g., "Reclassified + from MEDIUM to HIGH — matches HIGH definition: + 'unpinned CI action on mutable tag'"). +4. If the definition confirms the current assignment, + retain it with the quoted evidence. + +The calibration pass MUST NOT introduce new findings +— it only adjusts severity levels on existing findings. + +### 9. Output Format + +Present findings in this structured format: + +```markdown +## PR Review: #<NUMBER> — <TITLE> + +### CI Status +| Check | Status | Classification | +|-------|--------|----------------| +| <name> | PASS/FAIL | PR-caused / Pre-existing / N/A | + +### Local Tool Results +<Table showing which tools ran, pass/fail status, and summary of failures if any> + +### Walkthrough +| File | Change | Focus | +|------|--------|-------| +| `internal/gateway/provider.go` | Add token expiry tracking | security | +| `internal/gateway/gateway_test.go` | Add regression test for stale tokens | test-quality | +| `cmd/unbound-force/gateway.go` | Register --provider flag | cli-ux | + +<For PRs with 30+ files, group by directory with counts:> +| Directory | Files | Summary | Focus | +|-----------|-------|---------|-------| +| `internal/gateway/` | 3 | Token refresh and provider detection | security | + +### Linked Issues +<Only include this section if Step 6 found linked issues> +| Issue | Title | Criteria | +|-------|-------|----------| +| #38 | Export metrics to CSV | 3/4 COVERED | +| | | ✓ CSV export with headers | +| | | ✓ Date range filtering | +| | | ✓ Output to stdout or file | +| | | ✗ Support custom delimiters | +| #999 | (fetch failed) | — | + +### Summary +<1-2 sentence assessment of what the PR does and overall quality. When a Walkthrough is present, the Summary serves as an assessment summary (overall verdict context), not a structural overview — the Walkthrough fills that role.> + +### Alignment +- <Finding with severity> + +### Security +- <Finding with severity> + +### Constitution Compliance +- <Finding with severity> + +### CI Failures (PR-caused) +- <Finding with severity — only if PR-caused failures exist> + +### CI Failures (Pre-existing) +- <Description — only if pre-existing failures exist> +- Note: These failures exist independently of this PR. See fix-branch offer below. + +### Verdict +**<APPROVE / REQUEST CHANGES / COMMENT>** + +<Brief justification. Pre-existing CI failures do NOT block the PR verdict.> +``` + +**Severity levels** (use `.opencode/uf/packs/severity.md` definitions if loaded in Step 7, otherwise use these defaults): +- **CRITICAL**: Must be fixed before merge (security vulnerabilities, data loss risks) +- **HIGH**: Should be fixed before merge (spec violations, missing tests for critical paths, PR-caused CI failures) +- **MEDIUM**: Recommended to fix (code quality, minor compliance issues) +- **LOW**: Optional improvements (style, naming suggestions) + +If no issues are found in a category, state "No issues found." + +### 10. Offer Fix-Branch for Pre-existing CI Failures + +If Step 3a identified any **pre-existing** CI failures, offer to create a fix branch: + +``` +I identified <N> pre-existing CI failure(s) that are NOT caused by this PR: +- <check name>: <brief description of failure> + +These failures also occur on the base branch (<BASE_BRANCH>). +``` + +Use the **AskUserQuestion tool** with options +`["Yes -- create fix branch", "No -- skip"]`. + +**If the user selects "Yes -- create fix branch"**: + +1. **Verify clean working tree**: + ```bash + git status --porcelain + ``` + If the output is not empty: **STOP** branch creation with message: + > "Working tree has uncommitted changes. Commit or stash them before creating a fix branch." + Switch back to the PR branch and continue to Step 11. + +2. **Check for branch name collision**: + ```bash + git branch --list "fix/pr-<PR_NUMBER>-<check-name>" + ``` + If the branch already exists, inform the user: + > "Branch `fix/pr-<PR_NUMBER>-<check-name>` already exists. Switch to it with `git checkout fix/pr-<PR_NUMBER>-<check-name>`, or delete it first." + Switch back to the PR branch and continue to Step 11. + +3. **Sanitize the check name** for branch-name safety: + lowercase, replace spaces and special characters with + hyphens, strip consecutive hyphens, remove characters + outside `[a-z0-9._-]`, truncate to 50 characters. + Example: `"Build (ubuntu/latest)"` → `build-ubuntu-latest`. + Also validate that `<PR_NUMBER>` is digits only. + +4. **Create a fix branch** from the base branch: + ```bash + git checkout <BASE_BRANCH> + git checkout -b fix/pr-<PR_NUMBER>-<sanitized-check-name> + ``` + Branch naming: `fix/pr-<PR_NUMBER>-<sanitized-check-name>` (e.g., `fix/pr-42-yamllint`, `fix/pr-42-test-auth-timeout`) + +5. **Analyze and propose the fix**: Use the CI failure output and the failing file(s) to determine the minimal change needed. Keep the scope as small as possible — fix only what is failing. + +6. **Commit with Conventional Commits format**: + Write the commit message to a temporary file to avoid + shell injection from AI-generated description text, + then commit using `-F`: + ```bash + git add <changed-files> + git commit -s -F <temp-commit-message-file> + ``` + The commit message file should contain: + ``` + fix: resolve <failing-check> CI failure + + <Brief description of what was wrong and how the fix addresses it.> + + This failure was pre-existing on <BASE_BRANCH> and unrelated to PR #<PR_NUMBER>. + + Assisted-by: <model> + ``` + + Where `<model>` is the model family name you are + currently running as. To resolve the model name: + (1) read your model identifier from the system + prompt or runtime environment; (2) remove everything + before and including the last `/`; (3) remove + everything after and including the first `@`; + (4) remove any trailing date suffix matching + `-YYYYMMDD` (a hyphen followed by exactly 8 digits); + (5) repeatedly remove any trailing version segment + matching `-N` (a hyphen followed by a single digit + at the end) until no more remain; (6) validate the + result contains only + `[a-zA-Z0-9._-]` characters. If the result is + empty, contains invalid characters, or cannot be + determined, use the literal string `unknown-model` + and warn the user (e.g., "Could not determine AI + model name — using 'unknown-model' in + attribution"). + Remove the temp file after committing. + +7. **Report to the user**: + ``` + Fix branch created: fix/pr-<PR_NUMBER>-<check-name> + + Changes: + - <file>: <what changed> + + The branch is local. To review and push: + git checkout fix/pr-<PR_NUMBER>-<check-name> + git log -1 + git push -u origin fix/pr-<PR_NUMBER>-<check-name> + ``` + +8. **Switch back** to the PR branch: + ```bash + git checkout <PR_BRANCH> + ``` + +**Guardrails**: +- The fix MUST be scoped to the specific failing check — no unrelated changes +- The agent MUST NOT push to the remote or file a PR automatically +- If the fix is non-trivial (requires understanding business logic, architectural decisions, or modifying more than 3 files), inform the user instead of attempting a fix: + ``` + The CI failure in <check> appears to require a non-trivial fix involving <description>. + I recommend investigating this separately rather than proposing an automated fix. + ``` + +### 11. Offer Verdict-aligned PR Review + +After presenting the review, if there are findings with +severity HIGH or above, offer to post them as a formal +GitHub review on the PR: + +``` +I found <N> findings (X CRITICAL, Y HIGH). +Verdict: <APPROVE / REQUEST CHANGES / COMMENT> +``` + +Use the **AskUserQuestion tool** with options +`["Yes -- post as GitHub review", "No -- terminal +summary is sufficient"]`. + +**If the user selects "Yes -- post as GitHub review"**: + +#### 11a. Pre-posting Checks + +Before preparing comments, run three state-awareness +checks using data from Step 7.5: + +**Duplicate review detection**: Check if a review from +the current user (Step 7.5c) already exists in the +review list (Step 7.5a): + +- If a prior review with the **same verdict** exists: + Inform the user that a prior review exists and the + latest review takes precedence. Use the + **AskUserQuestion tool** with options + `["Yes -- post new review", "No -- skip posting"]`. + +- If a prior review with a **different verdict** exists: + Inform the user of the prior verdict and that the new + review will override it. Use the + **AskUserQuestion tool** with options + `["Yes -- override with <new_verdict>", + "No -- keep existing <old_verdict>"]`. + +- If no prior review exists: proceed silently. + +**Stale review + CODEOWNER checks** (APPROVE verdicts +only): Fetch branch protection settings in a single API +call to avoid redundant requests: + +```bash +gh api repos/{owner}/{repo}/branches/<baseRefName>/protection \ + --jq '{dismiss_stale: .required_pull_request_reviews.dismiss_stale_reviews, require_codeowners: .required_pull_request_reviews.require_code_owner_reviews}' +``` + +If the API returns 404 (no branch protection) or 403 +(insufficient permissions): skip both checks silently. + +If `dismiss_stale` is true, display: +``` +Warning: This repo dismisses stale reviews. If the author +pushes any new commits after this APPROVE, it will be +automatically invalidated and the PR will return to +REVIEW_REQUIRED. You may need to re-run /review-pr after +final commits. +``` + +If `require_codeowners` is true, check for CODEOWNERS +file: + +```bash +gh api repos/{owner}/{repo}/contents/CODEOWNERS \ + --jq '.name' 2>/dev/null || \ +gh api repos/{owner}/{repo}/contents/.github/CODEOWNERS \ + --jq '.name' 2>/dev/null +``` + +If CODEOWNERS exists and `require_code_owner_reviews` is +true, display: +``` +Warning: This repo requires code owner reviews. This +APPROVE may not satisfy branch protection if this +account is not listed in CODEOWNERS. +``` + +If any API call fails: skip silently. + +1. **Prepare comments**: For each finding that maps to a + specific file and line range in the diff, prepare an + in-line comment with: + - The finding description + - The severity level + - A concrete suggestion for fixing the issue + + **Suggestion block format**: When a finding has a + concrete single-file code fix (literal replacement), + format it using GitHub's suggestion block syntax: + + ```` + **[HIGH] Description of the issue** + + ```suggestion + corrected code here + ``` + ```` + + Use suggestion blocks ONLY for literal code + replacements that can be applied as-is. MUST NOT use + suggestion blocks for: + - Architectural or design recommendations + - Multi-file changes + - Removal of security controls (input validation, + auth checks, error handling, lint suppressions) + + For these cases, use plain text with an explanation. + + Cap at 15 comments maximum. If more than 15 findings + qualify, prioritize CRITICAL over HIGH. Include + remaining findings in the review body summary. + +2. **Show all comments for human review**: Present each + prepared comment with its full before/after context: + ``` + File: <path> + Line: <line_number> + Type: suggestion / plain-text + Body: <comment text with suggestion block if applicable> + ``` + +3. **Verdict-aligned confirmation**: Map the verdict from + Step 9 to the GitHub API event type: + - APPROVE → `"event": "APPROVE"` + - REQUEST CHANGES → `"event": "REQUEST_CHANGES"` + - COMMENT → `"event": "COMMENT"` + + Display the verdict context, then use the + **AskUserQuestion tool** for confirmation: + + For APPROVE verdicts: inform the user that this may + unblock merge in repos with branch protection and + that the review will be labeled as AI-generated. + Use the **AskUserQuestion tool** with options + `["Approve -- post review", "No -- skip posting", + "Edit comments first", "Change verdict"]`. + + For REQUEST CHANGES or COMMENT verdicts: inform the + user that this will block merge in repos with branch + protection. Use the **AskUserQuestion tool** with + options `["Yes -- post review", "No -- skip posting", + "Edit comments first", "Change verdict"]`. + + The "Change verdict" option lets the user override the + computed verdict (e.g., downgrade REQUEST CHANGES to + COMMENT). + +4. **Post as a single review event**: Construct a JSON + payload containing the event type, review body, and + inline comments array. Write the payload to a + temporary file and submit via: + + ```bash + gh api repos/{owner}/{repo}/pulls/<PR_NUMBER>/reviews \ + --method POST \ + --input <json-file> + ``` + + The review body MUST include the line: + `_This review was generated by /review-pr + (AI-assisted)._` + + Always write the JSON payload to a temporary file + rather than interpolating AI-generated text into shell + arguments, to prevent shell injection. Remove the + temporary file after posting. + + **Graceful degradation**: If `gh api` returns HTTP 403 + or 422 (insufficient permissions, non-collaborator, or + self-review prohibition), fall back to posting as + `"event": "COMMENT"` with a note: + > "Note: Could not post as <original verdict> due to + > insufficient permissions. Posted as COMMENT instead. + > Original verdict: <APPROVE/REQUEST CHANGES>." + + If the fallback also fails, inform the user that their + token lacks write permissions for PR reviews and + suggest re-authenticating with `gh auth login`. + + - **"No -- skip posting"**: Skip posting, the terminal summary is sufficient + - **"Edit comments first"**: Let the user modify comments before posting, then re-confirm with the **AskUserQuestion tool** + +5. **CRITICAL RULE**: NEVER post reviews without explicit + human confirmation via the **AskUserQuestion tool**. + Always show the exact content (verdict type + all + comments) that will be posted and wait for the user + to select a confirming option. For APPROVE verdicts, + the user MUST select the "Approve -- post review" + option — a clearly-labeled action that conveys the + merge-unblocking consequence. diff --git a/.opencode/commands/triage-issue.md b/.opencode/commands/triage-issue.md new file mode 100644 index 0000000..ad7900c --- /dev/null +++ b/.opencode/commands/triage-issue.md @@ -0,0 +1,480 @@ +--- +description: "Triage a GitHub issue using the Divisor review panel" +--- +<!-- scaffolded by uf vdev --> + + +# Triage Issue + +You are a token-efficient issue analyst. The user provides a GitHub issue number. Fetch the issue, fan out to the Divisor review panel for multi-agent assessment, consolidate verdicts into a classification, then execute triage actions (labels, comments, child issues) with user confirmation. Produce a JSON artifact for every invocation. + +The command follows four sequential phases (Ingest → Assess → Classify → Act). Phases are not independently invocable — run all four in sequence every invocation. + +## Arguments + +- **Issue number** (required): The GitHub issue number to triage (e.g., `42`). + +**Argument parsing** (before any tool calls): Check the user's message for an issue number argument. Validate that it matches `^[1-9][0-9]*$` (positive integer, no leading zeros). If the argument is missing, invalid, zero, negative, or contains non-numeric characters: **STOP** with error: +> "Invalid issue number. Must be a positive integer." + +No `gh` CLI commands are permitted until the argument passes validation. Set `ISSUE_NUMBER` to the validated value. All subsequent steps use `<ISSUE_NUMBER>`. + +--- + +## Phase 1: Ingest + +Fetch the issue, repository context, and duplicate candidates. + +### 1.0 Prerequisites + +Verify the `gh` CLI is available and authenticated: + +```bash +which gh +``` + +If not found: **STOP** with error: +> "GitHub CLI (gh) is not installed. Install from https://cli.github.com/" + +```bash +gh auth status +``` + +If not authenticated: **STOP** with error: +> "GitHub CLI not authenticated. Run `gh auth login` to authenticate." + +Detect the current repository: + +```bash +gh repo view --json nameWithOwner --jq '.nameWithOwner' +``` + +Record `{owner}/{repo}` for all subsequent API calls. Repository identifiers MUST NOT be hardcoded. + +### 1.1 Fetch Issue + +```bash +gh issue view <ISSUE_NUMBER> --json number,title,body,labels,author,comments,assignees,createdAt,state +``` + +**If the issue does not exist**: **STOP** with the `gh` error output. + +**If the issue is closed**: **STOP** with error: +> "Issue #<ISSUE_NUMBER> is closed. Triage applies to open issues only." + +Record the full issue data for agent consumption. + +### 1.2 Re-Run Detection + +Check for previous triage actions on this issue to support idempotent re-runs: + +1. **Existing labels**: Extract the `labels` array from the issue data fetched in 1.1. Record which triage-relevant labels are already applied (`bug`, `enhancement`, `question`, `design-discussion`, `duplicate`, `needs-info`). + +2. **Previous triage comment**: Check the `comments` array for any comment containing the footer `_This triage was performed by the Divisor review panel._`. If found, note that a previous triage comment exists. + +3. **Existing artifact**: Check if `.uf/artifacts/issue-triage/issue-<ISSUE_NUMBER>.json` exists. If so, the new artifact will use a round number (e.g., `issue-<ISSUE_NUMBER>-2.json`). + +### 1.3 Fetch Repository Context + +Read project context files to provide agents with design philosophy: + +1. Read `README.md` (if it exists) — project description and purpose +2. Read `AGENTS.md` — coding conventions, project structure, behavioral rules + +These provide agents with the context needed to assess whether an issue aligns with project goals and conventions. + +### 1.4 Duplicate Check + +Extract keywords from the issue title and first paragraph of the body for duplicate search: + +1. **Extract keywords**: Take the issue title and the first paragraph of the body. Select 5-10 meaningful keywords (nouns, verbs, technical terms). Exclude common stop words. + +2. **Sanitize keywords**: Remove shell metacharacters (`;`, `|`, `` ` ``, `$`, `(`, `)`, `"`) and strip any strings starting with `--` to prevent CLI flag injection. + +3. **Search for duplicates**: + +```bash +gh issue list --search "<sanitized-keywords>" --state open --json number,title,url --limit 10 +``` + +4. **Filter results**: Exclude the current issue from the results. Record any remaining candidates as `duplicate_candidates` for agent evaluation. + +--- + +## Phase 2: Assess (Parallel Fan-Out) + +Fan out to the Divisor review panel for multi-agent assessment. + +### 2.1 Discover Available Agents + +1. **Read the `.opencode/agents/` directory** using the Read tool to list all entries. + +2. **Filter for triage panel agents**: From the directory listing, select only entries matching these five target agents: + - `divisor-adversary.md` + - `divisor-architect.md` + - `divisor-guard.md` + - `divisor-sre.md` + - `divisor-testing.md` + + Note: `divisor-curator` is excluded from the triage panel. Its domain (documentation gap detection and content pipeline triage) is not relevant to issue classification. + +3. **Extract agent names**: For each matching file, strip the `.md` extension to get the agent name (e.g., `divisor-adversary.md` → `divisor-adversary`). + +4. **Guard clause**: If zero triage panel agents are discovered: **STOP** with error: + > "No Divisor agents found. At least one agent is required for triage." + +5. **Note absent agents**: Compare discovered agents against the five target agents. Any target agent not discovered is noted as absent. Absent agents are informational only — they do not block triage. + +### 2.2 Fan Out to Agents + +Delegate assessment to all discovered agents **in parallel** using the Task tool. For each agent, provide: + +- Full issue text (title, body, comments, author, labels, creation date) +- Repository context (README.md and AGENTS.md summaries) +- Duplicate candidates from Phase 1 + +Each agent MUST return a **structured assessment** with these fields: + +| Field | Values | +|---|---| +| **verdict** | `VALID`, `INVALID`, or `NEEDS-CLARIFICATION` | +| **category** | `bug`, `feature`, `enhancement`, `question`, `opinion`, `duplicate`, or `needs-clarification` | +| **objectivity** | `objective` (verifiable evidence exists) or `subjective` (preference-based) | +| **reasoning** | Evidence-based explanation for the verdict and category | +| **split_recommendation** | `null` or an array of `{title, description}` — each item is a proposed child issue | + +Use the following focus areas when prompting each agent: + +| Agent | Focus | +|---|---| +| `divisor-adversary` | Security implications, attack surface, error handling gaps, dependency risks, injection vectors | +| `divisor-architect` | Architectural alignment, design patterns, scope fit, technical feasibility, convention adherence | +| `divisor-guard` | Intent alignment with project goals, constitution compliance, scope discipline, user value | +| `divisor-sre` | Operational impact, performance implications, deployment concerns, monitoring gaps, reliability | +| `divisor-testing` | Testability, reproducibility, test coverage implications, regression risk, acceptance criteria clarity | + +For any discovered agent not in this table, use a generic prompt: "Assess this GitHub issue for validity, category, and objectivity. Return your structured assessment." + +### 2.3 Collect Assessments + +Collect all agent responses. If an agent fails to respond or returns an unparseable response, record the failure and proceed with the remaining assessments. The command SHOULD proceed with as few as one successful assessment. + +--- + +## Phase 3: Classify (Consolidation) + +Consolidate individual agent assessments into a single classification. + +### 3.1 Verdict Resolution + +Apply the three-rule majority in order: + +1. **NEEDS-CLARIFICATION majority**: If NEEDS-CLARIFICATION verdicts constitute a majority of all agents (>50%), the overall verdict is **NEEDS-CLARIFICATION**. + +2. **Exclude NEEDS-CLARIFICATION**: Otherwise, exclude NEEDS-CLARIFICATION verdicts. If VALID or INVALID has a majority of the remaining votes, that verdict wins. + +3. **Tie-breaking**: If the remaining votes tie (equal VALID and INVALID after excluding NEEDS-CLARIFICATION), the overall verdict defaults to **NEEDS-CLARIFICATION**. + +When fewer than 5 agents are available, majority of available agents applies. + +### 3.2 Category Resolution + +Resolve category disagreements using the specificity hierarchy: + +``` +bug > feature > enhancement > needs-clarification > opinion > question +``` + +When agents disagree, the most specific category wins. + +**Duplicate resolution** (independent of hierarchy): An issue is classified as `duplicate` only when BOTH conditions are met: +1. Phase 1 duplicate search found matching candidates +2. At least two agents independently classify the issue as `duplicate` + +When both conditions are met, `duplicate` takes precedence over the specificity hierarchy. + +### 3.3 Objectivity Classification + +- **Objective**: At least ONE agent provides verifiable evidence (reproducible bug, measurable performance issue, documented behavior contradiction) +- **Subjective**: ALL agents agree the issue is preference-based + +### 3.4 Record Dissent + +Record all dissenting agents (those whose verdict differs from the consolidated verdict) with their agent name and reasoning. These are included in the artifact for provenance tracing. + +### 3.5 Synthesize Split Recommendations + +If two or more agents recommend splitting the issue, synthesize their recommendations into a unified set of proposed child issues. Deduplicate overlapping proposals and merge complementary ones. + +--- + +## Phase 4: Act (Interactive) + +Present the analysis and execute triage actions with user confirmation. + +### 4.1 Present Analysis Summary + +Display the consolidated classification to the user: + +``` +─── Issue Triage Summary ───────────────── +Issue: #<ISSUE_NUMBER>: <title> +Verdict: <VALID|INVALID|NEEDS-CLARIFICATION> +Category: <category> +Objectivity: <objective|subjective> +Agents: <N> consulted, <N> available +Dissent: <agent names and brief reasons, or "none"> +Duplicates: <candidate issue numbers, or "none found"> +Split: <"recommended" with count, or "not recommended"> +────────────────────────────────────────── + +── Agent Assessments ── +<For each agent: name, verdict, category, brief reasoning> + +── Proposed Actions ── +• Label: <label> (auto-apply / requires confirmation) +• Comment: <tone tier> (requires confirmation) +• Split: <N child issues> (requires confirmation, if applicable) +────────────────────────────────────────── +``` + +### 4.2 Label Application + +Labels are applied **automatically without user confirmation**, with one exception: the `duplicate` label requires user confirmation because it carries implicit "close" semantics. + +**Label mapping**: + +| Category | Label | +|---|---| +| `bug` | `bug` | +| `feature` | `enhancement` | +| `enhancement` | `enhancement` | +| `question` | `question` | +| `opinion` | `design-discussion` | +| `duplicate` | `duplicate` | +| `needs-clarification` | `needs-info` | + +**Re-run check**: If the target label is already applied (detected in Phase 1.2), skip label application and note "label already present." + +**Label existence check**: Before applying, verify the label exists in the repository. If it does not exist, create it: + +```bash +gh label create "<label>" --description "<description>" --color "<color>" +``` + +If label creation fails due to insufficient permissions, report the specific label that could not be created, skip that label, and continue with remaining actions. Record the failure in `actions_taken`. + +**Apply the label**: + +```bash +gh issue edit <ISSUE_NUMBER> --add-label "<label>" +``` + +**For `duplicate` label only**: Inform the user that the +`duplicate` label signals the issue should be closed. +Use the **AskUserQuestion tool** with options +`["Yes -- apply duplicate label", "No -- skip"]`. + +### 4.3 Comment Composition and Posting + +Compose a triage comment based on the consolidated classification. The comment tone follows three tiers: + +| Verdict | Tone | +|---|---| +| VALID | Factual analysis: classification, recommendations, next steps | +| INVALID / OPINION | Warm, non-dismissive: acknowledge reporter effort, explain reasoning with specific references, offer alternatives, invite continued engagement | +| NEEDS-CLARIFICATION | Specific questions: what information would help, what to reproduce, what context is missing | + +**All comments MUST include the footer**: +``` +_This triage was performed by the Divisor review panel._ +``` + +**If duplicate candidates were found** (but not classified as duplicate): mention similar issues in the comment for the reporter's awareness. + +**Re-run check**: If a previous triage comment was +detected in Phase 1.2, warn the user that posting +another comment may cause confusion. Use the +**AskUserQuestion tool** with options `["Yes -- post +another comment", "No -- skip comment"]`. If the user +selects "No -- skip comment", record +`comment_posted: false` in the artifact and skip to +Phase 4.4. + +**Present the composed comment to the user for +confirmation**: Use the **AskUserQuestion tool** with +options `["Approve -- post as-is", "Modify -- adjust +comment text", "Abort -- do not post"]`. + +| Selection | Action | +|---|---| +| **Approve -- post as-is** | Post the comment as-is | +| **Modify -- adjust comment text** | Use **AskUserQuestion tool** (open-ended, no preset options) to collect the adjusted comment text; post the adjusted version | +| **Abort -- do not post** | Do not post any comment; record `comment_posted: false` in artifact | + +**Post the comment** (on Approve or Modify): + +Write the comment body to a temporary file and post via `gh api --input`. NEVER interpolate comment text into shell arguments. + +```bash +# Write comment body to temp file (never interpolate into shell args) +COMMENT_FILE=$(mktemp) +chmod 600 "$COMMENT_FILE" +cat > "$COMMENT_FILE" << 'COMMENT_EOF' +{"body": "<comment content as JSON-escaped string>"} +COMMENT_EOF + +# Post the comment +gh api repos/{owner}/{repo}/issues/<ISSUE_NUMBER>/comments \ + --method POST --input "$COMMENT_FILE" + +# Clean up temp file in ALL paths (success, failure, abort) +rm -f "$COMMENT_FILE" +``` + +**On API failure**: Report the error, do NOT retry. Record the failure in `actions_taken`. Clean up the temp file. + +### 4.4 Child Issue Creation (If Splitting) + +This section applies only when Phase 3.5 produced split recommendations. + +For each proposed child issue: + +1. **Present to user**: Show the proposed title and body. + Use the **AskUserQuestion tool** with options + `["Yes -- create this child issue", "No -- skip"]` + for each child issue individually. + +2. **Duplicate check**: Before creating, search for existing issues matching the proposed title: + +```bash +gh issue list --search "<sanitized-child-title>" --state open --json number,title --limit 5 +``` + + If a close match is found, warn the user about the + potential duplicate and use the **AskUserQuestion + tool** with options `["Yes -- create anyway", + "No -- skip this child issue"]`. + +3. **Create the child issue** (if the user selected a confirming option): + +Each child issue body MUST include a cross-reference: `Split from #<ISSUE_NUMBER>`. + +Write the child issue payload to a temporary file and create via `gh api --input`: + +```bash +CHILD_FILE=$(mktemp) +chmod 600 "$CHILD_FILE" +cat > "$CHILD_FILE" << 'CHILD_EOF' +{"title": "<child title>", "body": "<child body with Split from #N>"} +CHILD_EOF + +gh api repos/{owner}/{repo}/issues \ + --method POST --input "$CHILD_FILE" + +rm -f "$CHILD_FILE" +``` + +Record each created child issue number and title. + +4. **Post parent comment**: After all confirmed child issues are created, post a comment on the parent issue listing the created children: + +``` +This issue has been split into the following child issues: +- #<child_number>: <child_title> +- #<child_number>: <child_title> + +_This triage was performed by the Divisor review panel._ +``` + +Post this comment using the same temp file + `--input` pattern from 4.3. + +5. **Parent issue remains open**: The parent issue MUST NOT be auto-closed after splitting. + +### 4.5 Produce Triage Artifact + +Write the artifact for **every invocation**, regardless of outcome (success, user abort, partial failure). + +**Artifact path**: `.uf/artifacts/issue-triage/issue-<ISSUE_NUMBER>.json` + +**Round number**: If the file already exists, scan for the highest existing round number and increment (e.g., `issue-42.json` exists → write `issue-42-2.json`; `issue-42-2.json` exists → write `issue-42-3.json`). + +**Atomic write**: Write to a temp file first, then rename to the final path. + +**Envelope wrapper** (standard schema): + +```json +{ + "hero": "the-divisor", + "version": "1.0.0", + "timestamp": "<ISO 8601>", + "artifact_type": "issue-triage", + "schema_version": "1.0.0", + "context": { + "repository": "<owner/repo>", + "issue_number": "<ISSUE_NUMBER>" + }, + "payload": { + "issue_number": 42, + "issue_url": "https://github.com/<owner>/<repo>/issues/<ISSUE_NUMBER>", + "repo": "<owner>/<repo>", + "title": "<issue title>", + "author": "<issue author login>", + "category": "bug", + "validity": "valid", + "objectivity": "objective", + "duplicate_of": null, + "split_issues": [], + "assessments": [ + { + "agent": "divisor-adversary", + "verdict": "valid", + "category": "bug", + "objectivity": "objective", + "reasoning": "...", + "split_recommendation": null + } + ], + "actions_taken": { + "labels_applied": ["bug"], + "comment_posted": true, + "child_issues_created": [], + "label_creation_failed": false + }, + "summary": { + "agents_consulted": 5, + "agents_available": 5, + "consensus": "4/5 valid", + "dissenting_agents": [ + {"agent": "divisor-sre", "reasoning": "..."} + ] + } + } +} +``` + +Fields may be `null` when not applicable (e.g., `duplicate_of` when the issue is not a duplicate). Use lowercase enum values in the payload (`valid`, `invalid`, `needs-clarification`, `bug`, `feature`, etc.) matching the schema definitions. Use UPPERCASE (`VALID`, `INVALID`, etc.) only in display/summary output to the user. + +**On partial failure**: The `actions_taken` section MUST reflect the actual state — which actions completed and which failed. Set `label_creation_failed` to `true` if label creation failed due to permissions. Set `comment_posted` to `false` if the user aborted or the API call failed. + +--- + +## Guardrails + +1. **No auto-close**: MUST NOT close or lock any issue under any circumstances. The parent issue remains open even after splitting. The `duplicate` label is applied only with user confirmation. + +2. **No comments without confirmation**: Every issue comment is shown to the user before posting. No autonomous public communication. + +3. **No child issues without confirmation**: Every proposed child issue is presented to the user before creation. No autonomous issue creation. + +4. **Single issue per invocation**: The command processes exactly one issue. If the user provides multiple issue numbers, use only the first and ignore the rest with a warning. + +5. **gh CLI verification before API calls**: `which gh` and `gh auth status` MUST succeed before any GitHub API call. Specific error messages per prerequisite failure. + +6. **API failure handling**: When any `gh` CLI or API call fails (network error, HTTP 403 rate limit, HTTP 5xx), report the specific error, indicate which phase failed, and list any actions already completed. MUST NOT proceed with subsequent GitHub mutations after a failure. MUST still produce the artifact with `actions_taken` reflecting partial state. + +7. **Idempotent re-run**: On re-invocation for the same issue, detect previously applied labels (from issue data) to avoid duplication. Detect previously posted triage comments by checking for the Divisor review panel footer. Use round numbers for artifacts to preserve history. + +8. **Shell injection prevention**: All untrusted text (issue content, agent output, synthesized comments, child issue content) MUST be written to temporary files and passed via `--input` for all `gh api` calls. Untrusted text MUST NOT be interpolated into shell arguments. Temp files MUST use restrictive permissions (`chmod 600`) and be cleaned up in all exit paths (success, failure, abort). + +9. **Safe artifact paths**: The issue number is validated as a positive integer (matching `^[1-9][0-9]*$`) before use in any file path. This validation occurs in the Arguments section before any other processing. diff --git a/.opencode/commands/uf-init.md b/.opencode/commands/uf-init.md index 75ef899..82a798c 100644 --- a/.opencode/commands/uf-init.md +++ b/.opencode/commands/uf-init.md @@ -6,9 +6,6 @@ description: > updating the OpenSpec CLI. --- <!-- scaffolded by uf vdev --> -<!-- scaffolded by uf vdev --> -<!-- scaffolded by uf vdev --> -<!-- scaffolded by uf vv0.6.1 --> # Command: /uf-init @@ -26,6 +23,47 @@ or after updating the OpenSpec CLI (`npm update`). Safe to re-run ## Instructions +### Step 0: Command Directory Migration + +Check whether the legacy `.opencode/command/` directory needs +to be migrated to `.opencode/commands/`: + +1. Check if `.opencode/command/` exists (old directory): + ```bash + ls -d .opencode/command/ 2>/dev/null + ``` + +2. Check if `.opencode/commands/` exists (new directory): + ```bash + ls -d .opencode/commands/ 2>/dev/null + ``` + +3. **If old exists and new does NOT exist**: rename the + directory: + ```bash + mv .opencode/command .opencode/commands + ``` + Report: `✅ command/ → commands/: migrated` + +4. **If both exist**: move unique files from old to new, + remove duplicates from old, and clean up: + ```bash + # For each file in old dir, move if not in new, else remove + for f in .opencode/command/*; do + name="$(basename "$f")" + if [ -f ".opencode/commands/$name" ]; then + rm "$f" + else + mv "$f" .opencode/commands/ + fi + done + rmdir .opencode/command 2>/dev/null + ``` + Report: `✅ command/ → commands/: merged (old dir cleaned up)` + +5. **If old does NOT exist**: no migration needed. + Report: `⊘ command/ migration: not needed` + ### Step 1: Check Prerequisites Verify the project has been initialized: @@ -63,19 +101,27 @@ completes to review all changes before committing. ### Step 2: Apply Branch Enforcement For each target file listed below, apply the branch enforcement -customization. For each file: +customization. Each enforcement category has **independent** +idempotency checks -- presence of one variant MUST NOT cause +other variants to be skipped. For each file: 1. **Read** the file content -2. **Check** if branch enforcement is already present. Look for - the concept semantically -- does the file already describe - creating, validating, or cleaning up an `opsx/<name>` branch? - Check for phrases like `git checkout -b opsx/`, `opsx/<name>`, - `opsx/<change-name>`, or equivalent branch management - instructions. -3. **If already present**: Report `⊘ <filename>: already present (skipped)` -4. **If not present**: Read the file structure, find the correct - insertion point, and insert the customization. Report - `✅ <filename>: inserted` +2. **Check** each applicable variant independently: + - **Basic branch check**: Look for `opsx/<name>`, + `opsx/<change-name>`, or `git checkout -b opsx/` + - **Dirty tree check** (propose only): Look for + `git status --short` in a pre-branch-creation + context + - **Commit-before-archive** (archive-change only): + Look for `git add` and `git commit` appearing + before the archive move step + - **Branch-switch confirmation** (explore only): Look + for `uncommitted changes` or `switch branches` in + the guardrails section +3. **For each variant**: If present, report + `⊘ <filename>: [variant] already present (skipped)`. + If not present, insert it and report + `✅ <filename>: [variant] inserted` #### Branch Enforcement: Propose (Skills + Commands) @@ -83,8 +129,13 @@ customization. For each file: - `.opencode/skills/openspec-propose/SKILL.md` - `.opencode/commands/opsx-propose.md` -**What to insert**: After the step that creates the change -directory (`openspec new change "<name>"`), insert a new step: +**Two independent checks**: + +**A. Basic branch check** -- idempotency marker: +`opsx/<name>` or `git checkout -b opsx/` + +If not present, insert after the step that creates the +change directory (`openspec new change "<name>"`): > **Create and checkout a branch** > @@ -101,6 +152,32 @@ directory (`openspec new change "<name>"`), insert a new step: artifact creation steps. Insert as a new numbered step; do NOT renumber existing steps (to avoid accidental content loss). +**B. Dirty tree check** -- idempotency marker: +`git status --short` in a pre-branch-creation context + +If not present, insert before the branch creation guard +(part A above), or immediately before the existing branch +check if part A is already present: + +> **Check for uncommitted changes** +> +> Before creating or switching branches, run +> `git status --short`. If there are uncommitted changes +> (staged, unstaged, or untracked files that appear +> related to work): +> - **STOP** and ask the user for confirmation before +> switching branches. Show what uncommitted changes +> exist and warn that switching branches with a dirty +> working tree may cause changes to be applied to the +> wrong branch. +> - If the user confirms, proceed. If not, abort. +> - Exception: if the user explicitly requested a new +> change, this still requires confirmation -- never +> silently switch branches with uncommitted work. + +**Where**: Before the branch creation guard. Insert as a +sub-step or preceding step. + #### Branch Enforcement: Apply (Skills + Commands) **Target files**: @@ -129,8 +206,12 @@ existing steps. - `.opencode/skills/openspec-archive-change/SKILL.md` - `.opencode/commands/opsx-archive.md` -**What to insert**: After the archive move completes, insert a -branch cleanup step: +**Two independent checks**: + +**A. Return to main branch** -- idempotency marker: +`git checkout main` after the archive move + +If not present, insert after the archive move completes: > **Return to main branch** > @@ -147,10 +228,66 @@ branch cleanup step: the archive, before the display summary step. Insert as a new numbered step; do NOT renumber existing steps. -**Note**: `openspec-explore` and `opsx-explore.md` are -intentionally excluded from branch enforcement -- explore mode -does not create or modify changes, so branch management does -not apply. +**B. Commit-before-archive** -- idempotency markers: +`git add` and `git commit` appearing before the archive +move step + +If not present, insert before the archive move step +(the step that moves the change directory to the archive): + +> **Commit and push all changes** +> +> Before archiving, ensure all work is committed: +> +> 1. Run `git status --short` to check for uncommitted +> changes. +> 2. If uncommitted changes exist: +> - Stage the change directory and implementation +> files explicitly: +> `git add openspec/changes/<name>/ .opencode/` +> and any other modified files shown by +> `git status --short` +> - Commit with a descriptive message: +> `git commit -m "feat(<name>): complete implementation"` +> - Push to remote: `git push` +> 3. Verify the working tree is clean after push. +> +> **CRITICAL**: Do NOT move to the archive step with +> uncommitted changes. All work must be committed and +> pushed before the change directory is moved to the +> archive. + +**Where**: Before the step that moves the change directory +to the archive. Insert as a new numbered step; do NOT +renumber existing steps. + +#### Branch Enforcement: Explore (Guardrail Only) + +**Target file**: +- `.opencode/skills/openspec-explore/SKILL.md` + +**Note**: Explore mode does not create or modify changes, so +full branch management does not apply. However, explore may +lead to creating a proposal, which requires a branch switch. + +**Single check** -- idempotency marker: `uncommitted changes` +or `switch branches` in the guardrails section + +If not present, append this bullet to the explore SKILL.md +guardrails section: + +> - Don't switch branches without confirmation -- If +> exploration leads to creating a proposal (which +> requires a new `opsx/` branch), check for uncommitted +> changes first and ask the user before switching. +> Never silently leave uncommitted work behind. + +**Where**: Append to the existing guardrails bullet list +at the end of the file. + +Report: `✅ openspec-explore/SKILL.md: branch-switch +confirmation inserted` or `⊘ openspec-explore/SKILL.md: +branch-switch confirmation already present (skipped)` ### Step 3: Apply Dewey Context @@ -409,18 +546,43 @@ step: run `.specify/scripts/bash/check-prerequisites.sh ### Step 6: Speckit Command Guardrails Inject a `## Guardrails` section into ALL 9 -`.opencode/commands/speckit.*.md` files. For each file: +`.opencode/commands/speckit.*.md` files. Use two +variants depending on the command type. + +**Spec-phase commands** (get Guardrails WITH +review-rationale sentence): +- `speckit.specify.md` +- `speckit.clarify.md` +- `speckit.plan.md` +- `speckit.tasks.md` +- `speckit.analyze.md` +- `speckit.checklist.md` + +**Execution/utility commands** (get Guardrails WITHOUT +review-rationale sentence): +- `speckit.implement.md` +- `speckit.constitution.md` +- `speckit.taskstoissues.md` + +For each file: 1. **Read** the file content 2. **Check** if a `## Guardrails` section already exists (search for the heading text `## Guardrails`) -3. **If already present**: Report - `⊘ <filename>: guardrails already present (skipped)` -4. **If not present**: Append the following block at the - very end of the file. Report +3. **If NOT present**: Append the appropriate guardrails + variant at the very end of the file. Report `✅ <filename>: guardrails injected` +4. **If already present**: Perform a secondary check + for spec-phase commands only -- search for the phrase + "review defeats the purpose". If the Guardrails + heading exists but the review-rationale sentence is + missing, append the sentence to the existing + Guardrails section. Report + `✅ <filename>: review-rationale added`. + If the sentence is already present, report + `⊘ <filename>: guardrails already present (skipped)` -The guardrails block to append: +**Spec-phase guardrails block** (with review-rationale): ```markdown @@ -437,18 +599,30 @@ The guardrails block to append: - Files within `FEATURE_DIR` (spec artifacts: plan.md, tasks.md, research.md, data-model.md, quickstart.md, contracts/, checklists/) +- The user needs to review the plan before + implementation begins. Implementing without review + defeats the purpose of the spec-first workflow. ``` -The 9 target files are: -- `speckit.specify.md` -- `speckit.clarify.md` -- `speckit.plan.md` -- `speckit.tasks.md` -- `speckit.analyze.md` -- `speckit.checklist.md` -- `speckit.implement.md` -- `speckit.constitution.md` -- `speckit.taskstoissues.md` +**Execution/utility guardrails block** (no +review-rationale): + +```markdown + +## Guardrails + +- **NEVER modify source code** — this command updates + spec artifacts ONLY. Implementation changes belong in + `/speckit.implement`, `/unleash`, or `/cobalt-crush`. +- **NEVER modify test files, Go source, Markdown agents, + convention packs, or config files** outside the + `specs/NNN-*/` feature directory. +- The ONLY files this command may write are: + - `FEATURE_SPEC` (the spec.md file) + - Files within `FEATURE_DIR` (spec artifacts: + plan.md, tasks.md, research.md, data-model.md, + quickstart.md, contracts/, checklists/) +``` **Note**: `speckit.implement.md` is an exception — it IS allowed to modify source code. However, the guardrails @@ -511,396 +685,13 @@ The guardrails block to append: tasks) - **NEVER commit, push, or create PRs** — those are /finale's responsibility -- **NEVER run /opsx-apply or /cobalt-crush** — the - user decides when to implement +- **NEVER run /unleash, /opsx-apply, or /cobalt-crush** + — the user decides when to implement - After artifacts are complete, STOP and prompt the - user to run /opsx-apply or /cobalt-crush -``` - -### Step 9: AGENTS.md Behavioral Guidance - -For the repo's `AGENTS.md` file, inject standardized -behavioral guidance sections if not already present. - -1. **Check** if `AGENTS.md` exists at the repo root. - If not, report `⊘ AGENTS.md: not found (skipped)` - and skip this entire step. - -2. **Read** the full contents of `AGENTS.md`. - -3. For each of the 8 guidance blocks below, in the order - listed (Core Mission first, Knowledge Retrieval last): - a. Check if the detection phrase (or semantic - equivalent heading) exists in the file - b. If present: report `⊘ <block>: already present - (skipped)` - c. If not present: find the appropriate insertion - point per the placement guidance and append the - block text. Report `✅ <block>: injected` - -4. After processing all 8 blocks, save the file once. - -**Injection order** (optimized for document flow): -1. Core Mission -2. Gatekeeping Value Protection -3. Workflow Phase Boundaries -4. CI Parity Gate -5. Review Council PR Prerequisite -6. Spec-First Development -7. Website Documentation Sync Gate -8. Knowledge Retrieval - -#### Block 1: Core Mission - -**Detection phrases**: `## Core Mission`, or both -`Strategic Architecture` AND `Outcome Orientation` -present in the same section. - -**Placement**: After `## Project Overview`, before -`## Behavioral Constraints`. If neither heading exists, -append near the top of the file after any frontmatter -and title. - -**Text to inject**: - -```markdown -## Core Mission - -- **Strategic Architecture**: Engineers shift from manual - coding to directing an "infinite supply of junior - developers" (AI agents). -- **Outcome Orientation**: Focus on conveying business - value and user intent rather than low-level technical - sub-tasks. -- **Intent-to-Context**: Treat specs and rules as the - medium through which human intent is manifested into - code. -``` - -#### Block 2: Gatekeeping Value Protection - -**Detection phrases**: `Gatekeeping Value Protection` -heading, or `MUST NOT modify values that serve as -quality`. - -**Placement**: Inside `## Behavioral Constraints` -section. If `## Behavioral Constraints` does not exist, -create it and place it after `## Core Mission` (or after -`## Project Overview` if Core Mission is absent). - -**Text to inject**: - -```markdown -### Gatekeeping Value Protection - -Agents MUST NOT modify values that serve as quality or -governance gates to make an implementation pass. The -following categories are protected: - -1. **Coverage thresholds and CRAP scores** — minimum - coverage percentages, CRAP score limits, coverage - ratchets -2. **Severity definitions and auto-fix policies** — - CRITICAL/HIGH/MEDIUM/LOW boundaries, auto-fix - eligibility rules -3. **Convention pack rule classifications** — - MUST/SHOULD/MAY designations on convention pack rules - (downgrading MUST to SHOULD is prohibited) -4. **CI flags and linter configuration** — `-race`, - `-count=1`, `govulncheck`, `golangci-lint` rules, - pinned action SHAs -5. **Agent temperature and tool-access settings** — - frontmatter `temperature`, `tools.write`, `tools.edit`, - `tools.bash` restrictions -6. **Constitution MUST rules** — any MUST rule in - `.specify/memory/constitution.md` or hero constitutions -7. **Review iteration limits and worker concurrency** — - max review iterations, max concurrent Swarm workers, - retry limits -8. **Workflow gate markers** — `<!-- spec-review: passed - -->`, task completion checkboxes used as gates, phase - checkpoint requirements - -**What to do instead**: When an implementation cannot -meet a gate, the agent MUST stop, report which gate is -blocking and why, and let the human decide whether to -adjust the gate or rework the implementation. Modifying -a gate without explicit human authorization is a -constitution violation (CRITICAL severity). + user to run /unleash, /opsx-apply, or /cobalt-crush ``` -#### Block 3: Workflow Phase Boundaries - -**Detection phrases**: `Workflow Phase Boundaries` -heading, or `MUST NOT cross workflow phase boundaries`. - -**Placement**: Inside `## Behavioral Constraints`, -after Gatekeeping Value Protection (if present). If -`## Behavioral Constraints` does not exist, create it. - -**Text to inject**: - -```markdown -### Workflow Phase Boundaries - -Agents MUST NOT cross workflow phase boundaries: - -- **Specify/Clarify/Plan/Tasks/Analyze/Checklist** phases: - spec artifacts ONLY (`specs/NNN-*/` directory). No - source code, test, agent, command, or config changes. -- **Implement** phase: source code changes allowed, - guided by spec artifacts. -- **Review** phase: findings and minor fixes only. No new - features. - -A phase boundary violation is treated as a process error. -The agent MUST stop and report the violation rather than -proceeding with out-of-phase changes. -``` - -#### Block 4: CI Parity Gate - -**Detection phrases**: `CI Parity Gate` heading or bold -text, or `replicate the CI checks locally`. - -**Placement**: Inside `## Behavioral Constraints` or -`## Technical Guardrails`, after Workflow Phase -Boundaries (if present). If neither section exists, -create `## Behavioral Constraints` and place it there. - -**Text to inject**: - -```markdown -### CI Parity Gate - -Before marking any implementation task complete or -declaring a PR ready, agents MUST replicate the CI checks -locally. Read `.github/workflows/` to identify the exact -commands CI runs, then execute those same commands. Any -failure is a blocking error — a task is not complete -until all CI-equivalent checks pass locally. Do not rely -on a memorized list of commands; always derive them from -the workflow files, which are the source of truth. -``` - -#### Block 5: Review Council PR Prerequisite - -**Detection phrases**: Both `Review Council` AND -`PR Prerequisite` present, or `/review-council` as a -command reference in a PR workflow context. - -**Placement**: After behavioral constraints, before -build commands or testing conventions. If no clear -anchor exists, append after the last behavioral -constraint block. - -**Text to inject**: - -```markdown -### Review Council as PR Prerequisite - -Before submitting a pull request, agents **must** run -`/review-council` and resolve all REQUEST CHANGES -findings until all reviewers return APPROVE. There must -be **minimal to no code changes** between the council's -APPROVE verdict and the PR submission — the council -reviews the final code, not a draft that changes -afterward. - -Workflow: - -1. Complete all implementation tasks -2. Run CI checks locally (build, test, vet) -3. Run `/review-council` — fix any findings, re-run - until APPROVE -4. Commit, push, and submit PR immediately after council - APPROVE -5. Do NOT make further code changes between APPROVE and - PR submission - -Exempt from council review: - -- Constitution amendments (governance documents, not code) -- Documentation-only changes (README, AGENTS.md, spec - artifacts) -- Emergency hotfixes (must be retroactively reviewed) -``` - -#### Block 6: Spec-First Development - -**Detection phrases**: `Spec-First Development` heading, -or `preceded by a spec workflow`. - -**Placement**: After behavioral constraints, before -build commands. If no clear anchor exists, append after -the last behavioral constraint or workflow rule block. - -**Text to inject**: - -```markdown -## Spec-First Development - -All changes that modify production code, test code, agent -prompts, embedded assets, or CI configuration **must** be -preceded by a spec workflow. The constitution -(`.specify/memory/constitution.md`) is the highest- -authority document in this project — all work must align -with it. - -Two spec workflows are available: - -| Workflow | Location | Best For | -|----------|----------|----------| -| **Speckit** | `specs/NNN-name/` | Numbered feature specs with the full pipeline | -| **OpenSpec** | `openspec/changes/name/` | Targeted changes with lightweight artifacts | - -**What requires a spec** (no exceptions without explicit -user override): - -- New features or capabilities -- Refactoring that changes function signatures, extracts - helpers, or moves code between packages -- Test additions or assertion strengthening across - multiple functions -- Agent prompt changes -- CI workflow modifications -- Data model changes (new struct fields, schema updates) - -**What is exempt** (may be done directly): - -- Constitution amendments (governed by the constitution's - own Governance section) -- Typo corrections, comment-only changes, single-line - formatting fixes -- Emergency hotfixes for critical production bugs (must - be retroactively documented) - -When an agent is unsure whether a change is trivial, it -**must** ask the user rather than proceeding without a -spec. The cost of an unnecessary spec is minutes; the -cost of an unplanned change is rework, drift, and broken -CI. -``` - -#### Block 7: Website Documentation Sync Gate - -**Detection phrases**: `Website Documentation` AND -`Gate` in a heading, or `gh issue create --repo` with -`unbound-force/website`. - -**Placement**: Near documentation validation gate or -spec commit gate. If no clear anchor exists, append -after Spec-First Development. - -**Text to inject**: - -````markdown -### Website Documentation Gate - -When a change affects user-facing behavior, hero -capabilities, CLI commands, or workflows, a GitHub issue -**MUST** be created in the `unbound-force/website` -repository to track required documentation or website -updates. The issue must be created before the -implementing PR is merged. - -```bash -gh issue create --repo unbound-force/website \ - --title "docs: <brief description of what changed>" \ - --body "<what changed, why it matters, which pages - need updating>" -``` - -**Exempt changes** (no website issue needed): -- Internal refactoring with no user-facing behavior - change -- Test-only changes -- CI/CD pipeline changes -- Spec artifacts (specs are internal planning documents) - -**Examples requiring a website issue**: -- New CLI command or flag added -- Hero capabilities changed (new agent, removed feature) -- Installation steps changed (`uf setup` flow) -- New convention pack added -- Breaking changes to any user-facing workflow -```` - -#### Block 8: Knowledge Retrieval - -**Detection phrases**: `## Knowledge Retrieval` heading, -or `dewey_semantic_search` as a tool reference (in a -table or code block, not just prose), or -`Tool Selection Matrix`. - -**Placement**: After coding conventions, before testing -conventions. If neither section exists, append near the -end of the file before any appendix or changelog. - -**Text to inject**: - -```markdown -## Knowledge Retrieval - -Agents SHOULD prefer Dewey MCP tools over grep/glob/read -for cross-repo context, design decisions, and -architectural patterns. Dewey provides semantic search -across all indexed Markdown files, specs, and web -documentation — returning ranked results with provenance -metadata that grep cannot match. - -### Tool Selection Matrix - -| Query Intent | Dewey Tool | When to Use | -|-------------|-----------|-------------| -| Conceptual understanding | `dewey_semantic_search` | "How does X work?" | -| Keyword lookup | `dewey_search` | Known terms, FR numbers | -| Read specific page | `dewey_get_page` | Known document path | -| Relationship discovery | `dewey_find_connections` | "How are X and Y related?" | -| Similar documents | `dewey_similar` | "Find specs like this one" | -| Tag-based discovery | `dewey_find_by_tag` | "All pages tagged #decision" | -| Property queries | `dewey_query_properties` | "All specs with status: draft" | -| Filtered semantic | `dewey_semantic_search_filtered` | Semantic search within source type | -| Graph navigation | `dewey_traverse` | Dependency chain walking | - -### When to Fall Back to grep/glob/read - -Use direct file operations instead of Dewey when: -- **Dewey is unavailable** — MCP tools return errors or - are not configured -- **Exact string matching is needed** — searching for a - specific error message, variable name, or code pattern -- **Specific file path is known** — reading a file you - already know the path to (use Read directly) -- **Binary/non-Markdown content** — Dewey indexes - Markdown; use grep for Go source, JSON, YAML, etc. - -### Graceful Degradation (3-Tier Pattern) - -**Tier 3 (Full Dewey)** — semantic + structured search: -- `dewey_semantic_search` — natural language queries -- `dewey_search` — keyword queries -- `dewey_get_page`, `dewey_find_connections`, - `dewey_traverse` — structured navigation -- `dewey_find_by_tag`, `dewey_query_properties` — - metadata queries - -**Tier 2 (Graph-only, no embedding model)** — structured -search only: -- `dewey_search` — keyword queries (no embeddings needed) -- `dewey_get_page`, `dewey_traverse`, - `dewey_find_connections` — graph navigation -- `dewey_find_by_tag`, `dewey_query_properties` — - metadata queries -- Semantic search unavailable — use exact keyword matches - -**Tier 1 (No Dewey)** — direct file access: -- Use Read tool for direct file access -- Use Grep for keyword search across the codebase -- Use Glob for file pattern matching -``` - -### Step 10: Report Results +### Step 9: Report Results After processing all customizations, display a summary: @@ -940,15 +731,17 @@ After processing all customizations, display a summary: [status] [filename]: [action] ... -### AGENTS.md Guidance - [status] Core Mission: [action] - [status] Gatekeeping Value Protection: [action] - [status] Workflow Phase Boundaries: [action] - [status] CI Parity Gate: [action] - [status] Review Council PR Prerequisite: [action] - [status] Spec-First Development: [action] - [status] Website Documentation Sync Gate: [action] - [status] Knowledge Retrieval: [action] +### STOP HERE Blocks + [status] [filename]: [action] + ... + +### Scaffold Comment Deduplication + [status] [filename]: [action] + ... + +### Legacy Directory Cleanup + [status] [item]: [action] + ... ### Summary Applied: N | Already present: N | Errors: N @@ -959,6 +752,121 @@ Use these status indicators: - `⊘` -- customization already present (skipped) - `❌` -- file not found or error (with fix suggestion) +### Step 10: STOP HERE Blocks + +Inject a STOP HERE block into each spec-phase speckit +command file. The block prevents premature advancement +to implementation by instructing the LLM to stop and +prompt the user. + +**Target files** (spec-phase commands only): +- `speckit.specify.md` +- `speckit.plan.md` +- `speckit.tasks.md` +- `speckit.analyze.md` +- `speckit.checklist.md` +- `speckit.clarify.md` + +**Excluded** (execution/utility commands -- no STOP HERE): +- `speckit.implement.md` +- `speckit.constitution.md` +- `speckit.taskstoissues.md` + +For each target file: + +1. **Read** the file content +2. **Check** if "STOP HERE" (case-sensitive) is already + present in the file +3. **If already present**: Report + `⊘ <filename>: STOP HERE already present (skipped)` +4. **If not present**: Insert the STOP HERE block. Report + `✅ <filename>: STOP HERE inserted` + +**What to insert**: + +```markdown + +**STOP HERE. Do NOT proceed to implementation.** + +Your job is done. Report the results and prompt the +user. The user will invoke a separate command +(`/speckit.implement`, `/unleash`, or `/cobalt-crush`) +when they are ready to implement. +``` + +**Where**: After the main workflow instructions, before +the `## Guardrails` section. If no `## Guardrails` +section exists, insert at the end of the file. + +### Step 11: Scaffold Comment Deduplication + +Deduplicate scaffold comments in all files processed by +`/uf-init`. Repeated runs of `uf init` across versions +can accumulate multiple `<!-- scaffolded by uf ... -->` +comments in the same file. + +**Target scope**: All files processed by `/uf-init`: +- The 4 OpenSpec skill files (Step 2-4 targets) +- The 3 OpenSpec command files (Step 2-3 targets) +- The 9 speckit command files (Step 5-6 targets) + +For each file: + +1. **Read** the file content +2. **Count** lines matching the pattern + `<!-- scaffolded by uf` (any version string after "uf") +3. **If 0 or 1 matches**: No action needed. Report + `⊘ <filename>: scaffold comments clean` +4. **If 2+ matches**: Keep only the LAST occurrence, + remove all earlier occurrences. Report + `✅ <filename>: deduplicated scaffold comments + (N removed)` + +**Important**: This step runs AFTER all other insertion +steps to catch any duplicates introduced by earlier steps. + +### Step 12: Legacy Directory Cleanup + +Clean up legacy directory artifacts from older versions +of `uf init`. + +Set `LEGACY_PACKS = .opencode/` + `unbound/packs/` +(the pre-Spec-025 convention pack location). + +#### Sub-task A: Legacy Packs Removal + +1. Check if `LEGACY_PACKS` exists +2. **If it does NOT exist**: Report + `⊘ legacy packs: not present` +3. **If it exists**: Verify pre-conditions: + - `.opencode/uf/packs/default.md` MUST exist + - `.opencode/uf/packs/severity.md` MUST exist +4. **If pre-conditions met**: Remove `LEGACY_PACKS` + recursively (NOT its parent directory). Then check + if the parent directory is empty -- if so, remove it + too. If the parent still contains other files or + directories, leave it and report a warning: + `⚠️ legacy parent dir: packs/ removed but directory + contains other content -- leaving in place`. + Report `✅ legacy packs: removed (migrated to + uf/packs/)` +5. **If pre-conditions NOT met**: Report + `❌ legacy packs: uf/packs/ missing core files, + skipped` + +#### Sub-task B: `command/` Migration Hardening + +After Step 0 runs (command directory migration), verify +the migration was effective: + +1. Check if any `speckit.*.md` files remain in + `.opencode/command/` (singular) +2. **If found**: Report + `⚠️ command/: speckit commands still in singular + directory after migration -- check Step 0 output` +3. **If not found**: Report + `⊘ command/: migration verified (or not needed)` + ### Post-Write Verification After all customizations are applied, for each file that was @@ -979,6 +887,8 @@ Finally, remind the user: After customizations are applied: +- Run `/unleash` for autonomous pipeline execution + (parallel swarm, recommended for multi-task changes) - Run `/cobalt-crush` to start implementing — it auto-detects your active workflow (Speckit or OpenSpec) and delegates to the correct implementation command. @@ -1017,6 +927,7 @@ Re-run `/uf-init` after: - Running `uf init` or `uf setup` (new tool versions may reset third-party files) - Updating the OpenSpec CLI (`npm update`) -- Upgrading the `uf` binary (`brew upgrade unbound-force` - — new versions may add scaffold files that need - customization) +- Upgrading the `uf` binary (`brew upgrade unbound-force`, + or on Fedora/RHEL: `sudo dnf upgrade unbound-force` + — new versions may add scaffold files that need + customization) diff --git a/.opencode/commands/unleash.md b/.opencode/commands/unleash.md index b070809..eedf81a 100644 --- a/.opencode/commands/unleash.md +++ b/.opencode/commands/unleash.md @@ -8,8 +8,6 @@ description: > needs human judgment. --- <!-- scaffolded by uf vdev --> -<!-- scaffolded by uf vdev --> -<!-- scaffolded by uf vdev --> # Command: /unleash @@ -329,12 +327,13 @@ analysis + quality validation) in a single pass. Parse `FEATURE_DIR/tasks.md` for phases and execute tasks. -**Derive build/test commands**: Read all files in -`.github/workflows/` to identify the exact CI commands -(build, test, vet, lint). Do NOT hardcode language- -specific commands -- the workflow files are the source -of truth. This is the same pattern used by -`/review-council` Phase 1a. +**Derive build/test commands**: Load the `pre-flight` +skill (invoke the `skill` tool with name `pre-flight`) +and use its CI Workflow Parsing phase to discover the +exact CI commands from `.github/workflows/`. Also run +its Local Tool Detection phase to discover additional +tools from config files. This is the shared pre-flight +logic used by `/review-council` and `/review-pr`. **For each phase in tasks.md**: @@ -450,8 +449,8 @@ of truth. This is the same pattern used by 4. **Phase checkpoint**: after all tasks in the phase are complete (both sequential and parallel), run the - CI build and test commands derived from - `.github/workflows/`. + pre-flight skill in `hard-gate` mode to execute all + detected CI and local tool commands. - If all pass: proceed to the next phase. - If any fail: **EXIT** with the failure details: @@ -604,8 +603,8 @@ Present structured demo instructions to the developer. most recent build/test checkpoint. 5. **Next Steps**: always present these options: - - `/finale` to commit, push, create PR, merge, and - return to main + - `/finale` to commit, push, create PR, and return + to main - `/speckit.clarify` to refine the spec and re-run `/unleash` @@ -631,7 +630,7 @@ Format the output as: ## Next Steps -- Run `/finale` to merge and release +- Run `/finale` to create PR and watch CI - Run `/speckit.clarify` to refine and iterate ``` @@ -657,6 +656,6 @@ Format the output as: - **NEVER create WorkflowInstance objects** -- `/unleash` operates at the Speckit pipeline level, not the hero lifecycle workflow level (Specs 008/012/016) -- **NEVER hardcode build/test commands** -- derive them - from `.github/workflows/` (CI files are source of - truth) +- **NEVER hardcode build/test commands** -- load the + `pre-flight` skill to derive them from + `.github/workflows/` and local tool configs diff --git a/.opencode/skills/always-on-guidance/SKILL.md b/.opencode/skills/always-on-guidance/SKILL.md new file mode 100644 index 0000000..70ed48e --- /dev/null +++ b/.opencode/skills/always-on-guidance/SKILL.md @@ -0,0 +1,47 @@ +--- +name: always-on-guidance +description: Global coding rules and tool usage discipline +tags: [always-on, coding, quality] +--- + +# Always-On Guidance + +Rules that apply to every coding session. + +## Tool Usage Discipline + +- Read files before editing — never guess at content +- Use `org_*` tools for work item management +- Use `comms_*` tools for agent messaging and file reservations +- Use `forge_*` tools for multi-agent coordination +- Use `hivemind_*` tools for learning storage and retrieval +- Check `hivemind_find` before solving problems from scratch + +## Code Quality + +- Functions do one thing well +- Names reveal intent — no abbreviations +- Comments explain *why*, not *what* +- No dead code or unused imports +- Error messages include context + +## Testing + +- Write tests for all new code +- Use `db.OpenMemory()` for database tests +- Use `t.TempDir()` for filesystem tests +- Standard library `testing` package only — no testify +- Test names: `TestXxx_Description` + +## Error Handling + +- Return errors, don't panic +- Wrap errors with context: `fmt.Errorf("operation: %w", err)` +- Handle all error paths — no ignored returns +- Use `errors.Is` for sentinel error checks + +## Git Discipline + +- Conventional commits: `type: description` +- Never force push to main +- Commit early, commit often diff --git a/.opencode/skills/forge-coordination/SKILL.md b/.opencode/skills/forge-coordination/SKILL.md new file mode 100644 index 0000000..a0dcdd3 --- /dev/null +++ b/.opencode/skills/forge-coordination/SKILL.md @@ -0,0 +1,62 @@ +--- +name: forge-coordination +description: Multi-agent coordination patterns for forge sessions +tags: [forge, coordination, multi-agent] +--- + +# Forge Coordination + +Patterns for coordinating parallel agent work. + +## Coordinator Protocol + +1. **Initialize**: `comms_init(project_path=".", task_description="...")` +2. **Check learnings**: `hivemind_find(query="<task keywords>")` +3. **Select strategy**: `forge_get_strategy_insights(task="<task>")` +4. **Decompose**: `forge_decompose(task="<task>", context="<learnings>")` +5. **Create epic**: `org_create_epic(epic_title="<task>", subtasks=[...])` +6. **Spawn workers**: `forge_spawn_subtask(bead_id, epic_id, subtask_title, files)` +7. **Monitor**: `comms_inbox()` + `forge_status(epic_id, project_key)` +8. **Review**: `forge_review(task_id, files_touched)` for each worker +9. **Complete**: `forge_complete(bead_id, summary, files_touched)` +10. **Learn**: `hivemind_store(information="...", tags="forge,<topic>")` + +## Worker Protocol + +1. **Initialize**: `comms_init(project_path=".", task_description="...")` +2. **Check learnings**: `hivemind_find(query="<task keywords>")` +3. **Reserve files**: `comms_reserve(paths=[...], reason="...")` +4. **Implement**: Make changes to reserved files +5. **Report progress**: `forge_progress(bead_id, progress_percent, status)` +6. **Store learnings**: `hivemind_store(information="...", tags="...")` +7. **Complete**: `forge_complete(bead_id, summary, files_touched)` + +## File Reservation Rules + +- Workers MUST reserve files before editing +- Coordinators NEVER reserve files +- Use `comms_reserve(paths=[...], exclusive=true)` for exclusive access +- Release files when done: `comms_release(paths=[...])` +- Emergency release: `comms_release_all()` (coordinator only) + +## Progress Reporting + +Report at milestones: 25%, 50%, 75%, 100% + +``` +forge_progress( + project_key="replicator", + agent_name="worker-1", + bead_id="<id>", + status="in_progress", + progress_percent=50, + message="Implemented core logic, starting tests" +) +``` + +## Conflict Resolution + +If a file reservation fails: +1. Check who holds the reservation +2. Send a message via `comms_send` to negotiate +3. Wait for release or escalate to coordinator diff --git a/.opencode/skills/forge-global/SKILL.md b/.opencode/skills/forge-global/SKILL.md new file mode 100644 index 0000000..f6d0dbe --- /dev/null +++ b/.opencode/skills/forge-global/SKILL.md @@ -0,0 +1,52 @@ +--- +name: forge-global +description: Cross-project forge coordination patterns +tags: [forge, global, coordination] +--- + +# Forge Global + +Patterns for forge coordination that apply across projects. + +## When to Forge + +Use a forge when: +- Task touches 3+ files +- Task has independent subtasks that can parallelize +- Task benefits from specialized workers (e.g., tests vs implementation) + +Don't forge when: +- Task is a single-file change +- Task requires sequential steps with tight coupling +- Task is exploratory or investigative + +## File Reservation Protocol + +1. Workers MUST call `comms_reserve(paths=[...])` before editing +2. Reservations are exclusive by default +3. Set `ttl_seconds` to auto-release after timeout +4. Always release when done: `comms_release(paths=[...])` +5. Coordinator can emergency release: `comms_release_all()` + +## Worker Spawning + +Each worker gets: +- A bead ID (cell in the org) +- An epic ID (parent cell) +- A list of assigned files +- Shared context from the coordinator + +Workers operate independently and report back via comms. + +## Broadcast + +Coordinator can broadcast context updates to all workers: + +``` +forge_broadcast( + project_path=".", + agent_name="coordinator", + epic_id="<id>", + message="API contract changed, update imports" +) +``` diff --git a/.opencode/skills/learning-systems/SKILL.md b/.opencode/skills/learning-systems/SKILL.md new file mode 100644 index 0000000..5533eed --- /dev/null +++ b/.opencode/skills/learning-systems/SKILL.md @@ -0,0 +1,64 @@ +--- +name: learning-systems +description: How the forge learns from outcomes +tags: [learning, forge, insights] +--- + +# Learning Systems + +The forge improves over time by recording outcomes and querying insights. + +## Recording Outcomes + +After every forge completion, record the outcome: + +``` +forge_record_outcome( + bead_id="<id>", + duration_ms=120000, + success=true, + strategy="file-based", + files_touched=["internal/foo/bar.go"], + error_count=0, + retry_count=0 +) +``` + +## Querying Insights + +### Strategy Insights + +Which decomposition strategies work best: + +``` +forge_get_strategy_insights(task="<task description>") +``` + +Returns success rates for file-based, feature-based, and risk-based strategies. + +### File Insights + +Historical gotchas for specific files: + +``` +forge_get_file_insights(files=["internal/foo/bar.go"]) +``` + +Returns past failure patterns, edge cases, and performance traps. + +### Pattern Insights + +Common failure patterns across all forges: + +``` +forge_get_pattern_insights() +``` + +Returns top 5 most frequent failure patterns with recommendations. + +## When to Store vs Query + +- **Store** after completing work: learnings, decisions, gotchas +- **Query** before starting work: check if someone solved it before +- Use `hivemind_store` for general learnings +- Use `forge_record_outcome` for structured forge metrics diff --git a/.opencode/skills/pre-flight/SKILL.md b/.opencode/skills/pre-flight/SKILL.md new file mode 100644 index 0000000..f9a1f1b --- /dev/null +++ b/.opencode/skills/pre-flight/SKILL.md @@ -0,0 +1,422 @@ +--- +name: pre-flight +description: "Shared pre-flight skill for CI detection and local tool execution. Supports hard-gate, ci-aware, and soft-gate execution policies." +--- +<!-- scaffolded by uf vdev --> +# Skill: Pre-flight Checks + +Shared logic for CI workflow detection, local tool +detection, CI coverage matrix generation, and local tool +execution. Consuming commands load this skill and select +an execution policy. + +## Execution Policies + +| Mode | Behavior | Typical consumer | +|------|----------|-----------------| +| `hard-gate` | Run all detected tools. Stop on first failure. | `/unleash` (phase checkpoints) | +| `ci-aware` | Build CI coverage matrix against PR check results. Skip tools CI already verified. Run the rest. | `/review-pr` | +| `soft-gate` | Run all detected tools. Classify failures as branch-caused vs pre-existing. Gate only on branch-caused failures. | `/review-council` | + +The consuming command specifies which mode to use. + +--- + +## Phase 1: CI Workflow Parsing + +Read all files in `.github/workflows/` to identify the +exact commands CI runs. Do NOT hardcode language-specific +commands — the workflow files are the source of truth. + +### Extraction rules + +- Extract only `run:` step commands from workflow YAML. +- **Ignore** `uses:` steps — these are GitHub-hosted + actions and are not locally executable. +- **Skip** commands containing unresolvable CI expressions + (`${{ secrets.* }}`, `${{ github.* }}`) with a warning + noting unresolvable CI expressions. These commands + depend on CI runtime context and cannot run locally. +- Multi-line `run:` blocks: extract each command line + individually. Skip lines that are pure shell control + flow (if/then/fi, variable assignments used only + within the block). + +### Output + +A list of CI commands discovered from workflows, e.g.: + +``` +CI commands discovered from .github/workflows/: + - go build ./... (ci_local.yml) + - go test -race -count=1 -coverprofile=coverage.out ./... (ci_local.yml) +``` + +If no `.github/workflows/` directory exists, report +"No CI workflows found" and proceed to Phase 2. + +--- + +## Phase 2: Local Tool Detection + +Check which tools are available by looking for their +configuration files: + +```bash +test -f Makefile && echo "MAKEFILE=yes" +test -f .golangci.yml && echo "GO_LINT=yes" +test -f ruff.toml -o -f pyproject.toml && echo "PYTHON_LINT=yes" +test -f .yamllint.yml && echo "YAML_LINT=yes" +test -f .pre-commit-config.yaml && echo "PRECOMMIT=yes" +test -f go.mod && echo "GO_TEST=yes" +test -f setup.py && echo "PYTHON_TEST=yes" +``` + +When `pyproject.toml` is present, detect both ruff and +pytest as separate tools. + +### Tool-to-command mapping + +| Config file | Tool | Command | What it checks | +|-------------|------|---------|----------------| +| `Makefile` | Make | `make check` (preferred), else `make lint` | Project-defined lint/format/vet | +| `.golangci.yml` | golangci-lint | `golangci-lint run ./...` | Go lint rules | +| `ruff.toml` or `pyproject.toml` | ruff | `ruff check .` | Python lint rules | +| `.yamllint.yml` | yamllint | `yamllint .` | YAML lint rules | +| `.pre-commit-config.yaml` | pre-commit | `pre-commit run --all-files` | Pre-commit hooks | +| `go.mod` | go test | `go test ./...` | Go tests | +| `pyproject.toml` or `setup.py` | pytest | `pytest` or `python -m pytest` | Python tests | + +### Binary availability check + +For each detected tool, verify the binary is available: + +```bash +which <binary-name> +``` + +If a config file is present but the tool binary is NOT +in PATH, report the tool as "detected but not available" +and skip it with a warning. Do NOT treat a missing binary +as a hard failure. + +### Output + +A list of detected tools with availability status, e.g.: + +``` +Local tools detected: + - Make (Makefile) ✓ available + - golangci-lint (.golangci.yml) ✓ available + - yamllint (.yamllint.yml) ✗ not available (skipped) +``` + +If no tools are detected, report "No local tools detected" +and proceed to Phase 3. + +--- + +## Phase 3: CI Coverage Matrix + +Build and display a coverage matrix that maps each +detected local tool to the CI check that covers the same +verification. This matrix makes the skip/run decision +visible and auditable. + +### Matrix construction + +For each detected and available tool, determine which CI +check (if any) covers the same verification. Map tool +names to CI check names by matching on the tool's purpose +(e.g., `go test` maps to a CI check containing "test", +`golangci-lint` maps to a check containing "lint"). + +### Decision rules (ci-aware mode) + +| CI status | Run locally? | Rationale | +|-----------|-------------|-----------| +| PASS | No | CI already verified | +| FAIL | No | Failure already captured from CI; will be included in AI review context | +| NONE (no matching check) | Yes | No CI coverage for this tool | +| No CI checks at all | Yes (all tools) | Cannot determine CI coverage | + +### Decision rules (hard-gate mode) + +In hard-gate mode, ALL detected and available tools are +marked "Run locally = Yes" regardless of CI status. The +CI status column in the matrix shows the actual status if +available, or "N/A" if CI results were not provided. The +coverage matrix is still displayed for visibility, but +skip decisions are not applied. + +### Display format + +``` +### CI Coverage Matrix +| Local tool | CI check | CI status | Run locally? | +|------------|----------|-----------|--------------| +| go test | Local CI / test | PASS | No | +| golangci-lint | CI Checks / lint | PASS | No | +| yamllint | (none) | NONE | Yes | +``` + +--- + +## Phase 4: Execution + +Run only the tools marked "Run locally = Yes" in the +coverage matrix. + +### hard-gate mode + +Execute each tool in order. If any tool exits with a +non-zero exit code: + +1. **STOP immediately** — do not run remaining tools. +2. Report the failure as a CRITICAL finding with the + full error output. +3. The consuming command MUST NOT proceed to AI review + or implementation. + +If all tools pass, report success. + +### ci-aware mode + +Execute each tool marked "Yes" in the coverage matrix. +Record all exit codes and output. + +- If tools pass: skip those categories in AI review. +- If tools fail: include the failure output as context + for AI review. Do NOT stop — the consuming command + decides how to handle failures. + +If no tools are marked "Yes" (all covered by CI): report +"All tools covered by CI — no local execution needed." + +### soft-gate mode + +Execute ALL detected and available tools (same as +hard-gate). Do NOT stop on first failure — record all +exit codes and output for every tool. + +- If ALL tools pass: verdict is PASS. No baseline + establishment is needed. Skip Phase 4a and 4b. +- If ANY tools fail: proceed to Phase 4a (Baseline + Establishment) to classify each failure. + +--- + +## Phase 4a: Baseline Establishment (soft-gate only) + +This phase runs only in `soft-gate` mode, and only when +at least one tool failed during Phase 4 execution. + +Establish a baseline for the default branch to determine +which failures are branch-caused vs pre-existing. Use a +two-tier strategy: CI API first, local worktree fallback. + +### Detect the default branch + +Before establishing a baseline, detect the repository's +default branch. Do NOT hardcode `main` — repositories +may use `master` or another default branch name. + +```bash +DEFAULT_BRANCH=$(git symbolic-ref \ + refs/remotes/origin/HEAD 2>/dev/null \ + | sed 's|refs/remotes/origin/||') +``` + +If that fails (remote HEAD not set, which happens after +a fresh clone without +`git remote set-head origin --auto`), fall back to +checking for common names: + +```bash +if [ -z "${DEFAULT_BRANCH}" ]; then + if git rev-parse --verify origin/main \ + >/dev/null 2>&1; then + DEFAULT_BRANCH="main" + elif git rev-parse --verify origin/master \ + >/dev/null 2>&1; then + DEFAULT_BRANCH="master" + fi +fi +``` + +If neither resolves, treat the baseline as unavailable +and fall through to the conservative fallback (all +failures classified as `unknown` = branch-caused). + +### Tier 1 — CI API baseline + +Check if the `gh` CLI is available: + +```bash +which gh +``` + +If `gh` is available, query the latest check-run results +for the default branch: + +```bash +gh api \ + repos/{owner}/{repo}/commits/${DEFAULT_BRANCH}/check-runs \ + --jq '.check_runs[] | {name, conclusion}' +``` + +Use `--arg` for any dynamic values to prevent injection +(consistent with `/review-pr` Step 3a). + +Map CI check names to local tool names using the same +coverage matrix logic from Phase 3. For each failing +tool from Phase 4, look up the corresponding CI check +conclusion on `${DEFAULT_BRANCH}`: + +- `conclusion: "success"` → baseline PASS +- `conclusion: "failure"` → baseline FAIL +- No matching check → baseline NO DATA + +If `gh` is not available, or the API call returns no +data, or the API call fails: proceed to Tier 2. + +### Tier 2 — Local worktree baseline + +Create a temporary detached worktree of the default +branch: + +```bash +SHORT_SHA=$(git rev-parse --short=8 ${DEFAULT_BRANCH}) +git worktree add /tmp/preflight-baseline-${SHORT_SHA} \ + ${DEFAULT_BRANCH} --detach +``` + +Run ONLY the tools that failed on the branch in the +worktree directory. Tools that passed on the branch +MUST NOT be run against the baseline — they are not +branch-caused by definition. + +```bash +# For each failing tool, run it in the worktree: +cd /tmp/preflight-baseline-${SHORT_SHA} +<tool-command> +# Record exit code +``` + +After running all failing tools, clean up the worktree: + +```bash +git worktree remove \ + /tmp/preflight-baseline-${SHORT_SHA} --force +``` + +Compare exit codes: +- Tool fails in worktree → baseline FAIL +- Tool passes in worktree → baseline PASS + +### Fallback — conservative classification + +If both Tier 1 and Tier 2 fail (e.g., `gh` unavailable +AND worktree creation fails due to disk space or dirty +state), or the default branch could not be detected, +classify ALL failures as `unknown`. The `unknown` +classification is treated as branch-caused +(conservative), matching `/review-pr` behavior. + +Record which baseline method was used: `CI API`, +`worktree`, or `unavailable`. + +--- + +## Phase 4b: Causality Classification (soft-gate only) + +This phase runs only in `soft-gate` mode, after Phase 4a +has established a baseline. + +For each failing tool from Phase 4, classify it using +the baseline result from Phase 4a: + +| Baseline status | Branch status | Classification | +|-----------------|---------------|----------------| +| Pass | Fail | **branch-caused** | +| Fail | Fail | **pre-existing** | +| No data | Fail | **unknown** (treat as branch-caused) | + +### Gate decision + +After classifying all failures: + +- If ANY failures are `branch-caused` or `unknown`: + verdict is **FAIL (branch-caused)**. The consuming + command MUST NOT proceed past the pre-flight gate. +- If ALL failures are `pre-existing`: verdict is + **PASS**. The consuming command MAY proceed, with + pre-existing failures reported as informational + findings. + +--- + +## Phase 5: Result Format + +Present results in a standardized format. + +### hard-gate and ci-aware modes + +``` +## Pre-flight Results + +### CI Coverage Matrix +| Local tool | CI check | CI status | Run locally? | +|------------|----------|-----------|--------------| +| ... | ... | ... | ... | + +### Execution Results +| Tool | Command | Exit code | Status | +|------|---------|-----------|--------| +| ... | ... | ... | ... | + +### Verdict +- **Mode**: hard-gate | ci-aware +- **Result**: PASS | FAIL +- **Failures**: [list if any] +``` + +### soft-gate mode + +``` +## Pre-flight Results + +### CI Coverage Matrix +| Local tool | CI check | CI status | Run locally? | +|------------|----------|-----------|--------------| +| ... | ... | ... | ... | + +### Execution Results +| Tool | Command | Exit code | Status | Causality | +|------|---------|-----------|--------|-----------| +| ... | ... | ... | ... | ... | + +### Verdict +- **Mode**: soft-gate +- **Result**: PASS | FAIL (branch-caused) +- **Branch-caused failures**: [list if any] +- **Pre-existing failures**: [list if any] +- **Baseline method**: CI API | worktree | unavailable +``` + +The `Causality` column in the Execution Results table +contains one of: `branch-caused`, `pre-existing`, +`unknown`, or `—` (for tools that passed). + +The `Result` field is: +- `PASS` if no branch-caused or unknown failures exist + (even if pre-existing failures exist) +- `FAIL (branch-caused)` if any branch-caused or unknown + failures exist + +The consuming command uses this result to decide whether +to proceed: +- `hard-gate`: stop on FAIL +- `ci-aware`: continue with failure context for AI review +- `soft-gate`: stop on FAIL (branch-caused), continue + with pre-existing failures as informational findings diff --git a/.opencode/skills/replicator-cli/SKILL.md b/.opencode/skills/replicator-cli/SKILL.md new file mode 100644 index 0000000..66d3d02 --- /dev/null +++ b/.opencode/skills/replicator-cli/SKILL.md @@ -0,0 +1,46 @@ +--- +name: replicator-cli +description: Replicator CLI quick reference +tags: [cli, reference, replicator] +--- + +# Replicator CLI + +Quick reference for all replicator commands. + +## Commands + +| Command | Purpose | +|---------|---------| +| `replicator init` | Per-repo setup: creates `.uf/replicator/` + agent kit | +| `replicator setup` | Per-machine setup: creates global SQLite DB | +| `replicator serve` | Start MCP JSON-RPC server on stdio | +| `replicator cells` | List work items (cells) | +| `replicator doctor` | Check environment health | +| `replicator stats` | Display activity summary | +| `replicator query` | Run preset SQL analytics queries | +| `replicator docs` | Generate MCP tool reference (markdown) | +| `replicator version` | Print version, commit, build date | + +## Build Targets + +```bash +make build # Build binary to ./bin/replicator +make test # Run all tests +make vet # Go vet +make check # Vet + test +make serve # Build and run MCP server +make install # Install to GOPATH/bin +``` + +## Init Flags + +- `--path <dir>` — target directory (default: `.`) +- `--force` — overwrite existing agent kit files + +## MCP Tool Categories + +- `org_*` (11 tools) — work item management +- `comms_*` (10 tools) — agent messaging and file reservations +- `forge_*` (24 tools) — multi-agent coordination +- `hivemind_*` (8 tools) — learning storage and retrieval diff --git a/.opencode/skills/review-context/SKILL.md b/.opencode/skills/review-context/SKILL.md new file mode 100644 index 0000000..dcdb21f --- /dev/null +++ b/.opencode/skills/review-context/SKILL.md @@ -0,0 +1,257 @@ +--- +name: review-context +description: "Shared review context discovery for spec artifacts, linked issues, path classification, and walkthrough generation." +--- +<!-- scaffolded by uf vdev --> +# Skill: Review Context Discovery + +Shared logic for discovering and loading review context +before a review command begins its analysis. Consuming +commands load this skill to standardize how spec +artifacts, linked issues, path classifications, and +walkthrough summaries are discovered and formatted. + +## Consumers + +| Command | How it loads | Notes | +|---------|-------------|-------| +| `/review-pr` | Skill tool | Replaces inline Steps 6-8 logic | +| `/review-council` | Skill tool | Phase 1c — Protocols 1, 3, 4 (skips Protocol 2: no PR body) | +| `/address-feedback` | Skill tool | Replaces inline fallback (line 143) | + +The consuming command specifies which protocols to +execute based on the available inputs (e.g., a local +review has no PR body to parse for issue links). + +--- + +## Protocol 1: Spec Artifact Discovery + +Locate the specification associated with the current +change. The discovery order is deterministic — stop at +the first match. + +### Step 1: Branch name matching + +Derive the spec directory from the current branch name +or PR branch name: + +| Branch pattern | Spec location | +|---------------|---------------| +| `NNN-<name>` (digits then dash) | `specs/<branch-name>/spec.md` (Speckit) | +| `opsx/<name>` | `openspec/changes/<name>/proposal.md` (OpenSpec changes) | +| `opsx/<name>` | `openspec/specs/<name>/spec.md` (OpenSpec specs) | + +### Step 2: PR description parsing + +If no spec is found via branch name and a PR description +is available, scan for explicit spec references (e.g., +"See spec 012" or "Implements specs/012-swarm/spec.md"). + +### Step 3: Changed-file detection + +If no spec is found via branch name or PR description, +check the changed file list for spec artifacts. The spec +may be introduced by the change itself. If found in +changed files, read the spec content from the diff +rather than from the filesystem. + +### Step 4: Read relevant sections + +When a spec is found, read only the sections relevant +to review to minimize token usage: + +| Spec type | Sections to read | +|-----------|-----------------| +| Speckit | Functional Requirements, User Stories | +| OpenSpec proposal | Capabilities, Impact | +| OpenSpec spec | Requirements, Acceptance Criteria | + +### Step 5: No spec found + +If no spec is found in any directory or in the changed +files, note this and use the PR title/description or +branch name as the intent source. No error or warning +needed — not every change has a spec. + +--- + +## Protocol 2: Issue Linking + +Parse and fetch linked issues to extract acceptance +criteria for alignment checking. This protocol applies +when a PR body is available. For local reviews without +a PR, skip this protocol. + +### Step 1: Parse issue references + +Parse the PR body for issue references using +case-insensitive matching: + +- `Fixes #N`, `Closes #N`, `Resolves #N` +- GitHub URL variants: + `Fixes https://github.com/<owner>/<repo>/issues/N` + +### Step 2: Validate references + +Apply all of the following validation controls: + +- **Digits-only validation**: Each parsed issue number + MUST be a positive integer (digits only). Discard + non-numeric values. +- **Same-repo URL scoping**: URL-format references MUST + belong to the same `{owner}/{repo}` as the PR. List + cross-repo references in the output as "cross-repo — + not validated" but do NOT fetch them. +- **Fetch limit**: Maximum 5 linked issues. If more + than 5 are found, list extras as "listed but not + fetched" in the output. + +### Step 3: Fetch linked issues + +For each validated, in-scope linked issue: + +```bash +gh issue view <N> --json title,body,labels +``` + +### Step 4: Sanitize fetched content + +Issue body content is user-controlled and untrusted. +Before incorporating into the review context: + +- **Body truncation**: Truncate to a maximum of 2000 + characters. + +### Step 5: Extract acceptance criteria + +From each fetched issue body, extract: + +- Checkbox lines (`- [ ]` or `- [x]`) +- Content under an `## Acceptance Criteria` heading + +If neither exists, use the issue title and body as +general intent context. + +### Step 6: Error handling + +If `gh issue view` returns 404, 403, or times out: + +- Log the error +- Skip that issue +- Note in the output as "fetch failed" +- Continue without blocking — the review proceeds + with available data + +Record the linked issues and their acceptance criteria +for use by the consuming command. + +--- + +## Protocol 3: Path-Based Focus Heuristics + +Classify each changed file against built-in heuristics +to guide review emphasis. The classification is additive +— it supplements standard review categories, not +replaces them. + +### Classification table + +| Path pattern | Focus category | Additional emphasis | +|-------------|---------------|-------------------| +| `*_test.go`, `*_test.py`, `**/__tests__/**`, `**/*_spec.*` | `test-quality` | Edge cases, assertion strength, mock isolation, test naming | +| `**/cmd/**`, `**/cli/**` | `cli-ux` | Error messages, flag validation, help text | +| `**/api/**`, `**/handler/**`, `**/middleware/**`, `**/routes/**` | `security` | Auth, input validation, injection | +| `*.md`, `docs/**` | `documentation` | Clarity, accuracy, broken links | +| `.github/workflows/**`, `Dockerfile*` | `ci-cd` | Permissions, pinned versions, secrets exposure | +| `go.mod`, `package.json`, `requirements.txt` | `dependencies` | Maintenance status, license, scope | +| Everything else | `standard` | Architecture, SOLID, coupling, baseline security | + +### Application + +For each changed file: + +1. Match the file path against the table (first match + wins for multi-match paths). +2. Record the focus category. +3. When reviewing the file, append the matched focus + instruction to the review context for that file. + +Security review (auth, input validation, injection) +applies to ALL changed files regardless of path +heuristic — the `security` focus category adds +additional emphasis, not exclusive coverage. + +--- + +## Protocol 4: Walkthrough Generation + +Generate a per-file change summary table while +analyzing each file's diff. The walkthrough is produced +alongside the review, not as a separate pass. + +### Standard format (< 30 files) + +```markdown +### Walkthrough +| File | Change | Focus | +|------|--------|-------| +| `internal/gateway/provider.go` | Add token expiry tracking | security | +| `internal/gateway/gateway_test.go` | Add regression test for stale tokens | test-quality | +| `cmd/unbound-force/gateway.go` | Register --provider flag | cli-ux | +``` + +### Directory-level format (>= 30 files) + +For PRs with 30 or more changed files, generate +directory-level summaries instead of per-file +summaries: + +```markdown +### Walkthrough +| Directory | Files | Summary | Focus | +|-----------|-------|---------|-------| +| `internal/gateway/` | 4 | Token refresh and provider abstraction | security | +| `cmd/unbound-force/` | 2 | CLI flag registration | cli-ux | +``` + +### Change descriptions + +Each change summary describes **what** changed (e.g., +"Add error handling for null inputs"), not **how** (no +code snippets). Keep summaries to one line. + +--- + +## Result Format + +Present the discovered context in a standardized +format that consuming commands can reference: + +``` +## Review Context + +### Specification +- Type: Speckit | OpenSpec | None +- Path: specs/012-swarm/spec.md +- Sections loaded: Functional Requirements, User Stories + +### Linked Issues +| Issue | Title | Criteria | +|-------|-------|----------| +| #42 | Add auth endpoint | 3 checkboxes extracted | +| #43 | Fix token refresh | Acceptance Criteria section | + +### File Classification +| File | Focus | +|------|-------| +| ... | ... | + +### Walkthrough +| File | Change | Focus | +|------|--------|-------| +| ... | ... | ... | +``` + +The consuming command uses this context to inform its +review analysis and output formatting. diff --git a/.opencode/skills/speckit-workflow/SKILL.md b/.opencode/skills/speckit-workflow/SKILL.md index bf67810..2c85666 100644 --- a/.opencode/skills/speckit-workflow/SKILL.md +++ b/.opencode/skills/speckit-workflow/SKILL.md @@ -7,9 +7,6 @@ tags: - decomposition --- <!-- scaffolded by uf vdev --> -<!-- scaffolded by uf vdev --> -<!-- scaffolded by uf vdev --> -<!-- scaffolded by uf vv0.6.1 --> # Speckit Workflow — Swarm Skill @@ -139,3 +136,13 @@ hero routing and workflow stage context: skills_use({ name: "unbound-force-heroes" }) skills_use({ name: "speckit-workflow" }) ``` + +## Entry Point + +The `/unleash` command is the primary way to trigger +autonomous pipeline execution using this skill. It +orchestrates the full Speckit pipeline (clarify, plan, +tasks, spec review, implement, code review, +retrospective, demo) and uses the task format described +above for the implementation phase. `/unleash` also +supports OpenSpec (`opsx/*`) branches. diff --git a/.opencode/skills/system-design/SKILL.md b/.opencode/skills/system-design/SKILL.md new file mode 100644 index 0000000..3ad5f2c --- /dev/null +++ b/.opencode/skills/system-design/SKILL.md @@ -0,0 +1,40 @@ +--- +name: system-design +description: System design principles for clean architecture +tags: [design, architecture, principles] +--- + +# System Design + +Core design principles for the replicator codebase. + +## Deep Modules + +Modules should have simple interfaces and complex implementations. +A deep module hides complexity behind a clean API. + +## Fight Complexity + +- Reduce the number of concepts a developer must hold in mind +- Make the common case simple, the edge case possible +- Prefer explicit over implicit behavior + +## SOLID Principles + +- **Single Responsibility**: Each package owns one domain concept +- **Open/Closed**: Extend via interfaces, not modification +- **Liskov Substitution**: Subtypes must be substitutable +- **Interface Segregation**: Small, focused interfaces +- **Dependency Inversion**: Depend on abstractions, not concretions + +## DRY + +Extract only when there are 3+ duplications. Premature abstraction +is worse than duplication. + +## Dependency Injection + +- Constructor injection: `NewFoo(deps)` or `Options` structs +- No global state or package-level variables +- External dependencies (filesystem, network, time) behind interfaces +- Makes testing straightforward with in-memory implementations diff --git a/.opencode/skills/testing-patterns/SKILL.md b/.opencode/skills/testing-patterns/SKILL.md new file mode 100644 index 0000000..d6106eb --- /dev/null +++ b/.opencode/skills/testing-patterns/SKILL.md @@ -0,0 +1,76 @@ +--- +name: testing-patterns +description: Go testing patterns for the replicator project +tags: [testing, go, patterns] +--- + +# Testing Patterns + +Go testing conventions for replicator. + +## Framework + +Standard library `testing` package only. No testify, gomega, or external +assertion libraries. Use `t.Errorf` / `t.Fatalf` directly. + +## Test Naming + +`TestXxx_Description` — e.g., `TestCreateCell_Defaults`, `TestReadyCell_PriorityOrder`. + +## Isolation Patterns + +### Database Tests + +```go +store := db.OpenMemory() +defer store.Close() +``` + +Every test gets its own in-memory SQLite database. No shared state. + +### Filesystem Tests + +```go +dir := t.TempDir() +// dir is automatically cleaned up +``` + +### HTTP Tests + +```go +srv := httptest.NewServer(handler) +defer srv.Close() +``` + +### Git Tests + +```go +if testing.Short() { + t.Skip("skipping git test in short mode") +} +dir := t.TempDir() +// exec.Command("git", "init", dir) +``` + +## Parity Tests + +Build tag: `//go:build parity` + +Compare Go response shapes against TypeScript fixtures in +`test/parity/fixtures/`. Run with: + +```bash +go test -tags parity ./test/parity/ -count=1 -v +``` + +## Assertions + +Use direct comparisons: + +```go +if got != want { + t.Errorf("FunctionName() = %v, want %v", got, want) +} +``` + +For slices and structs, use `reflect.DeepEqual` or compare field by field. diff --git a/.opencode/uf/packs/content.md b/.opencode/uf/packs/content.md index 917455c..72b1a5d 100644 --- a/.opencode/uf/packs/content.md +++ b/.opencode/uf/packs/content.md @@ -4,7 +4,6 @@ language: Any version: 1.0.0 --- <!-- scaffolded by uf vdev --> -<!-- scaffolded by uf vdev --> # Convention Pack: Content (Documentation, Blog, PR/Comms) diff --git a/.opencode/uf/packs/default.md b/.opencode/uf/packs/default.md index f1774bf..513117f 100644 --- a/.opencode/uf/packs/default.md +++ b/.opencode/uf/packs/default.md @@ -4,9 +4,6 @@ language: Any version: 1.0.0 --- <!-- scaffolded by uf vdev --> -<!-- scaffolded by uf vdev --> -<!-- scaffolded by uf vdev --> -<!-- scaffolded by uf vv0.6.1 --> # Convention Pack: Default (Language-Agnostic) diff --git a/.opencode/uf/packs/go.md b/.opencode/uf/packs/go.md index 0df9cc0..605af52 100644 --- a/.opencode/uf/packs/go.md +++ b/.opencode/uf/packs/go.md @@ -4,9 +4,6 @@ language: Go version: 1.0.0 --- <!-- scaffolded by uf vdev --> -<!-- scaffolded by uf vdev --> -<!-- scaffolded by uf vdev --> -<!-- scaffolded by uf vv0.6.1 --> # Convention Pack: Go diff --git a/.opencode/uf/packs/python-custom.md b/.opencode/uf/packs/python-custom.md new file mode 100644 index 0000000..7ce61fc --- /dev/null +++ b/.opencode/uf/packs/python-custom.md @@ -0,0 +1,20 @@ +--- +pack_id: python-custom +language: Python +version: 1.0.0 +--- +<!-- scaffolded by uf vdev --> + +# Custom Rules: Python + +Project-specific Python conventions that extend the canonical +Python convention pack. Rules in this file are loaded alongside +`python.md` by Cobalt-Crush (during implementation) and +all Divisor persona agents (during review). + +Use the `CR-NNN` prefix for all custom rules. Use `[MUST]`, +`[SHOULD]`, or `[MAY]` severity indicators per RFC 2119. + +## Custom Rules + +<!-- Add project-specific rules below this line --> diff --git a/.opencode/uf/packs/python.md b/.opencode/uf/packs/python.md new file mode 100644 index 0000000..496f529 --- /dev/null +++ b/.opencode/uf/packs/python.md @@ -0,0 +1,268 @@ +--- +pack_id: python +language: Python +version: 1.0.0 +--- +<!-- scaffolded by uf vdev --> + +# Convention Pack: Python + +This convention pack defines Python-specific review +criteria for The Divisor PR reviewer framework. Persona +agents load this pack dynamically at review time to +evaluate Python codebases against language-specific +coding style, architectural patterns, security checks, +testing conventions, type annotations, and documentation +requirements. + +Rules use RFC 2119 severity indicators: [MUST] for +mandatory requirements, [SHOULD] for strong recommendations, +and [MAY] for optional best practices. + +--- + +## Coding Style + +- **CS-001** [MUST] Code MUST be auto-formatted with a + consistent formatter (`black`, `ruff format`, or + equivalent). No manual formatting overrides. Line + length MUST match the project's configured limit. + Formatting changes MUST NOT be mixed with logic + changes in the same commit. + +- **CS-002** [MUST] Imports MUST be auto-sorted with a + consistent tool (`isort`, `ruff` with isort rules, or + equivalent). Organize in groups separated by blank + lines: standard library, third-party packages, + local/project modules. + +- **CS-003** [MUST] Code MUST pass a linter (`flake8`, + `ruff check`, or equivalent) with the project's + configured ruleset. No lint errors committed without + explicit suppression comments that include the specific + code and justification (e.g., `# noqa: E501 - URL`). + +- **CS-004** [MUST] Use `snake_case` for functions, + methods, variables, and module names. Use `PascalCase` + for class names. Use `UPPER_SNAKE_CASE` for module-level + constants. + +- **CS-005** [MUST] All functions that can fail MUST raise + specific exception types or return typed results. Never + silently swallow exceptions. Every `except` clause MUST + either handle, re-raise, or log the exception with + context. + +- **CS-006** [MUST] Bare `except:` and `except Exception:` + MUST NOT be used unless re-raising or logging with full + context. Catch the most specific exception type possible. + +- **CS-007** [MUST] Use f-strings for string formatting. + Do not use `%` formatting or `.format()` in new code. + +- **CS-008** [MUST] No mutable default arguments. Use + `None` as default and initialize inside the function + body (e.g., `def foo(items=None): items = items or []`). + +- **CS-009** [MUST] Use `with` statements for all resource + management (files, database connections, locks, network + sessions). Never rely on garbage collection for cleanup. + +- **CS-010** [SHOULD] Keep functions focused on a single + responsibility. Functions exceeding ~50 lines of logic + SHOULD be evaluated for decomposition. + +- **CS-011** [SHOULD] Use `pathlib.Path` for filesystem + path construction instead of `os.path.join` in new code. + +- **CS-012** [SHOULD] Use list/dict/set comprehensions + where they improve readability. Avoid nested + comprehensions deeper than two levels. + +- **CS-013** [SHOULD] Prefer `dataclasses`, Pydantic + models, or typed NamedTuples over plain dicts for + structured data with known schemas. + +--- + +## Architectural Patterns + +- **AP-001** [MUST] Each module MUST have a single, + well-defined responsibility. A module that handles both + business logic and I/O coordination is a violation. + +- **AP-002** [SHOULD] Dependencies SHOULD be injected + rather than hard-instantiated. Functions and constructors + SHOULD accept interfaces or abstractions rather than + concrete implementations where testability benefits. + +- **AP-003** [MUST] Circular imports MUST NOT exist. If + module A imports module B, module B MUST NOT import + module A (directly or transitively). Use local imports, + `TYPE_CHECKING` guards, or extract shared types to break + cycles. + +- **AP-004** [SHOULD] Configuration SHOULD be loaded from + environment variables, config files, or framework + settings (e.g., `django.conf.settings`), not hardcoded. + +- **AP-005** [SHOULD] Long modules (>500 lines) SHOULD be + evaluated for splitting into submodules with a package + `__init__.py` that re-exports the public API. + +- **AP-006** [MUST] Application code MUST NOT import from + test modules. Test utilities shared across test files + SHOULD live in `conftest.py` or a dedicated test helpers + package. + +--- + +## Security Checks + +- **SC-001** [MUST] Never hardcode secrets, API keys, + tokens, or credentials in source code. Secrets MUST be + loaded from environment variables, secret managers, or + encrypted configuration. Files matching common secret + patterns (`.env`, `credentials.json`, `*.pem`, `*.key`) + MUST NOT be committed. + +- **SC-002** [MUST] All user input MUST be validated and + sanitized before use. Use parameterized queries for + database access -- never string concatenation or + f-string interpolation in SQL. + +- **SC-003** [MUST] Use `defusedxml` or equivalent for + XML parsing of untrusted input. Never use + `xml.etree.ElementTree` or `lxml` with untrusted data + without disabling entity expansion. Test-only XML + parsing of trusted fixtures MAY use standard library + parsers. + +- **SC-004** [MUST] Code MUST pass security static + analysis (`bandit`, `ruff` S rules, or equivalent). + Address all HIGH and CRITICAL findings before merge. + +- **SC-005** [SHOULD] Dependencies SHOULD be audited + regularly with `pip-audit`, Dependabot, or equivalent + tooling. PRs introducing new dependencies SHOULD note + maintenance status and known vulnerabilities. + Dependencies with critical CVEs MUST NOT be merged. + +- **SC-006** [MUST] File operations with user-supplied + paths MUST validate against directory traversal. Use + `os.path.realpath()` or `pathlib.Path.resolve()` and + verify the result is within the expected root. + +- **SC-007** [MUST] Never pass user-supplied or external + input to `shell=True` subprocess calls. [SHOULD] Prefer + `subprocess.run()` with list arguments and `shell=False` + for new code. Internal utility wrappers that use + `shell=True` with hardcoded or developer-controlled + commands are acceptable when documented. + +- **SC-008** [SHOULD] Set safe file permissions when + creating files: `0o644` for regular files, `0o755` for + executable scripts and directories. Avoid world-writable + permissions. + +--- + +## Testing Conventions + +- **TC-001** [MUST] Use `pytest` as the test runner. Do + not use `unittest.TestCase` for new tests. Existing + `TestCase` subclasses are acceptable until migrated. + +- **TC-002** [MUST] New functionality MUST be accompanied + by tests covering the primary success path and at least + one failure/edge case path. + +- **TC-003** [MUST] Bug fixes MUST include a regression + test that reproduces the original failure and verifies + the fix. + +- **TC-004** [MUST] External dependencies (APIs, databases, + filesystem, network) MUST be mocked in unit tests using + `unittest.mock.patch`, `pytest-mock`, or `pytest` + fixtures. Tests MUST NOT require external services or + network connectivity. + +- **TC-005** [MUST] Tests MUST be isolated -- each test + MUST be independently runnable without depending on + execution order or shared mutable state. + +- **TC-006** [SHOULD] Use `pytest.mark.parametrize` for + table-driven tests when exercising multiple input/output + combinations for the same function. + +- **TC-007** [SHOULD] Test names SHOULD clearly describe + the scenario: `test_<function>_<condition>_<expected>` + (e.g., `test_parse_empty_input_returns_none`). + +- **TC-008** [SHOULD] Use `factory-boy`, `pytest` fixtures, + or equivalent for test data construction. Avoid large + inline dicts or manual object construction repeated + across tests. + +- **TC-009** [SHOULD] Coverage SHOULD be measured with + `pytest-cov` or equivalent. A `--cov-fail-under` + threshold SHOULD be enforced in CI to prevent coverage + regression. + +- **TC-010** [SHOULD] Place test files in a `tests/` + directory mirroring the source structure, or co-locate + with source files using the `test_<module>.py` naming + convention. Test file naming MUST follow the project's + established convention consistently. + +- **TC-011** [SHOULD] Use `conftest.py` for shared + fixtures. Do not duplicate fixture definitions across + test files. + +--- + +## Type Annotations + +- **TA-001** [SHOULD] All new public functions and methods + SHOULD have type annotations on parameters and return + values. + +- **TA-002** [SHOULD] Run a type checker (`mypy`, `pyright`, + `ty`, or equivalent) and address type errors + incrementally -- do not disable the type checker globally. + +- **TA-003** [SHOULD] Use built-in generics (`list[str]`, + `dict[str, int]`, `X | None`) for Python 3.10+. For + Python 3.9 and below, use `typing` module constructs + (`Optional`, `Union`, `List`, `Dict`). + +- **TA-004** [SHOULD] Prefer `Protocol` classes over ABC + for structural typing where duck typing is the intent. + +--- + +## Documentation Requirements + +- **DR-001** [MUST] All public functions, classes, and + methods MUST have docstrings. Use a consistent docstring + format (Google-style, NumPy-style, or reStructuredText) + across the project. + +- **DR-002** [MUST] Commit messages MUST use Conventional + Commits format: `type: description` (e.g., `feat:`, + `fix:`, `docs:`, `chore:`, `refactor:`). + +- **DR-003** [SHOULD] User-visible changes SHOULD be + recorded in a changelog or release notes following the + project's established format. + +- **DR-004** [SHOULD] Configuration options, environment + variables, and feature flags SHOULD be documented in + the project README or a dedicated configuration + reference. + +--- + +## Custom Rules + +<!-- This section is intentionally empty in the canonical pack. Project-specific custom rules belong in python-custom.md --> diff --git a/.opencode/uf/packs/severity.md b/.opencode/uf/packs/severity.md index d43767f..ae0fafc 100644 --- a/.opencode/uf/packs/severity.md +++ b/.opencode/uf/packs/severity.md @@ -2,7 +2,6 @@ description: "Shared severity level definitions for all Divisor Council personas." --- <!-- scaffolded by uf vdev --> -<!-- scaffolded by uf vdev --> # Severity Convention Pack @@ -79,6 +78,34 @@ impact. | SRE | Style improvement in error messages, optional health check enhancement, minor doc gap | | Architect | Formatting preference, optional structural improvement, minor comment enhancement | +## Compound Severity Escalation + +When multiple findings share a root cause, personas MUST +assess the **combined** severity rather than classifying +each finding in isolation. Findings that individually +appear LOW or MEDIUM can compound into a HIGH or +CRITICAL finding when they create a single coherent +attack surface or failure mode. + +**Rule**: If two or more findings (a) affect the same +component or pipeline stage, (b) share a common root +cause, and (c) together produce a risk greater than any +individual finding, consolidate them into a single +finding at the escalated severity. The consolidated +finding MUST cite each contributing factor. + +| Pattern | Individual | Compound | +|---------|-----------|----------| +| Unverified binary + privileged CI container | MEDIUM + MEDIUM | HIGH (supply chain attack in privileged context) | +| Broad permissions + missing input validation + external-facing endpoint | MEDIUM + MEDIUM + MEDIUM | HIGH (unauthenticated access with elevated privileges) | +| Missing error handling + missing retry + critical data path | MEDIUM + LOW + context | HIGH (silent data loss on transient failure) | + +**When NOT to escalate**: Findings that happen to appear +in the same PR but have independent root causes and +independent blast radii MUST NOT be artificially +consolidated. Consolidation applies only when the +findings are causally linked. + ## Auto-Fix Policy (Spec Review Mode) | Severity | Action | Rationale | diff --git a/.opencode/uf/packs/typescript.md b/.opencode/uf/packs/typescript.md index ad7a49e..9b1eb42 100644 --- a/.opencode/uf/packs/typescript.md +++ b/.opencode/uf/packs/typescript.md @@ -4,9 +4,6 @@ language: TypeScript version: 1.0.0 --- <!-- scaffolded by uf vdev --> -<!-- scaffolded by uf vdev --> -<!-- scaffolded by uf vdev --> -<!-- scaffolded by uf vv0.6.1 --> # Convention Pack: TypeScript diff --git a/.uf/replicator/cells.json b/.uf/replicator/cells.json new file mode 100644 index 0000000..fe51488 --- /dev/null +++ b/.uf/replicator/cells.json @@ -0,0 +1 @@ +[] diff --git a/AGENTS.md b/AGENTS.md index 3c822e0..eedf7ee 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -437,3 +437,14 @@ originally by [Joel Hooks](https://github.com/joelhooks). ## Recent Changes - 001-go-rewrite-phases: Added Go 1.25+ + `cobra` (CLI), `modernc.org/sqlite` (pure Go SQLite), stdlib `encoding/json` (MCP JSON-RPC), stdlib `os/exec` (git operations) + +## Convention Packs + +This repository uses convention packs scaffolded by +unbound-force. Agents MUST read the applicable pack(s) +before writing or reviewing code. + +- `.opencode/uf/packs/default.md` +- `.opencode/uf/packs/severity.md` +- `.opencode/uf/packs/content.md` +- `.opencode/uf/packs/go.md` diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..9c9f8ad --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,21 @@ +# Unbound Force — managed by uf init + +@AGENTS.md +@.opencode/agents/cobalt-crush-dev.md + +## Convention Packs + +@.opencode/uf/packs/default.md +@.opencode/uf/packs/severity.md +@.opencode/uf/packs/content.md +@.opencode/uf/packs/go.md + +## Review Agents (read on-demand) + +When performing code review, read the applicable +Divisor agent from .opencode/agents/: +- divisor-guard.md — intent drift, constitution +- divisor-architect.md — structure, patterns, DRY +- divisor-adversary.md — security, error handling +- divisor-testing.md — test quality, assertions +- divisor-sre.md — operations, performance diff --git a/openspec/schemas/unbound-force/schema.yaml b/openspec/schemas/unbound-force/schema.yaml index d7eb106..9e3a612 100644 --- a/openspec/schemas/unbound-force/schema.yaml +++ b/openspec/schemas/unbound-force/schema.yaml @@ -55,6 +55,15 @@ artifacts: checkboxes. Group related tasks. Include a task for verifying constitution alignment if the proposal identified relevant principles. + Add [P] marker after the task number on tasks + that are eligible for parallel execution. + A task is parallel-eligible when it: (a) touches + different files from other [P] tasks in the same + group, (b) has no dependency on prior tasks in + the group, (c) can safely execute without ordering + constraints. Do NOT add [P] when tasks modify the + same file — parallel workers will cause merge + conflicts. Format: - [ ] N.M [P] description. requires: [specs, design] apply: @@ -65,7 +74,4 @@ apply: task as you complete it. Verify that the implementation maintains constitution alignment as documented in the proposal. -# scaffolded by uf vv0.6.1 -# scaffolded by uf vdev -# scaffolded by uf vdev # scaffolded by uf vdev diff --git a/openspec/schemas/unbound-force/templates/design.md b/openspec/schemas/unbound-force/templates/design.md index 9bfbd31..2165de3 100644 --- a/openspec/schemas/unbound-force/templates/design.md +++ b/openspec/schemas/unbound-force/templates/design.md @@ -17,7 +17,4 @@ ## Risks / Trade-offs <!-- Known risks and accepted trade-offs --> -<!-- scaffolded by uf vv0.6.1 --> -<!-- scaffolded by uf vdev --> -<!-- scaffolded by uf vdev --> <!-- scaffolded by uf vdev --> diff --git a/openspec/schemas/unbound-force/templates/proposal.md b/openspec/schemas/unbound-force/templates/proposal.md index 2f1ebba..45d5fa9 100644 --- a/openspec/schemas/unbound-force/templates/proposal.md +++ b/openspec/schemas/unbound-force/templates/proposal.md @@ -54,7 +54,4 @@ output? Does it maintain provenance metadata? --> <!-- Does this change verify observable side effects? Are components testable in isolation? --> -<!-- scaffolded by uf vv0.6.1 --> -<!-- scaffolded by uf vdev --> -<!-- scaffolded by uf vdev --> <!-- scaffolded by uf vdev --> diff --git a/openspec/schemas/unbound-force/templates/spec.md b/openspec/schemas/unbound-force/templates/spec.md index 3ca8ff5..7b1e55a 100644 --- a/openspec/schemas/unbound-force/templates/spec.md +++ b/openspec/schemas/unbound-force/templates/spec.md @@ -20,7 +20,4 @@ ### Requirement: <!-- name --> <!-- reason for removal --> -<!-- scaffolded by uf vv0.6.1 --> -<!-- scaffolded by uf vdev --> -<!-- scaffolded by uf vdev --> <!-- scaffolded by uf vdev --> diff --git a/openspec/schemas/unbound-force/templates/tasks.md b/openspec/schemas/unbound-force/templates/tasks.md index f3d649d..e5bbfc7 100644 --- a/openspec/schemas/unbound-force/templates/tasks.md +++ b/openspec/schemas/unbound-force/templates/tasks.md @@ -1,12 +1,22 @@ +<!-- + [P] marks tasks eligible for parallel execution. + Add [P] when a task: (a) touches different files from + other [P] tasks in the group, (b) has no dependency + on prior tasks in the group, (c) can safely execute + without ordering constraints. + Do NOT add [P] when tasks modify the same file — + parallel workers will cause merge conflicts. + Tasks without [P] run sequentially first, then [P] + tasks run in parallel. +--> + ## 1. <!-- Task Group --> -- [ ] 1.1 <!-- task description --> -- [ ] 1.2 <!-- task description --> +- [ ] 1.1 <!-- sequential task (runs first) --> +- [ ] 1.2 [P] <!-- parallel task (different file) --> +- [ ] 1.3 [P] <!-- parallel task (different file) --> ## 2. <!-- Task Group --> - [ ] 2.1 <!-- task description --> -<!-- scaffolded by uf vv0.6.1 --> -<!-- scaffolded by uf vdev --> -<!-- scaffolded by uf vdev --> <!-- scaffolded by uf vdev -->