From 65af69b6a4e8d7885df490d8046ba18759fe44dc Mon Sep 17 00:00:00 2001 From: Simon Flandergan Date: Thu, 25 Jun 2026 22:16:18 +0200 Subject: [PATCH 01/65] plan: dual-harness Claude /implement and forge-agnostic publishing --- plans/2026-06-25-dual-harness-forge/plan.md | 1387 +++++++++++++++++++ 1 file changed, 1387 insertions(+) create mode 100644 plans/2026-06-25-dual-harness-forge/plan.md diff --git a/plans/2026-06-25-dual-harness-forge/plan.md b/plans/2026-06-25-dual-harness-forge/plan.md new file mode 100644 index 0000000..4ca662e --- /dev/null +++ b/plans/2026-06-25-dual-harness-forge/plan.md @@ -0,0 +1,1387 @@ +# Dual-Harness Implementer & Forge-Agnostic Publishing + +> **For implementation agents:** Execute this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** Close two structural gaps identified by inspecting an adapted downstream project: (1) Claude Code has no `/implement` controller — implementation is OpenCode-only, and (2) publishing is GitHub-only with no skill wrapper, making it impossible to swap forge platforms or prevent agents from bypassing push safety. + +**Configuration shape:** The Claude implementer adds two files to the core template layer (`core/claude/`) and updates six existing files for cross-references and documentation. Forge-agnostic publishing replaces the raw `scripts/publish-branch.sh` with a `github-publish` authored skill (same pattern as `github-pr-comments`), then adds a `gitlab` forge overlay under `core/forge/gitlab/` with its own publish and MR-comment skills. The installer scripts get a forge prompt. + +**Configuration surface:** +- New: `core/claude/skills/implement/SKILL.md`, `core/claude/agents/implement-task.md` +- New: `core/agents/skills/github-publish/SKILL.md`, `core/agents/skills/github-publish/scripts/push-branch.sh`, `core/agents/skills/github-publish/scripts/open-pr.sh` +- New: `core/forge/gitlab/` tree (publish skill, MR-comments skill, opencode.json overlay, claude/settings.json overlay, AGENTS.md addition) +- Modified: `core/claude/README.md`, `core/claude/skills/planner/SKILL.md`, `core/claude/skills/review-code/SKILL.md`, `core/claude/skills/review-plan/SKILL.md`, `core/opencode/agents/implement.md`, `core/opencode/agents/implement-task.md`, `core/claude/settings.json`, `core/AGENTS.md`, `README.md`, `scripts/init.sh`, `scripts/copy.sh` +- Removed: `scripts/publish-branch.sh` (replaced by `github-publish` skill) + +## File Map + +### Part A — Claude Dual-Harness Implementer (core) + +| File | Action | Responsibility | +|---|---|---| +| `core/claude/skills/implement/SKILL.md` | Create | Claude `/implement` controller — dispatches `implement-task` workers | +| `core/claude/agents/implement-task.md` | Create | Claude `implement-task` subagent definition | +| `core/claude/README.md` | Modify | Add `/implement` to skill table, add `implement-task` agent, update symlink inventory | +| `core/claude/skills/planner/SKILL.md` | Modify | Update stop conditions: mention `/implement` as Claude alternative to OpenCode handoff | +| `core/claude/skills/review-code/SKILL.md` | Modify | Update escalation rules: mention `/implement` for fix-plan execution | +| `core/claude/skills/review-plan/SKILL.md` | Modify | Update handoff text: mention `/implement` as Claude alternative | +| `core/docs/agents/implement-task.md` | Verify | Already correct — no changes expected | +| `README.md` | Modify | Add `implement` to Claude skill list, add `implement-task` agent mention | + +### Part B — Forge-Agnostic Publishing (core) + +| File | Action | Responsibility | +|---|---|---| +| `core/agents/skills/github-publish/SKILL.md` | Create | Safe publishing skill — refuses `main`, refuses force-push | +| `core/agents/skills/github-publish/scripts/push-branch.sh` | Create | Push guard (from `scripts/publish-branch.sh`, hardened) | +| `core/agents/skills/github-publish/scripts/open-pr.sh` | Create | PR creation with existence check | +| `core/opencode/agents/implement.md` | Modify | Replace raw `git push` / `gh pr create` with `github-publish` skill references | +| `core/opencode/agents/implement-task.md` | Modify | No changes expected (workers don't push) | +| `core/opencode/agents/finish.md` | Modify | Replace raw `git push` with `github-publish` skill reference | +| `core/claude/skills/finish/SKILL.md` | Modify | Replace raw `git push` with `github-publish` skill reference | +| `core/claude/skills/brainstorm/SKILL.md` | Modify | Replace raw `git push` with `github-publish` skill reference | +| `core/claude/settings.json` | Modify | Add `github-publish` script permissions | +| `scripts/publish-branch.sh` | Delete | Replaced by `github-publish` skill | +| `README.md` | Modify | Add `github-publish` to authored skills list | + +### Part C — GitLab Forge Overlay + +| File | Action | Responsibility | +|---|---|---| +| `core/forge/gitlab/AGENTS.md` | Create | GitLab-specific conventions addition | +| `core/forge/gitlab/.agents/skills/gitlab-publish/SKILL.md` | Create | GitLab safe publishing skill | +| `core/forge/gitlab/.agents/skills/gitlab-publish/scripts/push-branch.sh` | Create | Push guard (refuses `main`/`master`) | +| `core/forge/gitlab/.agents/skills/gitlab-publish/scripts/open-mr.sh` | Create | MR creation with `glab` | +| `core/forge/gitlab/.agents/skills/gitlab-mr-comments/SKILL.md` | Create | GitLab MR comment fetching and reply | +| `core/forge/gitlab/.agents/skills/gitlab-mr-comments/scripts/fetch-mr-comments.sh` | Create | MR discussion fetcher | +| `core/forge/gitlab/.agents/skills/gitlab-mr-comments/scripts/reply-to-mr-comment.sh` | Create | MR discussion reply poster | +| `core/forge/gitlab/opencode.json` | Create | GitLab-specific bash permission overlays | +| `core/forge/gitlab/claude/settings.json` | Create | GitLab-specific Claude permission overlays | +| `core/forge/gitlab/docs/agents/review-plan.md` | Create | GitLab MR comments loading addition | +| `core/forge/gitlab/docs/agents/review-code.md` | Create | GitLab MR comments loading addition | +| `core/forge/gitlab/docs/agents/bugfix.md` | Create | GitLab issue creation addition | +| `scripts/init.sh` | Modify | Add forge prompt (github/gitlab) | +| `scripts/copy.sh` | Modify | Add forge prompt, merge forge overlay | +| `README.md` | Modify | Document forge dimension, update symlink table | + +--- + +## Task 1: Create Claude `/implement` Controller Skill + +**Files:** +- Create: `core/claude/skills/implement/SKILL.md` + +- [ ] **Step 1: Write the implement controller skill** + +Create `core/claude/skills/implement/SKILL.md`: + +```markdown +--- +name: implement +description: Executes an approved plan task-by-task in Claude Code — dispatches a fresh implement-task worker per task, reviews each diff, and runs verification before any completion claim. +argument-hint: [path to approved plan] +disable-model-invocation: true +--- + +You are the implementation controller for this repository. +This is the Claude Code half of implementation; OpenCode (`@implement`) is the equivalent controller on that harness. +Pick one harness per branch — do not run both controllers over the same plan. + +Approved plan (if provided): $ARGUMENTS + +## Load first + +Load `docs/agents/implement.md` and follow its document list exactly. +Then load the approved `plan.md` (and `spec.md` if present) and the docs the plan names. + +Use the `workflow-verification` skill before any completion claim. +Do not say work is complete, fixed, or passing unless the relevant verification commands have just run successfully. + +## Execution rules + +- **Never implement on `main`.** Create or ask for a scoped branch first. +- **Default behavior:** execute the plan task-by-task by dispatching a fresh `implement-task` worker (via the Agent tool, `subagent_type: implement-task`) for each task. This is the standard workflow — do not deviate unless the user explicitly asks for inline implementation. +- **Inline implementation:** acceptable only when the user explicitly asks you to implement directly. When inline, apply the same per-task and review gates as delegated workers. +- **Controller duties:** orchestrate — dispatch tasks, package context for workers, review worker reports and diffs, enforce spec compliance and code-quality gates, and run verification before any completion claim. Give the worker the full task text, relevant context, exact plan/spec paths, affected docs, and current branch state; do not make it reread the whole plan. +- **One focused commit per task.** Delegated workers create the task commit; commit inline only when you execute a task yourself. Review the worker report and `git diff` before moving on. +- Follow TDD for behavior changes unless the plan marks a step as docs-only, config-only, or trivial wiring. +- Do not pause between tasks for routine progress approval. +- Stop and ask only when the same task fails more than three times, the plan conflicts with code reality, or an architectural decision is required. If a task needs an architectural decision, report the blocker and recommend human escalation. + +## Model selection + +Each per-task `implement-task` worker runs on Sonnet — the `implement-task` agent pins `model: sonnet`, so leave the model override off when dispatching it. +If a worker fails to deliver a task (after the per-task retry limit), re-dispatch the same task with a `model` override to a more capable model before escalating to a human. + +## Verification + +Run targeted verification while iterating and the required final verification before claiming completion. Use the `workflow-verification` skill as the completion gate. + +## Shell guidance + +- Prefer `git mv` for moves/renames of tracked paths and `git rm` for removals of tracked paths. Use plain `mv`/`rm` only for untracked paths. +- Never work on or push to `main`. Publish through the `github-publish` skill — do not hand-roll `git push`. + +## Finishing + +After final verification, commit all changes and push the branch with the `github-publish` skill: +`bash .claude/skills/github-publish/scripts/push-branch.sh`. +Then open a pull request with `bash .claude/skills/github-publish/scripts/open-pr.sh` — it skips creation when a PR already exists for the branch. +``` + +- [ ] **Step 2: Verify** + +Run: `codespell core/claude/skills/implement/SKILL.md` +Expected: no errors (or only false positives for agent-specific terms) + +- [ ] **Step 3: Commit** + +```bash +git add core/claude/skills/implement/SKILL.md +git commit -m "feat: add Claude /implement controller skill" +``` + +--- + +## Task 2: Create Claude `implement-task` Subagent + +**Files:** +- Create: `core/claude/agents/implement-task.md` + +- [ ] **Step 1: Write the implement-task subagent definition** + +Create `core/claude/agents/implement-task.md`: + +```markdown +--- +name: implement-task +description: Worker that implements one approved plan task with TDD, a single focused commit, and self-review. Dispatched by the /implement controller — one fresh worker per task. +tools: Bash, Read, Edit, Write, Glob, Grep, Agent +model: sonnet +--- + +You are the single-task implementation worker for this repository. + +Implement exactly one task provided by the `/implement` controller. +Do not read or execute unrelated tasks from the plan unless the controller explicitly asks. + +Load `docs/agents/implement-task.md` and only the task context, spec/plan excerpts, and docs provided or named by the controller. + +## Rules + +- Never work on `main`. +- Follow the provided task text, spec/plan context, and the repository docs the guide (`docs/agents/implement-task.md`) tells you to load for the area you touch. +- Follow TDD for behavior changes unless the task is explicitly docs-only, config-only, or trivial wiring. +- Make the smallest correct change. Make small, justified adaptations to fit the current codebase, and report them clearly. +- If you need to verify an exact file path, module boundary, or existing pattern before editing, dispatch an `Explore` subagent with a focused question rather than guessing. Use it only for read-only verification of your one task — do not re-plan, widen scope, or dispatch other implementers. +- Prefer `git mv` for moves/renames of tracked paths and `git rm` for removals of tracked paths. Use plain `mv`/`rm` only for untracked paths. +- Commit exactly the task changes with the commit message specified by the plan, or a concise message if the plan omitted one. +- Do not push, create pull requests, amend commits, delete branches, remove worktrees, or dispatch other implementers. +- If requirements are unclear, report `NEEDS_CONTEXT` before editing. +- If blocked after three attempts on the same issue, report `BLOCKED` with what you tried. + +Before reporting, self-review the diff for spec compliance, overbuilding, tests, and obvious defects. + +## Report format + +- **Status:** `DONE`, `DONE_WITH_CONCERNS`, `NEEDS_CONTEXT`, or `BLOCKED` +- **Commit:** commit SHA or `none` +- **Implemented:** concise summary +- **Verification:** exact commands run and results +- **Files changed:** paths +- **Concerns:** anything the controller should inspect +``` + +- [ ] **Step 2: Verify** + +Run: `codespell core/claude/agents/implement-task.md` +Expected: no errors + +- [ ] **Step 3: Commit** + +```bash +git add core/claude/agents/implement-task.md +git commit -m "feat: add Claude implement-task subagent definition" +``` + +--- + +## Task 3: Create `github-publish` Authored Skill + +**Files:** +- Create: `core/agents/skills/github-publish/SKILL.md` +- Create: `core/agents/skills/github-publish/scripts/push-branch.sh` +- Create: `core/agents/skills/github-publish/scripts/open-pr.sh` + +- [ ] **Step 1: Write the SKILL.md** + +Create `core/agents/skills/github-publish/SKILL.md`: + +```markdown +--- +name: github-publish +description: Use when pushing a branch or opening a pull request — guards against pushing to the default branch and against force-pushing +user-invocable: false +--- + +# GitHub Publish + +Safe publishing for this repository. Pushing and opening pull requests go through bundled scripts that **refuse to act on `main`** and refuse force-pushes. + +## Why a script, not a raw `git push` + +`git push origin $(git rev-parse --abbrev-ref HEAD)` does **not** protect `main`: while you are on `main` it expands to `git push origin main`, and permission globs cannot see through the command substitution to block it. The guard has to inspect the current branch at run time, which is what these scripts do. + +## Push the current branch + +```bash +bash .agents/skills/github-publish/scripts/push-branch.sh +``` + +It pushes the current branch to `origin`, refusing if the branch is `main` or a detached `HEAD`, and refusing any `--force` / `-f` / `--force-with-lease` argument. Extra arguments (e.g. `--set-upstream`) are passed through. + +## Open a pull request + +```bash +bash .agents/skills/github-publish/scripts/open-pr.sh [gh pr create flags] +``` + +It refuses on `main`, skips creation when a PR already exists for the current branch (printing the existing one), and otherwise runs `gh pr create` for the current branch. Pass `--fill` to derive the title/description from commits, or `--title`/`--description` explicitly. + +## Rules + +- Never bypass these scripts with a raw `git push` to publish work — the protection only holds if publishing goes through them. +- Force-pushing and pushing to `main` are out of scope for this skill; they require a deliberate, human-run command. +``` + +- [ ] **Step 2: Write push-branch.sh** + +Create `core/agents/skills/github-publish/scripts/push-branch.sh`: + +```bash +#!/usr/bin/env bash +set -euo pipefail + +branch="$(git rev-parse --abbrev-ref HEAD)" + +case "$branch" in + main|master|HEAD) + printf 'Refusing to push: current branch is "%s". Create a scoped feature branch first.\n' "$branch" >&2 + exit 1 + ;; +esac + +# Force-pushing is never part of safe publishing. +for arg in "$@"; do + case "$arg" in + --force|-f|--force-with-lease|--force-with-lease=*) + printf 'Refusing to force-push from this script. Force-push must be a deliberate, human-run command.\n' >&2 + exit 1 + ;; + esac +done + +printf 'Pushing branch "%s" to origin...\n' "$branch" +git push origin "$branch" "$@" +``` + +- [ ] **Step 3: Write open-pr.sh** + +Create `core/agents/skills/github-publish/scripts/open-pr.sh`: + +```bash +#!/usr/bin/env bash +set -euo pipefail + +branch="$(git rev-parse --abbrev-ref HEAD)" + +case "$branch" in + main|master|HEAD) + printf 'Refusing: current branch is "%s". Open a pull request from a feature branch.\n' "$branch" >&2 + exit 1 + ;; +esac + +# Skip creation if a pull request already exists for this branch. +existing="$(gh pr list --head "$branch" --json url --jq 'length')" +if [ "${existing:-0}" -gt 0 ]; then + printf 'A pull request already exists for branch "%s":\n' "$branch" + gh pr list --head "$branch" --json url,title --jq '.[] | " \(.title) — \(.url)"' + exit 0 +fi + +printf 'Opening pull request for branch "%s"...\n' "$branch" +gh pr create --head "$branch" "$@" +``` + +- [ ] **Step 4: Make scripts executable** + +```bash +chmod +x core/agents/skills/github-publish/scripts/push-branch.sh +chmod +x core/agents/skills/github-publish/scripts/open-pr.sh +``` + +- [ ] **Step 5: Verify** + +Run: `shellcheck core/agents/skills/github-publish/scripts/*.sh` +Run: `bash -n core/agents/skills/github-publish/scripts/*.sh` +Run: `codespell core/agents/skills/github-publish/SKILL.md` +Expected: no errors + +- [ ] **Step 6: Commit** + +```bash +git add core/agents/skills/github-publish/ +git commit -m "feat: add github-publish authored skill with push guard and PR opener" +``` + +--- + +## Task 4: Wire `github-publish` into OpenCode Agents + +**Files:** +- Modify: `core/opencode/agents/implement.md` +- Modify: `core/opencode/agents/finish.md` + +- [ ] **Step 1: Update implement.md** + +In `core/opencode/agents/implement.md`: + +Replace the raw push/PR instructions in the body (lines 100-113) with `github-publish` skill references. Specifically: + +- Replace line 100 (`Always use 'git push origin $(git rev-parse --abbrev-ref HEAD)'...`) with: + `Publish through the 'github-publish' skill — 'bash .agents/skills/github-publish/scripts/push-branch.sh' to push, which refuses 'main'. Never hand-roll 'git push': 'git push origin $(...)' silently pushes 'main' when the current branch is 'main'.` + +- Replace line 101 (the `gh pr list --head` check) with: + `Open a pull request with 'bash .agents/skills/github-publish/scripts/open-pr.sh' — it skips creation when a PR already exists for the current branch.` + +- Replace line 113 (the final push+PR block) with: + `After final verification, commit all changes, push the branch with 'bash .agents/skills/github-publish/scripts/push-branch.sh', and open a GitHub pull request with 'bash .agents/skills/github-publish/scripts/open-pr.sh' (it no-ops when a PR already exists). The push script refuses 'main'.` + +- Add `github-publish` to the skill permission allowlist: + Replace `"workflow-implementation": allow` with: + ``` + "workflow-implementation": allow + "github-publish": allow + ``` + +- Add the publish script to bash permissions: + After the `"git push origin $(git rev-parse --abbrev-ref HEAD)": allow` line, add: + ``` + "bash .agents/skills/github-publish/scripts/push-branch.sh*": allow + "bash .agents/skills/github-publish/scripts/open-pr.sh*": ask + ``` + +- Remove the `"git push origin $(git rev-parse --abbrev-ref HEAD)": allow` line (no longer needed since the skill handles it). + +- [ ] **Step 2: Update finish.md** + +In `core/opencode/agents/finish.md`: + +- Replace the push instruction in the body with a `github-publish` skill reference. +- Add `github-publish` to the skill permission allowlist. +- Add the publish script permissions to bash. +- Remove any raw `git push` permission lines that are replaced by the skill. + +- [ ] **Step 3: Verify** + +Run: `codespell core/opencode/agents/implement.md core/opencode/agents/finish.md` +Expected: no errors + +- [ ] **Step 4: Commit** + +```bash +git add core/opencode/agents/implement.md core/opencode/agents/finish.md +git commit -m "refactor: wire github-publish skill into OpenCode implement and finish agents" +``` + +--- + +## Task 5: Wire `github-publish` into Claude Skills + +**Files:** +- Modify: `core/claude/skills/finish/SKILL.md` +- Modify: `core/claude/skills/brainstorm/SKILL.md` +- Modify: `core/claude/settings.json` + +- [ ] **Step 1: Update finish/SKILL.md** + +In `core/claude/skills/finish/SKILL.md`: + +- Replace step 5 (lines 49-51) push instruction: + From: `git push origin $(git rev-parse --abbrev-ref HEAD)` + To: `bash .claude/skills/github-publish/scripts/push-branch.sh` + +- Update the "Push boundaries" section (lines 53-57): + Replace the raw `git push` instruction with: + `Push only with 'bash .claude/skills/github-publish/scripts/push-branch.sh'. Never use bare 'git push', push to 'main', force-push, delete remote refs, push tags, or push arbitrary refspecs without explicit approval. Do not create PRs, amend commits, delete branches, close comments, or remove worktrees.` + +- [ ] **Step 2: Update brainstorm/SKILL.md** + +In `core/claude/skills/brainstorm/SKILL.md`: + +- Replace the shell guidance (lines 34-35): + From: `Always use 'git push origin $(git rev-parse --abbrev-ref HEAD)' — never use bare 'git push' to avoid accidentally pushing to 'main'.` + To: `Publish through the 'github-publish' skill — 'bash .claude/skills/github-publish/scripts/push-branch.sh'. Never hand-roll 'git push'.` + +- [ ] **Step 3: Update settings.json** + +In `core/claude/settings.json`: + +Add to the `allow` array: +``` +"Bash(bash .claude/skills/github-publish/scripts/push-branch.sh:*)" +``` + +Add to the `ask` array: +``` +"Bash(bash .claude/skills/github-publish/scripts/open-pr.sh:*)" +``` + +- [ ] **Step 4: Verify** + +Run: `codespell core/claude/skills/finish/SKILL.md core/claude/skills/brainstorm/SKILL.md` +Expected: no errors + +- [ ] **Step 5: Commit** + +```bash +git add core/claude/skills/finish/SKILL.md core/claude/skills/brainstorm/SKILL.md core/claude/settings.json +git commit -m "refactor: wire github-publish skill into Claude finish, brainstorm, and settings" +``` + +--- + +## Task 6: Delete Raw `scripts/publish-branch.sh` + +**Files:** +- Delete: `scripts/publish-branch.sh` + +- [ ] **Step 1: Remove the file** + +```bash +git rm scripts/publish-branch.sh +``` + +- [ ] **Step 2: Update AGENTS.md references** + +In `AGENTS.md` (repo-root self-maintenance conventions), the line referencing `scripts/publish-branch.sh` needs updating: + +Replace: +`Use 'scripts/publish-branch.sh' for branch publishing and PR creation so branch-safety checks are centralized.` + +With: +`Use the 'github-publish' skill scripts for branch publishing and PR creation so branch-safety checks are centralized. Never hand-roll 'git push'.` + +- [ ] **Step 3: Verify** + +Run: `codespell AGENTS.md` +Expected: no errors + +- [ ] **Step 4: Commit** + +```bash +git add AGENTS.md +git commit -m "refactor: replace publish-branch.sh with github-publish skill references" +``` + +--- + +## Task 7: Update Claude README for Dual Harness + +**Files:** +- Modify: `core/claude/README.md` + +- [ ] **Step 1: Update the skill table** + +In `core/claude/README.md`, update the skill table to add `/implement`: + +```markdown +| Skill (`/name`) | OpenCode counterpart | Role | +| --- | --- | --- | +| `/brainstorm` | `@brainstorm` | Idea → approved `spec.md` (interactive; offers domain grilling) | +| `/bugfix` | `@bugfix` | Investigate bug → structured GitHub issue; does not fix | +| `/planner` | `@planner` | Spec → task-by-task `plan.md` (offers grilling only when new domain language or non-trivial decisions appear) | +| `/implement` | `@implement` | Execute plan task-by-task via `implement-task` workers, verify, commit | +| `/review-plan` | `@review-plan` | Review + finalize the hand-off plan | +| `/review-code` | `@review-code` | Review a diff/PR → fix-plan hand-off doc | +| `/finish` | `@finish` | Durable feature doc, light glossary/ADR reconciliation, cleanup | +``` + +- [ ] **Step 2: Update the design principle section** + +Replace the opening paragraph: +From: `Claude Code runs the **conversational** half of the agent pipeline. The **implementation** half stays in OpenCode.` +To: `Claude Code runs both the **conversational** and **implementation** halves of the agent pipeline. OpenCode provides the same pipeline; pick one harness per branch.` + +- [ ] **Step 3: Update the shared authored skills list** + +Add `github-publish` to the shared authored skills list: +`- 'github-publish' — used by '/implement', '/finish' (+ OpenCode)` + +Update the symlink inventory to include `github-publish`: +Add to the symlinked shared skills list: +`- 'github-publish' — used by '/implement', '/finish' (+ OpenCode)` + +- [ ] **Step 4: Update the "Usage" section** + +Update the usage line to include `/implement`: +`Type '/brainstorm', '/bugfix', '/implement', '/planner', '/review-plan', '/review-code', or '/finish'` + +- [ ] **Step 5: Update the permissions section** + +Update the permissions description to mention the `github-publish` skill scripts instead of `gh pr create`. + +- [ ] **Step 6: Verify** + +Run: `codespell core/claude/README.md` +Expected: no errors + +- [ ] **Step 7: Commit** + +```bash +git add core/claude/README.md +git commit -m "docs: update Claude README for /implement controller and github-publish skill" +``` + +--- + +## Task 8: Update Existing Claude Skills for `/implement` Cross-References + +**Files:** +- Modify: `core/claude/skills/planner/SKILL.md` +- Modify: `core/claude/skills/review-code/SKILL.md` +- Modify: `core/claude/skills/review-plan/SKILL.md` + +- [ ] **Step 1: Update planner/SKILL.md stop conditions** + +In `core/claude/skills/planner/SKILL.md`, replace the stop conditions (lines 74-77): + +From: +``` +- After the plan is written, **stop**. Optionally suggest `/review-plan` before handoff. +- Implementation runs in **OpenCode** (`@implement` / `@implement-task`), not Claude Code. + Hand off to OpenCode for execution. +``` + +To: +``` +- After the plan is written, **stop**. Optionally suggest `/review-plan` before handoff. +- Implementation can run in either harness: Claude Code (`/implement`) or OpenCode + (`@implement`). Pick one per branch. Suggest the user's preferred harness. +``` + +- [ ] **Step 2: Update review-code/SKILL.md escalation rules** + +In `core/claude/skills/review-code/SKILL.md`, update step 7 (lines 73-76): + +From: +``` +7. If the user approves dispatching `@implement-task` for trivial review-scoped fixes, + dispatch focused tasks only after presenting the exact fix instructions. In Claude + Code, prefer writing the fix-plan handoff document and handing it to OpenCode + (`@implement` / `@implement-task`) for TDD implementation. +``` + +To: +``` +7. If the user approves dispatching `@implement-task` or `/implement` for trivial + review-scoped fixes, dispatch focused tasks only after presenting the exact fix + instructions. Pick one harness per branch. +``` + +- [ ] **Step 3: Update review-plan/SKILL.md finalization** + +In `core/claude/skills/review-plan/SKILL.md`, update the handoff section (line 78): + +From: +`4. Report the finalized plan path and confirm it is ready for OpenCode handoff.` + +To: +`4. Report the finalized plan path and confirm it is ready for implementation handoff (Claude '/implement' or OpenCode '@implement').` + +- [ ] **Step 4: Verify** + +Run: `codespell core/claude/skills/planner/SKILL.md core/claude/skills/review-code/SKILL.md core/claude/skills/review-plan/SKILL.md` +Expected: no errors + +- [ ] **Step 5: Commit** + +```bash +git add core/claude/skills/planner/SKILL.md core/claude/skills/review-code/SKILL.md core/claude/skills/review-plan/SKILL.md +git commit -m "refactor: update Claude planner, review-code, review-plan for dual-harness /implement" +``` + +--- + +## Task 9: Symlink `github-publish` into Claude Skills + +**Files:** +- Modify: `core/claude/` (symlink creation — handled by `init.sh` / `copy.sh`) +- Modify: `scripts/init.sh` +- Modify: `scripts/copy.sh` + +- [ ] **Step 1: Update init.sh symlink creation** + +In `scripts/init.sh`, find the section that creates Claude symlinks (the loop that symlinks authored skills from `.agents/skills/` into `.claude/skills/`). Add `github-publish` to the list of skills to symlink. + +The exact location depends on the current script structure. Look for the array or loop that lists: `grill-with-docs`, `workflow-bug-analysis`, `workflow-brainstorming`, `workflow-planning`, `workflow-verification`, `feature-documentation`, `github-pr-comments`. + +Add `github-publish` to that list. + +- [ ] **Step 2: Update copy.sh symlink creation** + +Same change in `scripts/copy.sh` — add `github-publish` to the symlink list. + +- [ ] **Step 3: Verify** + +Run: `shellcheck scripts/init.sh scripts/copy.sh` +Run: `bash -n scripts/init.sh scripts/copy.sh` +Expected: no errors + +- [ ] **Step 4: Commit** + +```bash +git add scripts/init.sh scripts/copy.sh +git commit -m "feat: add github-publish to Claude symlink creation in installer scripts" +``` + +--- + +## Task 10: Create GitLab Forge Overlay Structure + +**Files:** +- Create: `core/forge/gitlab/AGENTS.md` +- Create: `core/forge/gitlab/.agents/skills/gitlab-publish/SKILL.md` +- Create: `core/forge/gitlab/.agents/skills/gitlab-publish/scripts/push-branch.sh` +- Create: `core/forge/gitlab/.agents/skills/gitlab-publish/scripts/open-mr.sh` +- Create: `core/forge/gitlab/.agents/skills/gitlab-mr-comments/SKILL.md` +- Create: `core/forge/gitlab/.agents/skills/gitlab-mr-comments/scripts/fetch-mr-comments.sh` +- Create: `core/forge/gitlab/.agents/skills/gitlab-mr-comments/scripts/reply-to-mr-comment.sh` + +- [ ] **Step 1: Create AGENTS.md** + +Create `core/forge/gitlab/AGENTS.md`: + +```markdown +## GitLab Conventions + +This repository uses GitLab as its forge. Merge requests (not pull requests) are the review surface. Use `glab` (GitLab CLI) for all forge operations. + +- Publishing goes through `gitlab-publish` skill scripts — never hand-roll `git push`. +- MR comment workflows go through `gitlab-mr-comments` skill scripts. +- Issues are created and managed via `glab issue create/view/list/update`. +``` + +- [ ] **Step 2: Create gitlab-publish SKILL.md** + +Create `core/forge/gitlab/.agents/skills/gitlab-publish/SKILL.md`: + +```markdown +--- +name: gitlab-publish +description: Use when pushing a branch or opening a merge request — guards against pushing to the default branch and against force-pushing +user-invocable: false +--- + +# GitLab Publish + +Safe publishing for this repository. Pushing and opening merge requests go through bundled scripts that **refuse to act on `main`/`master`** and refuse force-pushes. + +## Why a script, not a raw `git push` + +`git push origin $(git rev-parse --abbrev-ref HEAD)` does **not** protect `main`: while you are on `main` it expands to `git push origin main`, and permission globs cannot see through the command substitution to block it. The guard has to inspect the current branch at run time, which is what these scripts do. + +## Push the current branch + +```bash +bash .agents/skills/gitlab-publish/scripts/push-branch.sh +``` + +It pushes the current branch to `origin`, refusing if the branch is `main`, `master`, or a detached `HEAD`, and refusing any `--force` / `-f` / `--force-with-lease` argument. Extra arguments (e.g. `--set-upstream`) are passed through. + +## Open a merge request + +```bash +bash .agents/skills/gitlab-publish/scripts/open-mr.sh [glab mr create flags] +``` + +It refuses on `main`/`master`, skips creation when an MR already exists for the current branch (printing the existing one), and otherwise runs `glab mr create` for the current branch. Pass `--fill` to derive the title/description from commits, or `--title`/`--description` explicitly. + +## Rules + +- Never bypass these scripts with a raw `git push` to publish work — the protection only holds if publishing goes through them. +- Force-pushing and pushing to `main`/`master` are out of scope for this skill; they require a deliberate, human-run command. +``` + +- [ ] **Step 3: Create gitlab-publish push-branch.sh** + +Create `core/forge/gitlab/.agents/skills/gitlab-publish/scripts/push-branch.sh`: + +```bash +#!/usr/bin/env bash +set -euo pipefail + +branch="$(git rev-parse --abbrev-ref HEAD)" + +case "$branch" in + main|master|HEAD) + printf 'Refusing to push: current branch is "%s". Create a scoped feature branch first.\n' "$branch" >&2 + exit 1 + ;; +esac + +# Force-pushing is never part of safe publishing. +for arg in "$@"; do + case "$arg" in + --force|-f|--force-with-lease|--force-with-lease=*) + printf 'Refusing to force-push from this script. Force-push must be a deliberate, human-run command.\n' >&2 + exit 1 + ;; + esac +done + +printf 'Pushing branch "%s" to origin...\n' "$branch" +git push origin "$branch" "$@" +``` + +- [ ] **Step 4: Create gitlab-publish open-mr.sh** + +Create `core/forge/gitlab/.agents/skills/gitlab-publish/scripts/open-mr.sh`: + +```bash +#!/usr/bin/env bash +set -euo pipefail + +branch="$(git rev-parse --abbrev-ref HEAD)" + +case "$branch" in + main|master|HEAD) + printf 'Refusing: current branch is "%s". Open a merge request from a feature branch.\n' "$branch" >&2 + exit 1 + ;; +esac + +# Skip creation if a merge request already exists for this branch. +existing="$(glab mr list --source-branch "$branch" -F json 2>/dev/null | jq -r 'length' || echo 0)" +if [ "${existing:-0}" -gt 0 ]; then + printf 'A merge request already exists for branch "%s":\n' "$branch" + glab mr list --source-branch "$branch" + exit 0 +fi + +printf 'Opening merge request for branch "%s"...\n' "$branch" +glab mr create --source-branch "$branch" "$@" +``` + +- [ ] **Step 5: Create gitlab-mr-comments SKILL.md** + +Create `core/forge/gitlab/.agents/skills/gitlab-mr-comments/SKILL.md`: + +```markdown +--- +name: gitlab-mr-comments +description: Use when GitLab merge request feedback lives in plain notes, inline diff discussions, or discussion threads +user-invocable: false +--- + +# GitLab MR Comments + +Use this for team merge request review workflows where feedback is stored as GitLab notes and discussions. + +## Baseline Failure To Avoid + +Agents naturally mix the GitLab note surfaces: they may read a standalone conversation note when feedback is actually an unresolved inline diff discussion, post a new top-level note instead of replying inside the existing thread, or edit someone else's note instead of replying to it. + +## Skill Scope + +This skill owns MR note mechanics: fetching notes, discussions, and the diff; distinguishing standalone conversation notes from inline diff discussions; obtaining exact discussion IDs; and posting approved replies through project scripts. + +This skill does not own role-level review orchestration. The calling review agent decides how to interpret notes, validate technical claims, combine them with other findings, suggest fixes, edit files, dispatch implementers, or perform final self-review. + +## Read Notes + +Use the bundled read-only helper before proposing fixes. It fetches standalone conversation notes, unresolved inline diff discussions, and the MR diff: + +```bash +bash .agents/skills/gitlab-mr-comments/scripts/fetch-mr-comments.sh [] +``` + +When `` is omitted, the script auto-detects the MR internal ID (`iid`) from the current branch. + +Run the command exactly as shown, without quoting the script path. The review agents have explicit auto-permissions for this command form. + +The helper prints a compact summary first, then full MR metadata, the discussions JSON, and the MR diff. Use the summary for grouping and the full JSON sections for exact discussion IDs. + +Optional read-only modes: + +```bash +bash .agents/skills/gitlab-mr-comments/scripts/fetch-mr-comments.sh [] --comments-only +bash .agents/skills/gitlab-mr-comments/scripts/fetch-mr-comments.sh [] --diff-only +bash .agents/skills/gitlab-mr-comments/scripts/fetch-mr-comments.sh [] --json +``` + +Do not call `glab` directly for reading MR metadata, notes, discussions, or diffs. The helper is the stable interface for this workflow. + +## Classify Notes + +- Standalone conversation notes: top-level MR discussion entries (`individual_note: true`), the GitLab analog of a plain comment. +- Inline diff discussions: resolvable threads whose notes carry a `diff position` (file path and line). Surface only those that are unresolved. +- Outdated inline discussions may still be valid; verify against the current diff before dismissing. + +## Review Workflow + +1. Fetch MR notes and diff when the caller's workflow involves an MR. +2. Use the summary to group target types, then use the full discussions JSON for exact discussion IDs. +3. Distinguish standalone conversation notes from inline diff discussions before posting replies. +4. Surface outdated inline discussions as context; the calling review agent decides whether they still apply. +5. For posting, require an exact approved reply batch with the discussion ID and body. +6. Post only the exact approved reply batch. + +## Replies + +Replying mutates GitLab state, so it is not hidden behind the read helper. Approval for edits, fixes, planning, or any other non-GitLab action does not authorize posting GitLab notes. + +Before posting, present the exact reply batch to the user. Include the discussion ID and body. Wait for explicit approval for that batch. + +After approval, reply inside the existing thread through the project script. Use the `id` of the discussion from the read helper as `discussion_id`: + +Pass a JSON array as the final argument: + +```bash +bash .agents/skills/gitlab-mr-comments/scripts/reply-to-mr-comment.sh [] '[ + { "discussion_id": "a1b2c3d4...", "body": "Fixed in abc123." }, + { "discussion_id": "e5f6g7h8...", "body": "Good catch, updated." } +]' +``` + +The MR number is optional; when omitted, the script auto-detects it from the current branch. Use a one-element array for a single reply. This script replies inside existing discussion threads; it does not open new standalone notes. + +## Common Mistakes + +- Treating standalone conversation notes as complete enough for inline diff review. +- Posting a new top-level note when the user asked to reply inside an inline thread. +- Resolving, editing, or deleting notes without explicit approval. +- Applying external feedback without checking whether it is technically correct. +- Treating approval for edits, fixes, planning, or other non-GitLab work as approval to post GitLab replies. +- Posting a reply batch that differs from the exact batch the user approved. +``` + +- [ ] **Step 6: Create gitlab-mr-comments fetch-mr-comments.sh** + +Create `core/forge/gitlab/.agents/skills/gitlab-mr-comments/scripts/fetch-mr-comments.sh`: + +```bash +#!/usr/bin/env bash +set -euo pipefail + +if [ "$#" -gt 2 ]; then + printf 'Usage: %s [] [--comments-only|--diff-only|--json]\n' "$0" >&2 + exit 2 +fi + +if [[ "${1:-}" =~ ^[0-9]+$ ]]; then + mr="$1" + mode="${2:-}" +else + mr="$(glab mr view -F json | jq -r '.iid')" + mode="${1:-}" +fi +case "$mode" in + ""|--comments-only|--diff-only|--json) ;; + *) + printf 'Unknown mode: %s\n' "$mode" >&2 + printf 'Usage: %s [] [--comments-only|--diff-only|--json]\n' "$0" >&2 + exit 2 + ;; +esac + +if [ "$mode" = "--diff-only" ]; then + glab mr diff "$mr" + exit 0 +fi + +mr_json="$(glab mr view "$mr" -F json)" +discussions_json="$(glab api --paginate "projects/:id/merge_requests/$mr/discussions?per_page=100")" + +if [ "$mode" = "--json" ]; then + jq -n \ + --argjson mr "$mr_json" \ + --argjson discussions "$discussions_json" \ + '{ mr: $mr, discussions: $discussions }' + exit 0 +fi + +printf '## Note Summary\n' +jq -r \ + --argjson mr "$mr_json" ' + def summarize: (. // "" | gsub("\\s+"; " ") | .[0:180]); + "MR !\($mr.iid): \($mr.title)", + "Branch: \($mr.source_branch) -> \($mr.target_branch)", + "URL: \($mr.web_url)", + "", + "Standalone conversation notes (\([.[] | select(.individual_note == true)] | length)):", + ( .[] | select(.individual_note == true) | .notes[] | select(.system == false) + | "- discussion_id=\(.id // "?") note=\(.id) author=\(.author.username) updated=\(.updated_at): \(.body | summarize)" ), + "", + "Unresolved inline diff discussions:", + ( .[] | select(.individual_note != true) | . as $d + | select([.notes[] | select(.resolvable == true and .resolved == false)] | length > 0) + | .notes[0] as $n + | "- discussion_id=\($d.id) \($n.position.new_path // $n.position.old_path // "?"):\($n.position.new_line // $n.position.old_line // "?") author=\($n.author.username) updated=\($n.updated_at): \($n.body | summarize)" ) + ' <<<"$discussions_json" + +printf '\n## MR\n' +printf '%s\n' "$mr_json" + +printf '\n## Discussions\n' +printf '%s\n' "$discussions_json" + +if [ "$mode" = "--comments-only" ]; then + exit 0 +fi + +printf '\n## Diff\n' +glab mr diff "$mr" +``` + +- [ ] **Step 7: Create gitlab-mr-comments reply-to-mr-comment.sh** + +Create `core/forge/gitlab/.agents/skills/gitlab-mr-comments/scripts/reply-to-mr-comment.sh`: + +```bash +#!/usr/bin/env bash +set -euo pipefail + +if [ "$#" -eq 1 ]; then + mr="$(glab mr view -F json | jq -r '.iid')" + replies_json="$1" +elif [ "$#" -eq 2 ] && [[ "$1" =~ ^[0-9]+$ ]]; then + mr="$1" + replies_json="$2" +else + printf 'Usage: %s [] \n' "$0" >&2 + exit 2 +fi + +if ! jq -e 'type == "array" and all(.[]; (.discussion_id | type == "string") and (.body | type == "string"))' \ + >/dev/null <<<"$replies_json"; then + printf 'Reply JSON must be an array of { "discussion_id": string, "body": string } objects.\n' >&2 + exit 2 +fi + +count=$(jq length <<<"$replies_json") +printf 'Posting %d replies to MR !%s...\n' "$count" "$mr" + +while IFS= read -r reply; do + discussion_id=$(jq -r '.discussion_id' <<<"$reply") + body=$(jq -r '.body' <<<"$reply") + + printf ' Replying to discussion %s... ' "$discussion_id" + glab mr note create "$mr" --reply "$discussion_id" -m "$body" + printf 'done\n' +done < <(jq -c '.[]' <<<"$replies_json") + +printf 'All %d replies posted.\n' "$count" +``` + +- [ ] **Step 8: Make all scripts executable** + +```bash +chmod +x core/forge/gitlab/.agents/skills/gitlab-publish/scripts/*.sh +chmod +x core/forge/gitlab/.agents/skills/gitlab-mr-comments/scripts/*.sh +``` + +- [ ] **Step 9: Verify** + +Run: `shellcheck core/forge/gitlab/.agents/skills/*/scripts/*.sh` +Run: `bash -n core/forge/gitlab/.agents/skills/*/scripts/*.sh` +Run: `codespell core/forge/gitlab/.agents/skills/*/SKILL.md core/forge/gitlab/AGENTS.md` +Expected: no errors + +- [ ] **Step 10: Commit** + +```bash +git add core/forge/gitlab/ +git commit -m "feat: add GitLab forge overlay with gitlab-publish and gitlab-mr-comments skills" +``` + +--- + +## Task 11: Create GitLab Forge Config Overlays + +**Files:** +- Create: `core/forge/gitlab/opencode.json` +- Create: `core/forge/gitlab/claude/settings.json` +- Create: `core/forge/gitlab/docs/agents/review-plan.md` +- Create: `core/forge/gitlab/docs/agents/review-code.md` +- Create: `core/forge/gitlab/docs/agents/bugfix.md` + +- [ ] **Step 1: Create opencode.json overlay** + +Create `core/forge/gitlab/opencode.json`: + +```json +{ + "agent": { + "implement": { + "permission": { + "bash": { + "glab mr create *": "allow", + "glab mr list *": "allow", + "glab mr view *": "allow", + "bash .agents/skills/gitlab-publish/scripts/push-branch.sh*": "allow", + "bash .agents/skills/gitlab-publish/scripts/open-mr.sh*": "ask", + "gh pr create *": "deny", + "gh pr list *": "deny", + "gh pr view *": "deny" + }, + "skill": { + "github-publish": "deny", + "gitlab-publish": "allow" + } + } + }, + "finish": { + "permission": { + "bash": { + "glab mr create *": "allow", + "glab mr list *": "allow", + "glab mr view *": "allow", + "bash .agents/skills/gitlab-publish/scripts/push-branch.sh*": "allow", + "bash .agents/skills/gitlab-publish/scripts/open-mr.sh*": "ask", + "gh pr create *": "deny", + "gh pr list *": "deny", + "gh pr view *": "deny" + }, + "skill": { + "github-publish": "deny", + "gitlab-publish": "allow" + } + } + }, + "bugfix": { + "permission": { + "bash": { + "glab issue create *": "allow", + "glab issue view *": "allow", + "glab issue list *": "allow", + "glab issue update *": "allow", + "gh issue create *": "deny", + "gh issue view *": "deny", + "gh issue list *": "deny" + } + } + }, + "review-plan": { + "permission": { + "bash": { + "glab mr view *": "allow", + "glab mr diff *": "allow", + "bash .agents/skills/gitlab-mr-comments/scripts/fetch-mr-comments.sh*": "allow", + "bash .agents/skills/gitlab-mr-comments/scripts/reply-to-mr-comment.sh*": "ask", + "gh pr view *": "deny", + "gh pr diff *": "deny" + }, + "skill": { + "github-pr-comments": "deny", + "gitlab-mr-comments": "allow" + } + } + }, + "review-code": { + "permission": { + "bash": { + "glab mr view *": "allow", + "glab mr diff *": "allow", + "bash .agents/skills/gitlab-mr-comments/scripts/fetch-mr-comments.sh*": "allow", + "bash .agents/skills/gitlab-mr-comments/scripts/reply-to-mr-comment.sh*": "ask", + "gh pr view *": "deny", + "gh pr diff *": "deny" + }, + "skill": { + "github-pr-comments": "deny", + "gitlab-mr-comments": "allow" + } + } + } + } +} +``` + +- [ ] **Step 2: Create claude/settings.json overlay** + +Create `core/forge/gitlab/claude/settings.json`: + +```json +{ + "$schema": "https://json.schemastore.org/claude-code-settings.json", + "permissions": { + "allow": [ + "Bash(glab mr view:*)", + "Bash(glab mr diff:*)", + "Bash(glab mr list:*)", + "Bash(glab issue view:*)", + "Bash(glab issue list:*)", + "Bash(bash .claude/skills/gitlab-publish/scripts/push-branch.sh:*)", + "Bash(bash .claude/skills/gitlab-mr-comments/scripts/fetch-mr-comments.sh:*)" + ], + "ask": [ + "Bash(glab mr create:*)", + "Bash(glab mr note create:*)", + "Bash(glab issue create:*)", + "Bash(glab issue update:*)", + "Bash(bash .claude/skills/gitlab-publish/scripts/open-mr.sh:*)", + "Bash(bash .claude/skills/gitlab-mr-comments/scripts/reply-to-mr-comment.sh:*)" + ], + "deny": [ + "Bash(gh pr create:*)", + "Bash(gh pr list:*)", + "Bash(gh pr view:*)", + "Bash(gh issue create:*)", + "Bash(gh issue view:*)" + ] + } +} +``` + +- [ ] **Step 3: Create role doc overlays** + +Create `core/forge/gitlab/docs/agents/review-plan.md`: + +```markdown +## GitLab + +- Use `gitlab-mr-comments` skill (not `github-pr-comments`) for MR feedback workflows. +- Fetch MR comments: `bash .agents/skills/gitlab-mr-comments/scripts/fetch-mr-comments.sh` +``` + +Create `core/forge/gitlab/docs/agents/review-code.md`: + +```markdown +## GitLab + +- Use `gitlab-mr-comments` skill (not `github-pr-comments`) for MR feedback workflows. +- Fetch MR comments: `bash .agents/skills/gitlab-mr-comments/scripts/fetch-mr-comments.sh` +``` + +Create `core/forge/gitlab/docs/agents/bugfix.md`: + +```markdown +## GitLab + +- Create issues with `glab issue create` (not `gh issue create`). +- Update issues with `glab issue update`. +``` + +- [ ] **Step 4: Verify** + +Run: `jq . core/forge/gitlab/opencode.json` +Run: `jq . core/forge/gitlab/claude/settings.json` +Run: `codespell core/forge/gitlab/docs/agents/*.md` +Expected: no errors + +- [ ] **Step 5: Commit** + +```bash +git add core/forge/gitlab/opencode.json core/forge/gitlab/claude/settings.json core/forge/gitlab/docs/ +git commit -m "feat: add GitLab forge config overlays and role doc additions" +``` + +--- + +## Task 12: Add Forge Selection to Installer Scripts + +**Files:** +- Modify: `scripts/init.sh` +- Modify: `scripts/copy.sh` + +- [ ] **Step 1: Add forge prompt to init.sh** + +In `scripts/init.sh`, add a forge selection prompt after the stack selection. The prompt should offer `github` (default) and `gitlab`. + +When `gitlab` is selected: +1. Apply `core/forge/gitlab/opencode.json` overlay (deep-merge, same as stacks) +2. Apply `core/forge/gitlab/claude/settings.json` overlay (permission union, same as stacks) +3. Apply `core/forge/gitlab/AGENTS.md` addition (concatenate, same as stacks) +4. Copy `core/forge/gitlab/.agents/skills/` into the target `.agents/skills/` +5. Create symlinks for `gitlab-publish` and `gitlab-mr-comments` into `.claude/skills/` +6. Do NOT copy `core/agents/skills/github-publish/` or `core/agents/skills/github-pr-comments/` +7. Concatenate `core/forge/gitlab/docs/agents/*.md` additions to the matching role docs + +When `github` is selected: +1. Copy `core/agents/skills/github-publish/` as normal +2. Copy `core/agents/skills/github-pr-comments/` as normal +3. No forge overlay applied + +- [ ] **Step 2: Add forge prompt to copy.sh** + +Same logic in `scripts/copy.sh`. The forge prompt appears alongside the stack prompt. + +- [ ] **Step 3: Verify** + +Run: `shellcheck scripts/init.sh scripts/copy.sh` +Run: `bash -n scripts/init.sh scripts/copy.sh` +Expected: no errors + +- [ ] **Step 4: Commit** + +```bash +git add scripts/init.sh scripts/copy.sh +git commit -m "feat: add forge selection (github/gitlab) to installer scripts" +``` + +--- + +## Task 13: Update Top-Level README + +**Files:** +- Modify: `README.md` + +- [ ] **Step 1: Update Installed Assets section** + +In `README.md`: + +Add `implement` to the Claude Workflow Entry Skills list: +``` +`brainstorm`, `bugfix`, `implement`, `finish`, `planner`, `review-code`, `review-plan` +``` + +Add `github-publish` to the Authored Reusable Skills list: +``` +`grill-with-docs`, `workflow-bug-analysis`, `workflow-brainstorming`, `workflow-planning`, `workflow-implementation`, `workflow-verification`, `feature-documentation`, `github-publish`, `github-pr-comments` +``` + +- [ ] **Step 2: Update Claude Symlink Model section** + +Add `github-publish` to the symlink table: + +```markdown +| `github-publish` | `../../.agents/skills/github-publish` | +``` + +Remove the note about `workflow-implementation` being reserved for OpenCode — with the dual-harness design, Claude now also has `/implement`. + +- [ ] **Step 3: Add Forge dimension documentation** + +After the "Initial Stacks" section, add: + +```markdown +## Forge Dimension + +The toolkit supports two forge platforms, orthogonal to the stack choice: + +| Forge | Publish Skill | PR/MR Comments Skill | CLI | +|---|---|---|---| +| **github** (default) | `github-publish` | `github-pr-comments` | `gh` | +| **gitlab** | `gitlab-publish` | `gitlab-mr-comments` | `glab` | + +During `init.sh` or `copy.sh`, you choose a forge alongside the stack. The GitLab forge overlay replaces GitHub skills with GitLab equivalents and swaps `gh` permissions for `glab` permissions in both OpenCode and Claude configs. +``` + +- [ ] **Step 4: Update the Extension Guide** + +In the Extension Guide section, add a note about forge overlays: + +```markdown +## Adding Future Forges + +To add a new forge (e.g. Bitbucket, Gitea): + +1. Create `core/forge//` with: + - `AGENTS.md` (forge-specific conventions) + - `.agents/skills/-publish/` (publish skill with scripts) + - `.agents/skills/-pr-comments/` or `-mr-comments/` (review feedback skill) + - `opencode.json` (forge-specific permission overlays) + - `claude/settings.json` (forge-specific permission overlays) + - `docs/agents/.md` additions for review/bugfix roles + +2. The forge assets are merged identically to stacks: config deep-merged, permissions unioned, role docs concatenated, skills copied and symlinked. +``` + +- [ ] **Step 5: Update the workflow table** + +In the Implementation Cycle table, update step 7: +From: `OpenCode '@implement' (controller) which spawns '@implement-task' workers.` +To: `Claude '/implement' or OpenCode '@implement' (controller) which spawns implement-task workers. Pick one harness per branch.` + +- [ ] **Step 6: Verify** + +Run: `codespell README.md` +Expected: no errors + +- [ ] **Step 7: Commit** + +```bash +git add README.md +git commit -m "docs: update README for dual-harness /implement, github-publish skill, and forge dimension" +``` + +--- + +## Task 14: Consistency Verification + +- [ ] **Step 1: Verify all symlinks are accounted for** + +Check that the symlink table in both `core/claude/README.md` and `README.md` lists exactly these skills: +- `grill-with-docs` +- `workflow-bug-analysis` +- `workflow-brainstorming` +- `workflow-planning` +- `workflow-verification` +- `feature-documentation` +- `github-publish` +- `github-pr-comments` + +(8 total for GitHub forge; GitLab forge replaces `github-publish` and `github-pr-comments` with `gitlab-publish` and `gitlab-mr-comments`) + +- [ ] **Step 2: Verify no stale `gh` references remain in core** + +Run: `grep -r "gh pr\|gh issue" core/ --include="*.md" --include="*.json" --include="*.sh" | grep -v "github-" | grep -v "forge/gitlab"` +Expected: no matches (all `gh` references should be inside `github-*` skills or denied in the GitLab overlay) + +- [ ] **Step 3: Verify no stale `git push origin $(git rev-parse"` references remain** + +Run: `grep -r 'git push origin' core/ --include="*.md" | grep -v "github-publish" | grep -v "gitlab-publish"` +Expected: no matches (all push instructions should reference the publish skills) + +- [ ] **Step 4: Verify all agent files reference the correct skills** + +Check that: +- `core/opencode/agents/implement.md` references `github-publish` skill (not raw push) +- `core/opencode/agents/finish.md` references `github-publish` skill (not raw push) +- `core/claude/skills/implement/SKILL.md` references `github-publish` skill +- `core/claude/skills/finish/SKILL.md` references `github-publish` skill +- `core/claude/skills/brainstorm/SKILL.md` references `github-publish` skill + +- [ ] **Step 5: Verify lockfiles** + +No changes to `skills-lock.json` or `core/skills-lock.json` — no new remote skills are being installed. + +- [ ] **Step 6: Final codespell pass** + +Run: `codespell core/ AGENTS.md README.md` +Expected: no errors (or only known false positives) + +- [ ] **Step 7: Commit (if any fixes needed)** + +```bash +git add -A +git commit -m "chore: consistency fixes from verification pass" +``` + +--- + +## Docs Used + +- `AGENTS.md` (repo-root conventions) — dot-mapping, sync invariants, skill lockfile scopes +- `core/claude/README.md` — current Claude skill inventory and symlink model +- `core/AGENTS.md` (template) — dual pipeline description, permissions +- `README.md` — installed assets, workflow table, extension guide +- `scripts/init.sh` — current installer flow +- `scripts/copy.sh` — current copy flow +- All `core/opencode/agents/*.md` — current agent definitions and permissions +- All `core/claude/skills/*/SKILL.md` — current Claude skill definitions +- `core/claude/settings.json` — current Claude permissions +- `core/agents/skills/github-pr-comments/` — pattern reference for forge skills +- `scripts/publish-branch.sh` — current publishing script (to be replaced) From 862b053dab9da73855fdfe4727160d516f5f47c4 Mon Sep 17 00:00:00 2001 From: Simon Flandergan Date: Thu, 25 Jun 2026 22:35:58 +0200 Subject: [PATCH 02/65] plan: revise to side-by-side GitLab skills, drop forge overlay system --- plans/2026-06-25-dual-harness-forge/plan.md | 1096 +++++++------------ 1 file changed, 424 insertions(+), 672 deletions(-) diff --git a/plans/2026-06-25-dual-harness-forge/plan.md b/plans/2026-06-25-dual-harness-forge/plan.md index 4ca662e..b92816d 100644 --- a/plans/2026-06-25-dual-harness-forge/plan.md +++ b/plans/2026-06-25-dual-harness-forge/plan.md @@ -1,69 +1,19 @@ -# Dual-Harness Implementer & Forge-Agnostic Publishing +# Dual-Harness Implementer & GitLab Platform Skills > **For implementation agents:** Execute this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. -**Goal:** Close two structural gaps identified by inspecting an adapted downstream project: (1) Claude Code has no `/implement` controller — implementation is OpenCode-only, and (2) publishing is GitHub-only with no skill wrapper, making it impossible to swap forge platforms or prevent agents from bypassing push safety. +**Goal:** Close two structural gaps identified by inspecting an adapted downstream project: (1) Claude Code has no `/implement` controller — implementation is OpenCode-only, and (2) publishing/review-comment skills are GitHub-only — no `glab` equivalents exist for GitLab-hosted projects. -**Configuration shape:** The Claude implementer adds two files to the core template layer (`core/claude/`) and updates six existing files for cross-references and documentation. Forge-agnostic publishing replaces the raw `scripts/publish-branch.sh` with a `github-publish` authored skill (same pattern as `github-pr-comments`), then adds a `gitlab` forge overlay under `core/forge/gitlab/` with its own publish and MR-comment skills. The installer scripts get a forge prompt. +**Configuration shape:** The Claude implementer adds two files to the core template layer and updates six existing files for cross-references. GitLab skills (`gitlab-publish`, `gitlab-mr-comments`) are added alongside the existing GitHub skills in `core/agents/skills/`. Both sets are always installed; the agents detect which platform the project uses from CLI availability and tool output. Permissions for `glab` are added to `opencode.json` and `claude/settings.json` alongside the existing `gh` permissions. **Configuration surface:** - New: `core/claude/skills/implement/SKILL.md`, `core/claude/agents/implement-task.md` -- New: `core/agents/skills/github-publish/SKILL.md`, `core/agents/skills/github-publish/scripts/push-branch.sh`, `core/agents/skills/github-publish/scripts/open-pr.sh` -- New: `core/forge/gitlab/` tree (publish skill, MR-comments skill, opencode.json overlay, claude/settings.json overlay, AGENTS.md addition) -- Modified: `core/claude/README.md`, `core/claude/skills/planner/SKILL.md`, `core/claude/skills/review-code/SKILL.md`, `core/claude/skills/review-plan/SKILL.md`, `core/opencode/agents/implement.md`, `core/opencode/agents/implement-task.md`, `core/claude/settings.json`, `core/AGENTS.md`, `README.md`, `scripts/init.sh`, `scripts/copy.sh` +- New: `core/agents/skills/github-publish/` (publish skill wrapping the existing `scripts/publish-branch.sh` logic) +- New: `core/agents/skills/gitlab-publish/` (publish skill using `glab`) +- New: `core/agents/skills/gitlab-mr-comments/` (MR comment skill using `glab`) +- Modified: `core/claude/README.md`, `core/claude/skills/planner/SKILL.md`, `core/claude/skills/review-code/SKILL.md`, `core/claude/skills/review-plan/SKILL.md`, `core/claude/skills/brainstorm/SKILL.md`, `core/claude/skills/finish/SKILL.md`, `core/claude/settings.json`, `core/opencode/agents/implement.md`, `core/opencode/agents/finish.md`, `core/opencode/agents/bugfix.md`, `core/opencode/agents/review-code.md`, `core/opencode/agents/review-plan.md`, `core/opencode.json`, `README.md`, `scripts/init.sh`, `scripts/copy.sh` - Removed: `scripts/publish-branch.sh` (replaced by `github-publish` skill) -## File Map - -### Part A — Claude Dual-Harness Implementer (core) - -| File | Action | Responsibility | -|---|---|---| -| `core/claude/skills/implement/SKILL.md` | Create | Claude `/implement` controller — dispatches `implement-task` workers | -| `core/claude/agents/implement-task.md` | Create | Claude `implement-task` subagent definition | -| `core/claude/README.md` | Modify | Add `/implement` to skill table, add `implement-task` agent, update symlink inventory | -| `core/claude/skills/planner/SKILL.md` | Modify | Update stop conditions: mention `/implement` as Claude alternative to OpenCode handoff | -| `core/claude/skills/review-code/SKILL.md` | Modify | Update escalation rules: mention `/implement` for fix-plan execution | -| `core/claude/skills/review-plan/SKILL.md` | Modify | Update handoff text: mention `/implement` as Claude alternative | -| `core/docs/agents/implement-task.md` | Verify | Already correct — no changes expected | -| `README.md` | Modify | Add `implement` to Claude skill list, add `implement-task` agent mention | - -### Part B — Forge-Agnostic Publishing (core) - -| File | Action | Responsibility | -|---|---|---| -| `core/agents/skills/github-publish/SKILL.md` | Create | Safe publishing skill — refuses `main`, refuses force-push | -| `core/agents/skills/github-publish/scripts/push-branch.sh` | Create | Push guard (from `scripts/publish-branch.sh`, hardened) | -| `core/agents/skills/github-publish/scripts/open-pr.sh` | Create | PR creation with existence check | -| `core/opencode/agents/implement.md` | Modify | Replace raw `git push` / `gh pr create` with `github-publish` skill references | -| `core/opencode/agents/implement-task.md` | Modify | No changes expected (workers don't push) | -| `core/opencode/agents/finish.md` | Modify | Replace raw `git push` with `github-publish` skill reference | -| `core/claude/skills/finish/SKILL.md` | Modify | Replace raw `git push` with `github-publish` skill reference | -| `core/claude/skills/brainstorm/SKILL.md` | Modify | Replace raw `git push` with `github-publish` skill reference | -| `core/claude/settings.json` | Modify | Add `github-publish` script permissions | -| `scripts/publish-branch.sh` | Delete | Replaced by `github-publish` skill | -| `README.md` | Modify | Add `github-publish` to authored skills list | - -### Part C — GitLab Forge Overlay - -| File | Action | Responsibility | -|---|---|---| -| `core/forge/gitlab/AGENTS.md` | Create | GitLab-specific conventions addition | -| `core/forge/gitlab/.agents/skills/gitlab-publish/SKILL.md` | Create | GitLab safe publishing skill | -| `core/forge/gitlab/.agents/skills/gitlab-publish/scripts/push-branch.sh` | Create | Push guard (refuses `main`/`master`) | -| `core/forge/gitlab/.agents/skills/gitlab-publish/scripts/open-mr.sh` | Create | MR creation with `glab` | -| `core/forge/gitlab/.agents/skills/gitlab-mr-comments/SKILL.md` | Create | GitLab MR comment fetching and reply | -| `core/forge/gitlab/.agents/skills/gitlab-mr-comments/scripts/fetch-mr-comments.sh` | Create | MR discussion fetcher | -| `core/forge/gitlab/.agents/skills/gitlab-mr-comments/scripts/reply-to-mr-comment.sh` | Create | MR discussion reply poster | -| `core/forge/gitlab/opencode.json` | Create | GitLab-specific bash permission overlays | -| `core/forge/gitlab/claude/settings.json` | Create | GitLab-specific Claude permission overlays | -| `core/forge/gitlab/docs/agents/review-plan.md` | Create | GitLab MR comments loading addition | -| `core/forge/gitlab/docs/agents/review-code.md` | Create | GitLab MR comments loading addition | -| `core/forge/gitlab/docs/agents/bugfix.md` | Create | GitLab issue creation addition | -| `scripts/init.sh` | Modify | Add forge prompt (github/gitlab) | -| `scripts/copy.sh` | Modify | Add forge prompt, merge forge overlay | -| `README.md` | Modify | Document forge dimension, update symlink table | - --- ## Task 1: Create Claude `/implement` Controller Skill @@ -120,19 +70,21 @@ Run targeted verification while iterating and the required final verification be ## Shell guidance - Prefer `git mv` for moves/renames of tracked paths and `git rm` for removals of tracked paths. Use plain `mv`/`rm` only for untracked paths. -- Never work on or push to `main`. Publish through the `github-publish` skill — do not hand-roll `git push`. +- Never work on or push to `main`. Publish through the appropriate publish skill — do not hand-roll `git push`. ## Finishing -After final verification, commit all changes and push the branch with the `github-publish` skill: -`bash .claude/skills/github-publish/scripts/push-branch.sh`. -Then open a pull request with `bash .claude/skills/github-publish/scripts/open-pr.sh` — it skips creation when a PR already exists for the branch. +After final verification, commit all changes and push the branch using the publish skill: +- GitHub: `bash .claude/skills/github-publish/scripts/push-branch.sh` then `bash .claude/skills/github-publish/scripts/open-pr.sh` +- GitLab: `bash .claude/skills/gitlab-publish/scripts/push-branch.sh` then `bash .claude/skills/gitlab-publish/scripts/open-mr.sh` + +The publish scripts refuse `main`/`master` and skip creation when a PR/MR already exists for the branch. ``` - [ ] **Step 2: Verify** Run: `codespell core/claude/skills/implement/SKILL.md` -Expected: no errors (or only false positives for agent-specific terms) +Expected: no errors - [ ] **Step 3: Commit** @@ -226,7 +178,7 @@ user-invocable: false # GitHub Publish -Safe publishing for this repository. Pushing and opening pull requests go through bundled scripts that **refuse to act on `main`** and refuse force-pushes. +Safe publishing for GitHub-hosted repositories. Pushing and opening pull requests go through bundled scripts that **refuse to act on `main`** and refuse force-pushes. ## Why a script, not a raw `git push` @@ -337,356 +289,27 @@ git commit -m "feat: add github-publish authored skill with push guard and PR op --- -## Task 4: Wire `github-publish` into OpenCode Agents - -**Files:** -- Modify: `core/opencode/agents/implement.md` -- Modify: `core/opencode/agents/finish.md` - -- [ ] **Step 1: Update implement.md** - -In `core/opencode/agents/implement.md`: - -Replace the raw push/PR instructions in the body (lines 100-113) with `github-publish` skill references. Specifically: - -- Replace line 100 (`Always use 'git push origin $(git rev-parse --abbrev-ref HEAD)'...`) with: - `Publish through the 'github-publish' skill — 'bash .agents/skills/github-publish/scripts/push-branch.sh' to push, which refuses 'main'. Never hand-roll 'git push': 'git push origin $(...)' silently pushes 'main' when the current branch is 'main'.` - -- Replace line 101 (the `gh pr list --head` check) with: - `Open a pull request with 'bash .agents/skills/github-publish/scripts/open-pr.sh' — it skips creation when a PR already exists for the current branch.` - -- Replace line 113 (the final push+PR block) with: - `After final verification, commit all changes, push the branch with 'bash .agents/skills/github-publish/scripts/push-branch.sh', and open a GitHub pull request with 'bash .agents/skills/github-publish/scripts/open-pr.sh' (it no-ops when a PR already exists). The push script refuses 'main'.` - -- Add `github-publish` to the skill permission allowlist: - Replace `"workflow-implementation": allow` with: - ``` - "workflow-implementation": allow - "github-publish": allow - ``` - -- Add the publish script to bash permissions: - After the `"git push origin $(git rev-parse --abbrev-ref HEAD)": allow` line, add: - ``` - "bash .agents/skills/github-publish/scripts/push-branch.sh*": allow - "bash .agents/skills/github-publish/scripts/open-pr.sh*": ask - ``` - -- Remove the `"git push origin $(git rev-parse --abbrev-ref HEAD)": allow` line (no longer needed since the skill handles it). - -- [ ] **Step 2: Update finish.md** - -In `core/opencode/agents/finish.md`: - -- Replace the push instruction in the body with a `github-publish` skill reference. -- Add `github-publish` to the skill permission allowlist. -- Add the publish script permissions to bash. -- Remove any raw `git push` permission lines that are replaced by the skill. - -- [ ] **Step 3: Verify** - -Run: `codespell core/opencode/agents/implement.md core/opencode/agents/finish.md` -Expected: no errors - -- [ ] **Step 4: Commit** - -```bash -git add core/opencode/agents/implement.md core/opencode/agents/finish.md -git commit -m "refactor: wire github-publish skill into OpenCode implement and finish agents" -``` - ---- - -## Task 5: Wire `github-publish` into Claude Skills - -**Files:** -- Modify: `core/claude/skills/finish/SKILL.md` -- Modify: `core/claude/skills/brainstorm/SKILL.md` -- Modify: `core/claude/settings.json` - -- [ ] **Step 1: Update finish/SKILL.md** - -In `core/claude/skills/finish/SKILL.md`: - -- Replace step 5 (lines 49-51) push instruction: - From: `git push origin $(git rev-parse --abbrev-ref HEAD)` - To: `bash .claude/skills/github-publish/scripts/push-branch.sh` - -- Update the "Push boundaries" section (lines 53-57): - Replace the raw `git push` instruction with: - `Push only with 'bash .claude/skills/github-publish/scripts/push-branch.sh'. Never use bare 'git push', push to 'main', force-push, delete remote refs, push tags, or push arbitrary refspecs without explicit approval. Do not create PRs, amend commits, delete branches, close comments, or remove worktrees.` - -- [ ] **Step 2: Update brainstorm/SKILL.md** - -In `core/claude/skills/brainstorm/SKILL.md`: - -- Replace the shell guidance (lines 34-35): - From: `Always use 'git push origin $(git rev-parse --abbrev-ref HEAD)' — never use bare 'git push' to avoid accidentally pushing to 'main'.` - To: `Publish through the 'github-publish' skill — 'bash .claude/skills/github-publish/scripts/push-branch.sh'. Never hand-roll 'git push'.` - -- [ ] **Step 3: Update settings.json** - -In `core/claude/settings.json`: - -Add to the `allow` array: -``` -"Bash(bash .claude/skills/github-publish/scripts/push-branch.sh:*)" -``` - -Add to the `ask` array: -``` -"Bash(bash .claude/skills/github-publish/scripts/open-pr.sh:*)" -``` - -- [ ] **Step 4: Verify** - -Run: `codespell core/claude/skills/finish/SKILL.md core/claude/skills/brainstorm/SKILL.md` -Expected: no errors - -- [ ] **Step 5: Commit** - -```bash -git add core/claude/skills/finish/SKILL.md core/claude/skills/brainstorm/SKILL.md core/claude/settings.json -git commit -m "refactor: wire github-publish skill into Claude finish, brainstorm, and settings" -``` - ---- - -## Task 6: Delete Raw `scripts/publish-branch.sh` - -**Files:** -- Delete: `scripts/publish-branch.sh` - -- [ ] **Step 1: Remove the file** - -```bash -git rm scripts/publish-branch.sh -``` - -- [ ] **Step 2: Update AGENTS.md references** - -In `AGENTS.md` (repo-root self-maintenance conventions), the line referencing `scripts/publish-branch.sh` needs updating: - -Replace: -`Use 'scripts/publish-branch.sh' for branch publishing and PR creation so branch-safety checks are centralized.` - -With: -`Use the 'github-publish' skill scripts for branch publishing and PR creation so branch-safety checks are centralized. Never hand-roll 'git push'.` - -- [ ] **Step 3: Verify** - -Run: `codespell AGENTS.md` -Expected: no errors - -- [ ] **Step 4: Commit** - -```bash -git add AGENTS.md -git commit -m "refactor: replace publish-branch.sh with github-publish skill references" -``` - ---- - -## Task 7: Update Claude README for Dual Harness - -**Files:** -- Modify: `core/claude/README.md` - -- [ ] **Step 1: Update the skill table** - -In `core/claude/README.md`, update the skill table to add `/implement`: - -```markdown -| Skill (`/name`) | OpenCode counterpart | Role | -| --- | --- | --- | -| `/brainstorm` | `@brainstorm` | Idea → approved `spec.md` (interactive; offers domain grilling) | -| `/bugfix` | `@bugfix` | Investigate bug → structured GitHub issue; does not fix | -| `/planner` | `@planner` | Spec → task-by-task `plan.md` (offers grilling only when new domain language or non-trivial decisions appear) | -| `/implement` | `@implement` | Execute plan task-by-task via `implement-task` workers, verify, commit | -| `/review-plan` | `@review-plan` | Review + finalize the hand-off plan | -| `/review-code` | `@review-code` | Review a diff/PR → fix-plan hand-off doc | -| `/finish` | `@finish` | Durable feature doc, light glossary/ADR reconciliation, cleanup | -``` - -- [ ] **Step 2: Update the design principle section** - -Replace the opening paragraph: -From: `Claude Code runs the **conversational** half of the agent pipeline. The **implementation** half stays in OpenCode.` -To: `Claude Code runs both the **conversational** and **implementation** halves of the agent pipeline. OpenCode provides the same pipeline; pick one harness per branch.` - -- [ ] **Step 3: Update the shared authored skills list** - -Add `github-publish` to the shared authored skills list: -`- 'github-publish' — used by '/implement', '/finish' (+ OpenCode)` - -Update the symlink inventory to include `github-publish`: -Add to the symlinked shared skills list: -`- 'github-publish' — used by '/implement', '/finish' (+ OpenCode)` - -- [ ] **Step 4: Update the "Usage" section** - -Update the usage line to include `/implement`: -`Type '/brainstorm', '/bugfix', '/implement', '/planner', '/review-plan', '/review-code', or '/finish'` - -- [ ] **Step 5: Update the permissions section** - -Update the permissions description to mention the `github-publish` skill scripts instead of `gh pr create`. - -- [ ] **Step 6: Verify** - -Run: `codespell core/claude/README.md` -Expected: no errors - -- [ ] **Step 7: Commit** - -```bash -git add core/claude/README.md -git commit -m "docs: update Claude README for /implement controller and github-publish skill" -``` - ---- - -## Task 8: Update Existing Claude Skills for `/implement` Cross-References - -**Files:** -- Modify: `core/claude/skills/planner/SKILL.md` -- Modify: `core/claude/skills/review-code/SKILL.md` -- Modify: `core/claude/skills/review-plan/SKILL.md` - -- [ ] **Step 1: Update planner/SKILL.md stop conditions** - -In `core/claude/skills/planner/SKILL.md`, replace the stop conditions (lines 74-77): - -From: -``` -- After the plan is written, **stop**. Optionally suggest `/review-plan` before handoff. -- Implementation runs in **OpenCode** (`@implement` / `@implement-task`), not Claude Code. - Hand off to OpenCode for execution. -``` - -To: -``` -- After the plan is written, **stop**. Optionally suggest `/review-plan` before handoff. -- Implementation can run in either harness: Claude Code (`/implement`) or OpenCode - (`@implement`). Pick one per branch. Suggest the user's preferred harness. -``` - -- [ ] **Step 2: Update review-code/SKILL.md escalation rules** - -In `core/claude/skills/review-code/SKILL.md`, update step 7 (lines 73-76): - -From: -``` -7. If the user approves dispatching `@implement-task` for trivial review-scoped fixes, - dispatch focused tasks only after presenting the exact fix instructions. In Claude - Code, prefer writing the fix-plan handoff document and handing it to OpenCode - (`@implement` / `@implement-task`) for TDD implementation. -``` - -To: -``` -7. If the user approves dispatching `@implement-task` or `/implement` for trivial - review-scoped fixes, dispatch focused tasks only after presenting the exact fix - instructions. Pick one harness per branch. -``` - -- [ ] **Step 3: Update review-plan/SKILL.md finalization** - -In `core/claude/skills/review-plan/SKILL.md`, update the handoff section (line 78): - -From: -`4. Report the finalized plan path and confirm it is ready for OpenCode handoff.` - -To: -`4. Report the finalized plan path and confirm it is ready for implementation handoff (Claude '/implement' or OpenCode '@implement').` - -- [ ] **Step 4: Verify** - -Run: `codespell core/claude/skills/planner/SKILL.md core/claude/skills/review-code/SKILL.md core/claude/skills/review-plan/SKILL.md` -Expected: no errors - -- [ ] **Step 5: Commit** - -```bash -git add core/claude/skills/planner/SKILL.md core/claude/skills/review-code/SKILL.md core/claude/skills/review-plan/SKILL.md -git commit -m "refactor: update Claude planner, review-code, review-plan for dual-harness /implement" -``` - ---- - -## Task 9: Symlink `github-publish` into Claude Skills - -**Files:** -- Modify: `core/claude/` (symlink creation — handled by `init.sh` / `copy.sh`) -- Modify: `scripts/init.sh` -- Modify: `scripts/copy.sh` - -- [ ] **Step 1: Update init.sh symlink creation** - -In `scripts/init.sh`, find the section that creates Claude symlinks (the loop that symlinks authored skills from `.agents/skills/` into `.claude/skills/`). Add `github-publish` to the list of skills to symlink. - -The exact location depends on the current script structure. Look for the array or loop that lists: `grill-with-docs`, `workflow-bug-analysis`, `workflow-brainstorming`, `workflow-planning`, `workflow-verification`, `feature-documentation`, `github-pr-comments`. - -Add `github-publish` to that list. - -- [ ] **Step 2: Update copy.sh symlink creation** - -Same change in `scripts/copy.sh` — add `github-publish` to the symlink list. - -- [ ] **Step 3: Verify** - -Run: `shellcheck scripts/init.sh scripts/copy.sh` -Run: `bash -n scripts/init.sh scripts/copy.sh` -Expected: no errors - -- [ ] **Step 4: Commit** - -```bash -git add scripts/init.sh scripts/copy.sh -git commit -m "feat: add github-publish to Claude symlink creation in installer scripts" -``` - ---- - -## Task 10: Create GitLab Forge Overlay Structure +## Task 4: Create `gitlab-publish` Authored Skill **Files:** -- Create: `core/forge/gitlab/AGENTS.md` -- Create: `core/forge/gitlab/.agents/skills/gitlab-publish/SKILL.md` -- Create: `core/forge/gitlab/.agents/skills/gitlab-publish/scripts/push-branch.sh` -- Create: `core/forge/gitlab/.agents/skills/gitlab-publish/scripts/open-mr.sh` -- Create: `core/forge/gitlab/.agents/skills/gitlab-mr-comments/SKILL.md` -- Create: `core/forge/gitlab/.agents/skills/gitlab-mr-comments/scripts/fetch-mr-comments.sh` -- Create: `core/forge/gitlab/.agents/skills/gitlab-mr-comments/scripts/reply-to-mr-comment.sh` - -- [ ] **Step 1: Create AGENTS.md** - -Create `core/forge/gitlab/AGENTS.md`: - -```markdown -## GitLab Conventions - -This repository uses GitLab as its forge. Merge requests (not pull requests) are the review surface. Use `glab` (GitLab CLI) for all forge operations. +- Create: `core/agents/skills/gitlab-publish/SKILL.md` +- Create: `core/agents/skills/gitlab-publish/scripts/push-branch.sh` +- Create: `core/agents/skills/gitlab-publish/scripts/open-mr.sh` -- Publishing goes through `gitlab-publish` skill scripts — never hand-roll `git push`. -- MR comment workflows go through `gitlab-mr-comments` skill scripts. -- Issues are created and managed via `glab issue create/view/list/update`. -``` - -- [ ] **Step 2: Create gitlab-publish SKILL.md** +- [ ] **Step 1: Write the SKILL.md** -Create `core/forge/gitlab/.agents/skills/gitlab-publish/SKILL.md`: +Create `core/agents/skills/gitlab-publish/SKILL.md`: ```markdown --- name: gitlab-publish -description: Use when pushing a branch or opening a merge request — guards against pushing to the default branch and against force-pushing +description: Use when pushing a branch or opening a merge request on a GitLab-hosted repository — guards against pushing to the default branch and against force-pushing user-invocable: false --- # GitLab Publish -Safe publishing for this repository. Pushing and opening merge requests go through bundled scripts that **refuse to act on `main`/`master`** and refuse force-pushes. +Safe publishing for GitLab-hosted repositories. Pushing and opening merge requests go through bundled scripts that **refuse to act on `main`/`master`** and refuse force-pushes. ## Why a script, not a raw `git push` @@ -714,9 +337,9 @@ It refuses on `main`/`master`, skips creation when an MR already exists for the - Force-pushing and pushing to `main`/`master` are out of scope for this skill; they require a deliberate, human-run command. ``` -- [ ] **Step 3: Create gitlab-publish push-branch.sh** +- [ ] **Step 2: Write push-branch.sh** -Create `core/forge/gitlab/.agents/skills/gitlab-publish/scripts/push-branch.sh`: +Create `core/agents/skills/gitlab-publish/scripts/push-branch.sh`: ```bash #!/usr/bin/env bash @@ -745,9 +368,9 @@ printf 'Pushing branch "%s" to origin...\n' "$branch" git push origin "$branch" "$@" ``` -- [ ] **Step 4: Create gitlab-publish open-mr.sh** +- [ ] **Step 3: Write open-mr.sh** -Create `core/forge/gitlab/.agents/skills/gitlab-publish/scripts/open-mr.sh`: +Create `core/agents/skills/gitlab-publish/scripts/open-mr.sh`: ```bash #!/usr/bin/env bash @@ -774,9 +397,39 @@ printf 'Opening merge request for branch "%s"...\n' "$branch" glab mr create --source-branch "$branch" "$@" ``` -- [ ] **Step 5: Create gitlab-mr-comments SKILL.md** +- [ ] **Step 4: Make scripts executable** + +```bash +chmod +x core/agents/skills/gitlab-publish/scripts/push-branch.sh +chmod +x core/agents/skills/gitlab-publish/scripts/open-mr.sh +``` + +- [ ] **Step 5: Verify** + +Run: `shellcheck core/agents/skills/gitlab-publish/scripts/*.sh` +Run: `bash -n core/agents/skills/gitlab-publish/scripts/*.sh` +Run: `codespell core/agents/skills/gitlab-publish/SKILL.md` +Expected: no errors + +- [ ] **Step 6: Commit** + +```bash +git add core/agents/skills/gitlab-publish/ +git commit -m "feat: add gitlab-publish authored skill with push guard and MR opener" +``` + +--- + +## Task 5: Create `gitlab-mr-comments` Authored Skill + +**Files:** +- Create: `core/agents/skills/gitlab-mr-comments/SKILL.md` +- Create: `core/agents/skills/gitlab-mr-comments/scripts/fetch-mr-comments.sh` +- Create: `core/agents/skills/gitlab-mr-comments/scripts/reply-to-mr-comment.sh` + +- [ ] **Step 1: Write the SKILL.md** -Create `core/forge/gitlab/.agents/skills/gitlab-mr-comments/SKILL.md`: +Create `core/agents/skills/gitlab-mr-comments/SKILL.md`: ```markdown --- @@ -787,7 +440,7 @@ user-invocable: false # GitLab MR Comments -Use this for team merge request review workflows where feedback is stored as GitLab notes and discussions. +Use this for team merge request review workflows where feedback is stored as GitLab notes and discussions. This is the GitLab equivalent of `github-pr-comments`. ## Baseline Failure To Avoid @@ -867,9 +520,9 @@ The MR number is optional; when omitted, the script auto-detects it from the cur - Posting a reply batch that differs from the exact batch the user approved. ``` -- [ ] **Step 6: Create gitlab-mr-comments fetch-mr-comments.sh** +- [ ] **Step 2: Write fetch-mr-comments.sh** -Create `core/forge/gitlab/.agents/skills/gitlab-mr-comments/scripts/fetch-mr-comments.sh`: +Create `core/agents/skills/gitlab-mr-comments/scripts/fetch-mr-comments.sh`: ```bash #!/usr/bin/env bash @@ -945,9 +598,9 @@ printf '\n## Diff\n' glab mr diff "$mr" ``` -- [ ] **Step 7: Create gitlab-mr-comments reply-to-mr-comment.sh** +- [ ] **Step 3: Write reply-to-mr-comment.sh** -Create `core/forge/gitlab/.agents/skills/gitlab-mr-comments/scripts/reply-to-mr-comment.sh`: +Create `core/agents/skills/gitlab-mr-comments/scripts/reply-to-mr-comment.sh`: ```bash #!/usr/bin/env bash @@ -985,390 +638,489 @@ done < <(jq -c '.[]' <<<"$replies_json") printf 'All %d replies posted.\n' "$count" ``` -- [ ] **Step 8: Make all scripts executable** +- [ ] **Step 4: Make scripts executable** ```bash -chmod +x core/forge/gitlab/.agents/skills/gitlab-publish/scripts/*.sh -chmod +x core/forge/gitlab/.agents/skills/gitlab-mr-comments/scripts/*.sh +chmod +x core/agents/skills/gitlab-mr-comments/scripts/*.sh ``` -- [ ] **Step 9: Verify** +- [ ] **Step 5: Verify** -Run: `shellcheck core/forge/gitlab/.agents/skills/*/scripts/*.sh` -Run: `bash -n core/forge/gitlab/.agents/skills/*/scripts/*.sh` -Run: `codespell core/forge/gitlab/.agents/skills/*/SKILL.md core/forge/gitlab/AGENTS.md` +Run: `shellcheck core/agents/skills/gitlab-mr-comments/scripts/*.sh` +Run: `bash -n core/agents/skills/gitlab-mr-comments/scripts/*.sh` +Run: `codespell core/agents/skills/gitlab-mr-comments/SKILL.md` Expected: no errors -- [ ] **Step 10: Commit** +- [ ] **Step 6: Commit** ```bash -git add core/forge/gitlab/ -git commit -m "feat: add GitLab forge overlay with gitlab-publish and gitlab-mr-comments skills" +git add core/agents/skills/gitlab-mr-comments/ +git commit -m "feat: add gitlab-mr-comments authored skill with MR discussion fetch and reply" ``` --- -## Task 11: Create GitLab Forge Config Overlays +## Task 6: Wire `github-publish` into OpenCode Agents **Files:** -- Create: `core/forge/gitlab/opencode.json` -- Create: `core/forge/gitlab/claude/settings.json` -- Create: `core/forge/gitlab/docs/agents/review-plan.md` -- Create: `core/forge/gitlab/docs/agents/review-code.md` -- Create: `core/forge/gitlab/docs/agents/bugfix.md` +- Modify: `core/opencode/agents/implement.md` +- Modify: `core/opencode/agents/finish.md` -- [ ] **Step 1: Create opencode.json overlay** +- [ ] **Step 1: Update implement.md** -Create `core/forge/gitlab/opencode.json`: +In `core/opencode/agents/implement.md`: -```json -{ - "agent": { - "implement": { - "permission": { - "bash": { - "glab mr create *": "allow", - "glab mr list *": "allow", - "glab mr view *": "allow", - "bash .agents/skills/gitlab-publish/scripts/push-branch.sh*": "allow", - "bash .agents/skills/gitlab-publish/scripts/open-mr.sh*": "ask", - "gh pr create *": "deny", - "gh pr list *": "deny", - "gh pr view *": "deny" - }, - "skill": { - "github-publish": "deny", - "gitlab-publish": "allow" - } - } - }, - "finish": { - "permission": { - "bash": { - "glab mr create *": "allow", - "glab mr list *": "allow", - "glab mr view *": "allow", - "bash .agents/skills/gitlab-publish/scripts/push-branch.sh*": "allow", - "bash .agents/skills/gitlab-publish/scripts/open-mr.sh*": "ask", - "gh pr create *": "deny", - "gh pr list *": "deny", - "gh pr view *": "deny" - }, - "skill": { - "github-publish": "deny", - "gitlab-publish": "allow" - } - } - }, - "bugfix": { - "permission": { - "bash": { - "glab issue create *": "allow", - "glab issue view *": "allow", - "glab issue list *": "allow", - "glab issue update *": "allow", - "gh issue create *": "deny", - "gh issue view *": "deny", - "gh issue list *": "deny" - } - } - }, - "review-plan": { - "permission": { - "bash": { - "glab mr view *": "allow", - "glab mr diff *": "allow", - "bash .agents/skills/gitlab-mr-comments/scripts/fetch-mr-comments.sh*": "allow", - "bash .agents/skills/gitlab-mr-comments/scripts/reply-to-mr-comment.sh*": "ask", - "gh pr view *": "deny", - "gh pr diff *": "deny" - }, - "skill": { - "github-pr-comments": "deny", - "gitlab-mr-comments": "allow" - } - } - }, - "review-code": { - "permission": { - "bash": { - "glab mr view *": "allow", - "glab mr diff *": "allow", - "bash .agents/skills/gitlab-mr-comments/scripts/fetch-mr-comments.sh*": "allow", - "bash .agents/skills/gitlab-mr-comments/scripts/reply-to-mr-comment.sh*": "ask", - "gh pr view *": "deny", - "gh pr diff *": "deny" - }, - "skill": { - "github-pr-comments": "deny", - "gitlab-mr-comments": "allow" - } - } - } - } -} +Replace the raw push/PR instructions with `github-publish` skill references: + +- Replace line 100 (`Always use 'git push origin $(git rev-parse --abbrev-ref HEAD)'...`) with: + `Publish through the 'github-publish' skill — 'bash .agents/skills/github-publish/scripts/push-branch.sh' to push, which refuses 'main'. Never hand-roll 'git push': 'git push origin $(...)' silently pushes 'main' when the current branch is 'main'.` + +- Replace line 101 (the `gh pr list --head` check) with: + `Open a pull request with 'bash .agents/skills/github-publish/scripts/open-pr.sh' — it skips creation when a PR already exists for the current branch.` + +- Replace line 113 (the final push+PR block) with: + `After final verification, commit all changes, push the branch with 'bash .agents/skills/github-publish/scripts/push-branch.sh', and open a GitHub pull request with 'bash .agents/skills/github-publish/scripts/open-pr.sh' (it no-ops when a PR already exists). The push script refuses 'main'.` + +- Add `github-publish` to the skill permission allowlist after `"workflow-verification": allow`. + +- Add the publish script bash permissions: + ``` + "bash .agents/skills/github-publish/scripts/push-branch.sh*": allow + "bash .agents/skills/github-publish/scripts/open-pr.sh*": ask + ``` + +- Remove the `"git push origin $(git rev-parse --abbrev-ref HEAD)": allow` line. + +- [ ] **Step 2: Update finish.md** + +Same pattern in `core/opencode/agents/finish.md` — replace raw push instructions with `github-publish` skill references, add the skill to the allowlist, add script bash permissions. + +- [ ] **Step 3: Verify** + +Run: `codespell core/opencode/agents/implement.md core/opencode/agents/finish.md` +Expected: no errors + +- [ ] **Step 4: Commit** + +```bash +git add core/opencode/agents/implement.md core/opencode/agents/finish.md +git commit -m "refactor: wire github-publish skill into OpenCode implement and finish agents" +``` + +--- + +## Task 7: Wire `gitlab-publish` into OpenCode Agents + +**Files:** +- Modify: `core/opencode/agents/implement.md` +- Modify: `core/opencode/agents/finish.md` +- Modify: `core/opencode.json` + +- [ ] **Step 1: Add gitlab-publish permissions to implement.md** + +In `core/opencode/agents/implement.md`, add alongside the `github-publish` permissions: + +```yaml + "bash .agents/skills/gitlab-publish/scripts/push-branch.sh*": allow + "bash .agents/skills/gitlab-publish/scripts/open-mr.sh*": ask +``` + +And add to the skill allowlist: +```yaml + "gitlab-publish": allow ``` -- [ ] **Step 2: Create claude/settings.json overlay** +- [ ] **Step 2: Add gitlab-publish permissions to finish.md** -Create `core/forge/gitlab/claude/settings.json`: +Same pattern in `core/opencode/agents/finish.md`. + +- [ ] **Step 3: Add glab permissions to opencode.json** + +In `core/opencode.json`, add to the global permission bash section: ```json -{ - "$schema": "https://json.schemastore.org/claude-code-settings.json", - "permissions": { - "allow": [ - "Bash(glab mr view:*)", - "Bash(glab mr diff:*)", - "Bash(glab mr list:*)", - "Bash(glab issue view:*)", - "Bash(glab issue list:*)", - "Bash(bash .claude/skills/gitlab-publish/scripts/push-branch.sh:*)", - "Bash(bash .claude/skills/gitlab-mr-comments/scripts/fetch-mr-comments.sh:*)" - ], - "ask": [ - "Bash(glab mr create:*)", - "Bash(glab mr note create:*)", - "Bash(glab issue create:*)", - "Bash(glab issue update:*)", - "Bash(bash .claude/skills/gitlab-publish/scripts/open-mr.sh:*)", - "Bash(bash .claude/skills/gitlab-mr-comments/scripts/reply-to-mr-comment.sh:*)" - ], - "deny": [ - "Bash(gh pr create:*)", - "Bash(gh pr list:*)", - "Bash(gh pr view:*)", - "Bash(gh issue create:*)", - "Bash(gh issue view:*)" - ] - } -} +"glab mr create *": "ask", +"glab mr list *": "allow", +"glab mr view *": "allow", +"glab mr diff *": "allow", +"glab issue create *": "ask", +"glab issue view *": "allow", +"glab issue list *": "allow", +"glab issue update *": "ask" ``` -- [ ] **Step 3: Create role doc overlays** +- [ ] **Step 4: Verify** -Create `core/forge/gitlab/docs/agents/review-plan.md`: +Run: `jq . core/opencode.json` +Expected: valid JSON -```markdown -## GitLab +- [ ] **Step 5: Commit** -- Use `gitlab-mr-comments` skill (not `github-pr-comments`) for MR feedback workflows. -- Fetch MR comments: `bash .agents/skills/gitlab-mr-comments/scripts/fetch-mr-comments.sh` +```bash +git add core/opencode/agents/implement.md core/opencode/agents/finish.md core/opencode.json +git commit -m "feat: add gitlab-publish permissions and glab CLI access to OpenCode agents" ``` -Create `core/forge/gitlab/docs/agents/review-code.md`: +--- + +## Task 8: Wire Skills into Claude Settings -```markdown -## GitLab +**Files:** +- Modify: `core/claude/settings.json` +- Modify: `core/claude/skills/finish/SKILL.md` +- Modify: `core/claude/skills/brainstorm/SKILL.md` -- Use `gitlab-mr-comments` skill (not `github-pr-comments`) for MR feedback workflows. -- Fetch MR comments: `bash .agents/skills/gitlab-mr-comments/scripts/fetch-mr-comments.sh` +- [ ] **Step 1: Update settings.json** + +In `core/claude/settings.json`, add to the `allow` array: +``` +"Bash(bash .claude/skills/github-publish/scripts/push-branch.sh:*)", +"Bash(bash .claude/skills/gitlab-publish/scripts/push-branch.sh:*)", +"Bash(bash .claude/skills/gitlab-mr-comments/scripts/fetch-mr-comments.sh:*)", +"Bash(glab mr view:*)", +"Bash(glab mr diff:*)", +"Bash(glab mr list:*)", +"Bash(glab issue view:*)", +"Bash(glab issue list:*)" ``` -Create `core/forge/gitlab/docs/agents/bugfix.md`: +Add to the `ask` array: +``` +"Bash(bash .claude/skills/github-publish/scripts/open-pr.sh:*)", +"Bash(bash .claude/skills/gitlab-publish/scripts/open-mr.sh:*)", +"Bash(bash .claude/skills/gitlab-mr-comments/scripts/reply-to-mr-comment.sh:*)", +"Bash(glab mr create:*)", +"Bash(glab mr note create:*)", +"Bash(glab issue create:*)", +"Bash(glab issue update:*)" +``` + +- [ ] **Step 2: Update finish/SKILL.md** + +Replace the push instructions (step 5 and the "Push boundaries" section) to reference both publish skills: ```markdown -## GitLab +5. **Commit and push.** Commit the feature doc and cleanup when the user requests it, + then push using the appropriate publish skill: + - GitHub: `bash .claude/skills/github-publish/scripts/push-branch.sh` + - GitLab: `bash .claude/skills/gitlab-publish/scripts/push-branch.sh` + +## Push boundaries + +Push only with the publish skill scripts. Never use bare `git push`, push to `main`, +force-push, delete remote refs, push tags, or push arbitrary refspecs without explicit +approval. Do not create PRs, amend commits, delete branches, close comments, or remove +worktrees. +``` + +- [ ] **Step 3: Update brainstorm/SKILL.md** -- Create issues with `glab issue create` (not `gh issue create`). -- Update issues with `glab issue update`. +Replace the shell guidance (lines 34-35): + +```markdown +- Publish through the appropriate publish skill — `bash .claude/skills/github-publish/scripts/push-branch.sh` (GitHub) or `bash .claude/skills/gitlab-publish/scripts/push-branch.sh` (GitLab). Never hand-roll `git push`. ``` - [ ] **Step 4: Verify** -Run: `jq . core/forge/gitlab/opencode.json` -Run: `jq . core/forge/gitlab/claude/settings.json` -Run: `codespell core/forge/gitlab/docs/agents/*.md` +Run: `codespell core/claude/skills/finish/SKILL.md core/claude/skills/brainstorm/SKILL.md` +Run: `jq . core/claude/settings.json` Expected: no errors - [ ] **Step 5: Commit** ```bash -git add core/forge/gitlab/opencode.json core/forge/gitlab/claude/settings.json core/forge/gitlab/docs/ -git commit -m "feat: add GitLab forge config overlays and role doc additions" +git add core/claude/settings.json core/claude/skills/finish/SKILL.md core/claude/skills/brainstorm/SKILL.md +git commit -m "feat: wire publish and gitlab skills into Claude settings, finish, and brainstorm" ``` --- -## Task 12: Add Forge Selection to Installer Scripts +## Task 9: Wire `gitlab-mr-comments` into Review Agents **Files:** -- Modify: `scripts/init.sh` -- Modify: `scripts/copy.sh` +- Modify: `core/opencode/agents/review-code.md` (verify — may not exist as a separate file) +- Modify: `core/opencode/agents/review-plan.md` (verify) +- Modify: `core/claude/skills/review-code/SKILL.md` +- Modify: `core/claude/skills/review-plan/SKILL.md` +- Modify: `core/docs/agents/review-code.md` +- Modify: `core/docs/agents/review-plan.md` -- [ ] **Step 1: Add forge prompt to init.sh** +- [ ] **Step 1: Update role docs to mention both comment skills** -In `scripts/init.sh`, add a forge selection prompt after the stack selection. The prompt should offer `github` (default) and `gitlab`. +In `core/docs/agents/review-code.md`, add to the Load section: +```markdown +- `github-pr-comments` or `gitlab-mr-comments` skill for PR/MR feedback (detect which CLI is available) +``` -When `gitlab` is selected: -1. Apply `core/forge/gitlab/opencode.json` overlay (deep-merge, same as stacks) -2. Apply `core/forge/gitlab/claude/settings.json` overlay (permission union, same as stacks) -3. Apply `core/forge/gitlab/AGENTS.md` addition (concatenate, same as stacks) -4. Copy `core/forge/gitlab/.agents/skills/` into the target `.agents/skills/` -5. Create symlinks for `gitlab-publish` and `gitlab-mr-comments` into `.claude/skills/` -6. Do NOT copy `core/agents/skills/github-publish/` or `core/agents/skills/github-pr-comments/` -7. Concatenate `core/forge/gitlab/docs/agents/*.md` additions to the matching role docs +In `core/docs/agents/review-plan.md`, add the same. -When `github` is selected: -1. Copy `core/agents/skills/github-publish/` as normal -2. Copy `core/agents/skills/github-pr-comments/` as normal -3. No forge overlay applied +- [ ] **Step 2: Update Claude review-code/SKILL.md** -- [ ] **Step 2: Add forge prompt to copy.sh** +In `core/claude/skills/review-code/SKILL.md`, update the references to `github-pr-comments`: -Same logic in `scripts/copy.sh`. The forge prompt appears alongside the stack prompt. +Replace: `Use the 'github-pr-comments' skill for reading and drafting replies to PR comments.` +With: `Use the 'github-pr-comments' skill for GitHub PRs or 'gitlab-mr-comments' skill for GitLab MRs. Detect which CLI is available ('gh' or 'glab') or which the user specifies.` -- [ ] **Step 3: Verify** +Update step 1 similarly: +Replace: `Read open PR comments first by using the 'github-pr-comments' skill.` +With: `Read open PR/MR comments first using the appropriate skill: 'github-pr-comments' for GitHub or 'gitlab-mr-comments' for GitLab.` -Run: `shellcheck scripts/init.sh scripts/copy.sh` -Run: `bash -n scripts/init.sh scripts/copy.sh` +- [ ] **Step 3: Update Claude review-plan/SKILL.md** + +Same pattern — update references to mention both skills with detection. + +- [ ] **Step 4: Add glab permissions to OpenCode review agents** + +In `core/opencode/agents/review-plan.md` and `core/opencode/agents/review-code.md`, add bash permissions for the gitlab-mr-comments scripts: + +```yaml + "bash .agents/skills/gitlab-mr-comments/scripts/fetch-mr-comments.sh*": allow + "bash .agents/skills/gitlab-mr-comments/scripts/reply-to-mr-comment.sh*": ask + "glab mr view *": allow + "glab mr diff *": allow +``` + +And add `gitlab-mr-comments` to the skill allowlist. + +- [ ] **Step 5: Verify** + +Run: `codespell core/claude/skills/review-code/SKILL.md core/claude/skills/review-plan/SKILL.md core/docs/agents/review-code.md core/docs/agents/review-plan.md` Expected: no errors -- [ ] **Step 4: Commit** +- [ ] **Step 6: Commit** ```bash -git add scripts/init.sh scripts/copy.sh -git commit -m "feat: add forge selection (github/gitlab) to installer scripts" +git add core/claude/skills/review-code/SKILL.md core/claude/skills/review-plan/SKILL.md core/docs/agents/review-code.md core/docs/agents/review-plan.md core/opencode/agents/review-code.md core/opencode/agents/review-plan.md +git commit -m "feat: wire gitlab-mr-comments into review agents alongside github-pr-comments" ``` --- -## Task 13: Update Top-Level README +## Task 10: Update Claude README for Dual Harness **Files:** -- Modify: `README.md` +- Modify: `core/claude/README.md` -- [ ] **Step 1: Update Installed Assets section** +- [ ] **Step 1: Update the skill table** -In `README.md`: +Add `/implement` to the skill table: -Add `implement` to the Claude Workflow Entry Skills list: -``` -`brainstorm`, `bugfix`, `implement`, `finish`, `planner`, `review-code`, `review-plan` +```markdown +| Skill (`/name`) | OpenCode counterpart | Role | +| --- | --- | --- | +| `/brainstorm` | `@brainstorm` | Idea → approved `spec.md` (interactive; offers domain grilling) | +| `/bugfix` | `@bugfix` | Investigate bug → structured issue; does not fix | +| `/planner` | `@planner` | Spec → task-by-task `plan.md` (offers grilling only when new domain language or non-trivial decisions appear) | +| `/implement` | `@implement` | Execute plan task-by-task via `implement-task` workers, verify, commit | +| `/review-plan` | `@review-plan` | Review + finalize the hand-off plan | +| `/review-code` | `@review-code` | Review a diff/PR/MR → fix-plan hand-off doc | +| `/finish` | `@finish` | Durable feature doc, light glossary/ADR reconciliation, cleanup | ``` -Add `github-publish` to the Authored Reusable Skills list: +- [ ] **Step 2: Update the design principle section** + +Replace the opening paragraph: +From: `Claude Code runs the **conversational** half of the agent pipeline. The **implementation** half stays in OpenCode.` +To: `Claude Code runs both the **conversational** and **implementation** halves of the agent pipeline. OpenCode provides the same pipeline; pick one harness per branch.` + +- [ ] **Step 3: Update the shared authored skills list** + +Add to the shared authored skills list: ``` -`grill-with-docs`, `workflow-bug-analysis`, `workflow-brainstorming`, `workflow-planning`, `workflow-implementation`, `workflow-verification`, `feature-documentation`, `github-publish`, `github-pr-comments` +- `github-publish` — used by `/implement`, `/finish` (+ OpenCode) +- `gitlab-publish` — used by `/implement`, `/finish` (+ OpenCode; GitLab equivalent) +- `gitlab-mr-comments` — used by `/review-plan`, `/review-code` (+ OpenCode; GitLab equivalent of `github-pr-comments`) ``` -- [ ] **Step 2: Update Claude Symlink Model section** +- [ ] **Step 4: Update the "Usage" section** -Add `github-publish` to the symlink table: +Update the usage line to include `/implement`: +`Type '/brainstorm', '/bugfix', '/implement', '/planner', '/review-plan', '/review-code', or '/finish'` -```markdown +- [ ] **Step 5: Update the permissions section** + +Mention that permissions include both `gh` and `glab` CLI access, and both GitHub and GitLab publish/comment skill scripts. + +- [ ] **Step 6: Update the symlink inventory** + +The symlink table should now include: +``` | `github-publish` | `../../.agents/skills/github-publish` | +| `gitlab-publish` | `../../.agents/skills/gitlab-publish` | +| `gitlab-mr-comments` | `../../.agents/skills/gitlab-mr-comments` | +``` + +Remove the note about `workflow-implementation` being reserved for OpenCode. + +- [ ] **Step 7: Verify** + +Run: `codespell core/claude/README.md` +Expected: no errors + +- [ ] **Step 8: Commit** + +```bash +git add core/claude/README.md +git commit -m "docs: update Claude README for /implement controller and GitLab skills" ``` -Remove the note about `workflow-implementation` being reserved for OpenCode — with the dual-harness design, Claude now also has `/implement`. +--- -- [ ] **Step 3: Add Forge dimension documentation** +## Task 11: Update Existing Claude Skills for `/implement` Cross-References -After the "Initial Stacks" section, add: +**Files:** +- Modify: `core/claude/skills/planner/SKILL.md` +- Modify: `core/claude/skills/review-code/SKILL.md` (if not already updated in Task 9) +- Modify: `core/claude/skills/review-plan/SKILL.md` (if not already updated in Task 9) -```markdown -## Forge Dimension +- [ ] **Step 1: Update planner/SKILL.md stop conditions** -The toolkit supports two forge platforms, orthogonal to the stack choice: +Replace the stop conditions (lines 74-77): -| Forge | Publish Skill | PR/MR Comments Skill | CLI | -|---|---|---|---| -| **github** (default) | `github-publish` | `github-pr-comments` | `gh` | -| **gitlab** | `gitlab-publish` | `gitlab-mr-comments` | `glab` | +From: +``` +- After the plan is written, **stop**. Optionally suggest `/review-plan` before handoff. +- Implementation runs in **OpenCode** (`@implement` / `@implement-task`), not Claude Code. + Hand off to OpenCode for execution. +``` -During `init.sh` or `copy.sh`, you choose a forge alongside the stack. The GitLab forge overlay replaces GitHub skills with GitLab equivalents and swaps `gh` permissions for `glab` permissions in both OpenCode and Claude configs. +To: +``` +- After the plan is written, **stop**. Optionally suggest `/review-plan` before handoff. +- Implementation can run in either harness: Claude Code (`/implement`) or OpenCode + (`@implement`). Pick one per branch. Suggest the user's preferred harness. ``` -- [ ] **Step 4: Update the Extension Guide** +- [ ] **Step 2: Verify** -In the Extension Guide section, add a note about forge overlays: +Run: `codespell core/claude/skills/planner/SKILL.md` +Expected: no errors -```markdown -## Adding Future Forges +- [ ] **Step 3: Commit** + +```bash +git add core/claude/skills/planner/SKILL.md +git commit -m "refactor: update Claude planner for dual-harness /implement handoff" +``` + +--- + +## Task 12: Delete Raw `scripts/publish-branch.sh` and Update Installer Symlinks + +**Files:** +- Delete: `scripts/publish-branch.sh` +- Modify: `scripts/init.sh` +- Modify: `scripts/copy.sh` + +- [ ] **Step 1: Remove publish-branch.sh** + +```bash +git rm scripts/publish-branch.sh +``` + +- [ ] **Step 2: Add new skills to init.sh symlink list** + +In `scripts/init.sh`, find the section that creates Claude symlinks (the loop that symlinks authored skills from `.agents/skills/` into `.claude/skills/`). Add `github-publish`, `gitlab-publish`, and `gitlab-mr-comments` to the list. + +Also ensure `gitlab-publish` and `gitlab-mr-comments` are copied into `.agents/skills/` alongside the existing skills. + +- [ ] **Step 3: Add new skills to copy.sh symlink list** + +Same changes in `scripts/copy.sh`. + +- [ ] **Step 4: Verify** + +Run: `shellcheck scripts/init.sh scripts/copy.sh` +Run: `bash -n scripts/init.sh scripts/copy.sh` +Expected: no errors + +- [ ] **Step 5: Commit** + +```bash +git add scripts/init.sh scripts/copy.sh +git commit -m "feat: add gitlab skills to installer symlink lists, remove publish-branch.sh" +``` + +--- + +## Task 13: Update Top-Level README + +**Files:** +- Modify: `README.md` + +- [ ] **Step 1: Update Installed Assets section** + +Add `implement` to the Claude Workflow Entry Skills: +``` +`brainstorm`, `bugfix`, `implement`, `finish`, `planner`, `review-code`, `review-plan` +``` -To add a new forge (e.g. Bitbucket, Gitea): +Add GitLab skills to the Authored Reusable Skills: +``` +`grill-with-docs`, `workflow-bug-analysis`, `workflow-brainstorming`, `workflow-planning`, `workflow-implementation`, `workflow-verification`, `feature-documentation`, `github-publish`, `github-pr-comments`, `gitlab-publish`, `gitlab-mr-comments` +``` -1. Create `core/forge//` with: - - `AGENTS.md` (forge-specific conventions) - - `.agents/skills/-publish/` (publish skill with scripts) - - `.agents/skills/-pr-comments/` or `-mr-comments/` (review feedback skill) - - `opencode.json` (forge-specific permission overlays) - - `claude/settings.json` (forge-specific permission overlays) - - `docs/agents/.md` additions for review/bugfix roles +- [ ] **Step 2: Update Claude Symlink Model section** -2. The forge assets are merged identically to stacks: config deep-merged, permissions unioned, role docs concatenated, skills copied and symlinked. +Add to the symlink table: +```markdown +| `github-publish` | `../../.agents/skills/github-publish` | +| `gitlab-publish` | `../../.agents/skills/gitlab-publish` | +| `gitlab-mr-comments` | `../../.agents/skills/gitlab-mr-comments` | ``` -- [ ] **Step 5: Update the workflow table** +Remove the note about `workflow-implementation` being reserved for OpenCode. + +- [ ] **Step 3: Update workflow table** In the Implementation Cycle table, update step 7: From: `OpenCode '@implement' (controller) which spawns '@implement-task' workers.` To: `Claude '/implement' or OpenCode '@implement' (controller) which spawns implement-task workers. Pick one harness per branch.` -- [ ] **Step 6: Verify** +- [ ] **Step 4: Verify** Run: `codespell README.md` Expected: no errors -- [ ] **Step 7: Commit** +- [ ] **Step 5: Commit** ```bash git add README.md -git commit -m "docs: update README for dual-harness /implement, github-publish skill, and forge dimension" +git commit -m "docs: update README for dual-harness /implement and GitLab skills" ``` --- ## Task 14: Consistency Verification -- [ ] **Step 1: Verify all symlinks are accounted for** +- [ ] **Step 1: Verify symlink table completeness** -Check that the symlink table in both `core/claude/README.md` and `README.md` lists exactly these skills: -- `grill-with-docs` -- `workflow-bug-analysis` -- `workflow-brainstorming` -- `workflow-planning` -- `workflow-verification` -- `feature-documentation` -- `github-publish` -- `github-pr-comments` +The Claude symlink table should list exactly these skills: +- `grill-with-docs`, `workflow-bug-analysis`, `workflow-brainstorming`, `workflow-planning`, `workflow-verification`, `feature-documentation` +- `github-publish`, `github-pr-comments` +- `gitlab-publish`, `gitlab-mr-comments` -(8 total for GitHub forge; GitLab forge replaces `github-publish` and `github-pr-comments` with `gitlab-publish` and `gitlab-mr-comments`) +(10 total) -- [ ] **Step 2: Verify no stale `gh` references remain in core** +- [ ] **Step 2: Verify no stale raw push references** -Run: `grep -r "gh pr\|gh issue" core/ --include="*.md" --include="*.json" --include="*.sh" | grep -v "github-" | grep -v "forge/gitlab"` -Expected: no matches (all `gh` references should be inside `github-*` skills or denied in the GitLab overlay) +Run: `grep -rn 'git push origin' core/ --include="*.md" | grep -v "github-publish" | grep -v "gitlab-publish" | grep -v "git push" | grep -v "refuse"` +Expected: no matches -- [ ] **Step 3: Verify no stale `git push origin $(git rev-parse"` references remain** +- [ ] **Step 3: Verify all skills exist on disk** -Run: `grep -r 'git push origin' core/ --include="*.md" | grep -v "github-publish" | grep -v "gitlab-publish"` -Expected: no matches (all push instructions should reference the publish skills) +Run: `ls core/agents/skills/github-publish/SKILL.md core/agents/skills/gitlab-publish/SKILL.md core/agents/skills/gitlab-mr-comments/SKILL.md` +Expected: all three files exist -- [ ] **Step 4: Verify all agent files reference the correct skills** +- [ ] **Step 4: Verify lockfiles** -Check that: -- `core/opencode/agents/implement.md` references `github-publish` skill (not raw push) -- `core/opencode/agents/finish.md` references `github-publish` skill (not raw push) -- `core/claude/skills/implement/SKILL.md` references `github-publish` skill -- `core/claude/skills/finish/SKILL.md` references `github-publish` skill -- `core/claude/skills/brainstorm/SKILL.md` references `github-publish` skill +No changes to `skills-lock.json` or `core/skills-lock.json` — no new remote skills are being installed. All new skills are authored. -- [ ] **Step 5: Verify lockfiles** +- [ ] **Step 5: Final codespell pass** -No changes to `skills-lock.json` or `core/skills-lock.json` — no new remote skills are being installed. - -- [ ] **Step 6: Final codespell pass** - -Run: `codespell core/ AGENTS.md README.md` -Expected: no errors (or only known false positives) - -- [ ] **Step 7: Commit (if any fixes needed)** - -```bash -git add -A -git commit -m "chore: consistency fixes from verification pass" -``` +Run: `codespell core/ README.md` +Expected: no errors --- @@ -1378,10 +1130,10 @@ git commit -m "chore: consistency fixes from verification pass" - `core/claude/README.md` — current Claude skill inventory and symlink model - `core/AGENTS.md` (template) — dual pipeline description, permissions - `README.md` — installed assets, workflow table, extension guide -- `scripts/init.sh` — current installer flow -- `scripts/copy.sh` — current copy flow +- `scripts/init.sh` — current installer flow and symlink creation +- `scripts/copy.sh` — current copy flow and symlink creation - All `core/opencode/agents/*.md` — current agent definitions and permissions - All `core/claude/skills/*/SKILL.md` — current Claude skill definitions - `core/claude/settings.json` — current Claude permissions -- `core/agents/skills/github-pr-comments/` — pattern reference for forge skills +- `core/agents/skills/github-pr-comments/` — pattern reference for platform skills - `scripts/publish-branch.sh` — current publishing script (to be replaced) From 9ab69ad9bb9968bae13cf3202ea910fe7a2116b1 Mon Sep 17 00:00:00 2001 From: Simon Flandergan Date: Fri, 26 Jun 2026 07:51:12 +0200 Subject: [PATCH 03/65] refactor: incorporate review findings into dual-harness plan --- plans/2026-06-25-dual-harness-forge/plan.md | 119 +++++++++++++++++--- 1 file changed, 103 insertions(+), 16 deletions(-) diff --git a/plans/2026-06-25-dual-harness-forge/plan.md b/plans/2026-06-25-dual-harness-forge/plan.md index b92816d..fe9e85c 100644 --- a/plans/2026-06-25-dual-harness-forge/plan.md +++ b/plans/2026-06-25-dual-harness-forge/plan.md @@ -4,15 +4,14 @@ **Goal:** Close two structural gaps identified by inspecting an adapted downstream project: (1) Claude Code has no `/implement` controller — implementation is OpenCode-only, and (2) publishing/review-comment skills are GitHub-only — no `glab` equivalents exist for GitLab-hosted projects. -**Configuration shape:** The Claude implementer adds two files to the core template layer and updates six existing files for cross-references. GitLab skills (`gitlab-publish`, `gitlab-mr-comments`) are added alongside the existing GitHub skills in `core/agents/skills/`. Both sets are always installed; the agents detect which platform the project uses from CLI availability and tool output. Permissions for `glab` are added to `opencode.json` and `claude/settings.json` alongside the existing `gh` permissions. +**Configuration shape:** The Claude implementer adds two files to the core template layer and updates existing skills, agents, docs, and settings for cross-references. GitLab skills (`gitlab-publish`, `gitlab-mr-comments`) are added alongside the existing GitHub skills in `core/agents/skills/`. Both sets are always installed; the agents detect which platform the project uses from CLI availability and tool output. Permissions for `glab` are added to `opencode.json` and `claude/settings.json` alongside the existing `gh` permissions. The root `scripts/publish-branch.sh` is preserved as a compatibility wrapper that delegates to the new `github-publish` skill. **Configuration surface:** - New: `core/claude/skills/implement/SKILL.md`, `core/claude/agents/implement-task.md` - New: `core/agents/skills/github-publish/` (publish skill wrapping the existing `scripts/publish-branch.sh` logic) - New: `core/agents/skills/gitlab-publish/` (publish skill using `glab`) - New: `core/agents/skills/gitlab-mr-comments/` (MR comment skill using `glab`) -- Modified: `core/claude/README.md`, `core/claude/skills/planner/SKILL.md`, `core/claude/skills/review-code/SKILL.md`, `core/claude/skills/review-plan/SKILL.md`, `core/claude/skills/brainstorm/SKILL.md`, `core/claude/skills/finish/SKILL.md`, `core/claude/settings.json`, `core/opencode/agents/implement.md`, `core/opencode/agents/finish.md`, `core/opencode/agents/bugfix.md`, `core/opencode/agents/review-code.md`, `core/opencode/agents/review-plan.md`, `core/opencode.json`, `README.md`, `scripts/init.sh`, `scripts/copy.sh` -- Removed: `scripts/publish-branch.sh` (replaced by `github-publish` skill) +- Modified: `core/claude/README.md`, `core/claude/skills/planner/SKILL.md`, `core/claude/skills/review-code/SKILL.md`, `core/claude/skills/review-plan/SKILL.md`, `core/claude/skills/brainstorm/SKILL.md`, `core/claude/skills/finish/SKILL.md`, `core/claude/settings.json`, `core/opencode/agents/implement.md`, `core/opencode/agents/finish.md`, `core/opencode/agents/review-code.md`, `core/opencode/agents/review-plan.md`, `core/opencode/agents/brainstorm.md`, `core/opencode/agents/planner.md`, `core/agents/skills/workflow-implementation/SKILL.md`, `core/opencode.json`, `README.md`, `scripts/init.sh`, `scripts/copy.sh`, `scripts/publish-branch.sh` --- @@ -1006,17 +1005,33 @@ git commit -m "refactor: update Claude planner for dual-harness /implement hando --- -## Task 12: Delete Raw `scripts/publish-branch.sh` and Update Installer Symlinks +## Task 12: Convert `scripts/publish-branch.sh` to Compatibility Wrapper and Update Installers **Files:** -- Delete: `scripts/publish-branch.sh` +- Modify: `scripts/publish-branch.sh` - Modify: `scripts/init.sh` - Modify: `scripts/copy.sh` -- [ ] **Step 1: Remove publish-branch.sh** +- [ ] **Step 1: Convert publish-branch.sh into a wrapper around the github-publish skill** + +The repo's self-maintenance agents (`@implement`, `@planning`, `@review`) and `AGENTS.md` still reference `scripts/publish-branch.sh`. Keep that path working by replacing its contents with a wrapper that delegates to the new `github-publish` skill scripts. + +Write `scripts/publish-branch.sh`: ```bash -git rm scripts/publish-branch.sh +#!/usr/bin/env bash +set -euo pipefail + +# Compatibility wrapper: this repo's self-maintenance agents still invoke +# scripts/publish-branch.sh. It delegates to the github-publish authored skill. +bash core/agents/skills/github-publish/scripts/push-branch.sh --set-upstream +bash core/agents/skills/github-publish/scripts/open-pr.sh --fill +``` + +Make it executable: + +```bash +chmod +x scripts/publish-branch.sh ``` - [ ] **Step 2: Add new skills to init.sh symlink list** @@ -1029,22 +1044,94 @@ Also ensure `gitlab-publish` and `gitlab-mr-comments` are copied into `.agents/s Same changes in `scripts/copy.sh`. +- [ ] **Step 4: Add `.claude/agents/` handling to the installers** + +The new Claude `implement-task` subagent lives in `core/claude/agents/implement-task.md`. Add copy logic to both `scripts/init.sh` and `scripts/copy.sh` so `.claude/agents/*.md` is installed into target projects, analogous to how `.opencode/agents/*.md` is handled. + +- [ ] **Step 5: Verify** + +Run: `shellcheck scripts/init.sh scripts/copy.sh scripts/publish-branch.sh` +Run: `bash -n scripts/init.sh scripts/copy.sh scripts/publish-branch.sh` +Run: `codespell scripts/publish-branch.sh` +Expected: no errors + +- [ ] **Step 6: Smoke-run the installers** + +Run a smoke test against `.temp/`: + +```bash +rm -rf .temp/smoke-init +./scripts/init.sh +# When prompted, choose a test target under .temp/smoke-init and any stack. +# After the run, verify that .temp/smoke-init/.claude/agents/implement-task.md exists +# and that .temp/smoke-init/.claude/skills/github-publish is a symlink resolving +# to ../../.agents/skills/github-publish. + +rm -rf .temp/smoke-copy +mkdir -p .temp/smoke-copy && cd .temp/smoke-copy && git init && git commit --allow-empty -m "init" && cd ../.. +./scripts/copy.sh .temp/smoke-copy +# Verify the same .claude/agents and .claude/skills symlink outcomes. +``` + +Clean up `.temp/smoke-init` and `.temp/smoke-copy` after verification. + +- [ ] **Step 7: Commit** + +```bash +git add scripts/publish-branch.sh scripts/init.sh scripts/copy.sh +git commit -m "feat: add gitlab skills and claude agents to installers, wrap publish-branch.sh" +``` + +--- + +## Task 13: Replace Remaining Raw Push References + +**Files:** +- Modify: `core/agents/skills/workflow-implementation/SKILL.md` +- Modify: `core/claude/skills/planner/SKILL.md` +- Modify: `core/claude/skills/review-plan/SKILL.md` +- Modify: `core/opencode/agents/brainstorm.md` +- Modify: `core/opencode/agents/planner.md` +- Modify: `core/opencode/agents/review-plan.md` + +- [ ] **Step 1: Update shared implementation skill** + +In `core/agents/skills/workflow-implementation/SKILL.md`, replace the raw push/PR instruction at line 100 with: + +`After final verification, the controller commits all changes, pushes the branch with 'bash .agents/skills/github-publish/scripts/push-branch.sh', and opens a GitHub pull request with 'bash .agents/skills/github-publish/scripts/open-pr.sh' if one does not already exist. Never push to 'main'.` + +- [ ] **Step 2: Update Claude planner and review-plan skills** + +In `core/claude/skills/planner/SKILL.md` line 69 and `core/claude/skills/review-plan/SKILL.md` line 81, replace the raw `git push origin $(git rev-parse --abbrev-ref HEAD)` instruction with: + +`- Publish through the appropriate publish skill — 'bash .claude/skills/github-publish/scripts/push-branch.sh' (GitHub) or 'bash .claude/skills/gitlab-publish/scripts/push-branch.sh' (GitLab). Never hand-roll 'git push'.` + +- [ ] **Step 3: Update OpenCode brainstorm, planner, and review-plan agents** + +In `core/opencode/agents/brainstorm.md` line 97, `core/opencode/agents/planner.md` line 91, and `core/opencode/agents/review-plan.md` line 73, replace the raw push instruction with publish-skill references and add the publish script bash permissions: + +```yaml +"bash .agents/skills/github-publish/scripts/push-branch.sh*": allow +"bash .agents/skills/gitlab-publish/scripts/push-branch.sh*": allow +``` + +Remove the `"git push origin $(git rev-parse --abbrev-ref HEAD)": allow` permission from each of these agents (where present). + - [ ] **Step 4: Verify** -Run: `shellcheck scripts/init.sh scripts/copy.sh` -Run: `bash -n scripts/init.sh scripts/copy.sh` +Run: `codespell core/agents/skills/workflow-implementation/SKILL.md core/claude/skills/planner/SKILL.md core/claude/skills/review-plan/SKILL.md core/opencode/agents/brainstorm.md core/opencode/agents/planner.md core/opencode/agents/review-plan.md` Expected: no errors - [ ] **Step 5: Commit** ```bash -git add scripts/init.sh scripts/copy.sh -git commit -m "feat: add gitlab skills to installer symlink lists, remove publish-branch.sh" +git add core/agents/skills/workflow-implementation/SKILL.md core/claude/skills/planner/SKILL.md core/claude/skills/review-plan/SKILL.md core/opencode/agents/brainstorm.md core/opencode/agents/planner.md core/opencode/agents/review-plan.md +git commit -m "refactor: replace remaining raw push references with publish skills" ``` --- -## Task 13: Update Top-Level README +## Task 14: Update Top-Level README **Files:** - Modify: `README.md` @@ -1092,7 +1179,7 @@ git commit -m "docs: update README for dual-harness /implement and GitLab skills --- -## Task 14: Consistency Verification +## Task 15: Consistency Verification - [ ] **Step 1: Verify symlink table completeness** @@ -1105,7 +1192,7 @@ The Claude symlink table should list exactly these skills: - [ ] **Step 2: Verify no stale raw push references** -Run: `grep -rn 'git push origin' core/ --include="*.md" | grep -v "github-publish" | grep -v "gitlab-publish" | grep -v "git push" | grep -v "refuse"` +Run: `grep -R 'git push origin \$(git rev-parse' core/ --include="*.md"` Expected: no matches - [ ] **Step 3: Verify all skills exist on disk** @@ -1119,7 +1206,7 @@ No changes to `skills-lock.json` or `core/skills-lock.json` — no new remote sk - [ ] **Step 5: Final codespell pass** -Run: `codespell core/ README.md` +Run: `codespell core/ README.md scripts/` Expected: no errors --- @@ -1136,4 +1223,4 @@ Expected: no errors - All `core/claude/skills/*/SKILL.md` — current Claude skill definitions - `core/claude/settings.json` — current Claude permissions - `core/agents/skills/github-pr-comments/` — pattern reference for platform skills -- `scripts/publish-branch.sh` — current publishing script (to be replaced) +- `scripts/publish-branch.sh` — current publishing script (to be converted to a github-publish compatibility wrapper) From 6df741dd70f1c0c54d2fbbbe1c9b2c2b7bfab387 Mon Sep 17 00:00:00 2001 From: Simon Flandergan Date: Fri, 26 Jun 2026 07:53:10 +0200 Subject: [PATCH 04/65] feat: add Claude /implement controller skill --- core/claude/skills/implement/SKILL.md | 53 +++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 core/claude/skills/implement/SKILL.md diff --git a/core/claude/skills/implement/SKILL.md b/core/claude/skills/implement/SKILL.md new file mode 100644 index 0000000..61f109b --- /dev/null +++ b/core/claude/skills/implement/SKILL.md @@ -0,0 +1,53 @@ +--- +name: implement +description: Executes an approved plan task-by-task in Claude Code — dispatches a fresh implement-task worker per task, reviews each diff, and runs verification before any completion claim. +argument-hint: [path to approved plan] +disable-model-invocation: true +--- + +You are the implementation controller for this repository. +This is the Claude Code half of implementation; OpenCode (`@implement`) is the equivalent controller on that harness. +Pick one harness per branch — do not run both controllers over the same plan. + +Approved plan (if provided): $ARGUMENTS + +## Load first + +Load `docs/agents/implement.md` and follow its document list exactly. +Then load the approved `plan.md` (and `spec.md` if present) and the docs the plan names. + +Use the `workflow-verification` skill before any completion claim. +Do not say work is complete, fixed, or passing unless the relevant verification commands have just run successfully. + +## Execution rules + +- **Never implement on `main`.** Create or ask for a scoped branch first. +- **Default behavior:** execute the plan task-by-task by dispatching a fresh `implement-task` worker (via the Agent tool, `subagent_type: implement-task`) for each task. This is the standard workflow — do not deviate unless the user explicitly asks for inline implementation. +- **Inline implementation:** acceptable only when the user explicitly asks you to implement directly. When inline, apply the same per-task and review gates as delegated workers. +- **Controller duties:** orchestrate — dispatch tasks, package context for workers, review worker reports and diffs, enforce spec compliance and code-quality gates, and run verification before any completion claim. Give the worker the full task text, relevant context, exact plan/spec paths, affected docs, and current branch state; do not make it reread the whole plan. +- **One focused commit per task.** Delegated workers create the task commit; commit inline only when you execute a task yourself. Review the worker report and `git diff` before moving on. +- Follow TDD for behavior changes unless the plan marks a step as docs-only, config-only, or trivial wiring. +- Do not pause between tasks for routine progress approval. +- Stop and ask only when the same task fails more than three times, the plan conflicts with code reality, or an architectural decision is required. If a task needs an architectural decision, report the blocker and recommend human escalation. + +## Model selection + +Each per-task `implement-task` worker runs on Sonnet — the `implement-task` agent pins `model: sonnet`, so leave the model override off when dispatching it. +If a worker fails to deliver a task (after the per-task retry limit), re-dispatch the same task with a `model` override to a more capable model before escalating to a human. + +## Verification + +Run targeted verification while iterating and the required final verification before claiming completion. Use the `workflow-verification` skill as the completion gate. + +## Shell guidance + +- Prefer `git mv` for moves/renames of tracked paths and `git rm` for removals of tracked paths. Use plain `mv`/`rm` only for untracked paths. +- Never work on or push to `main`. Publish through the appropriate publish skill — do not hand-roll `git push`. + +## Finishing + +After final verification, commit all changes and push the branch using the publish skill: +- GitHub: `bash .claude/skills/github-publish/scripts/push-branch.sh` then `bash .claude/skills/github-publish/scripts/open-pr.sh` +- GitLab: `bash .claude/skills/gitlab-publish/scripts/push-branch.sh` then `bash .claude/skills/gitlab-publish/scripts/open-mr.sh` + +The publish scripts refuse `main`/`master` and skip creation when a PR/MR already exists for the branch. From 14b796286fa55f7959e568024bbd6becede93b44 Mon Sep 17 00:00:00 2001 From: Simon Flandergan Date: Fri, 26 Jun 2026 07:53:14 +0200 Subject: [PATCH 05/65] feat: add Claude implement-task subagent definition --- core/claude/agents/implement-task.md | 37 ++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 core/claude/agents/implement-task.md diff --git a/core/claude/agents/implement-task.md b/core/claude/agents/implement-task.md new file mode 100644 index 0000000..477e3ae --- /dev/null +++ b/core/claude/agents/implement-task.md @@ -0,0 +1,37 @@ +--- +name: implement-task +description: Worker that implements one approved plan task with TDD, a single focused commit, and self-review. Dispatched by the /implement controller — one fresh worker per task. +tools: Bash, Read, Edit, Write, Glob, Grep, Agent +model: sonnet +--- + +You are the single-task implementation worker for this repository. + +Implement exactly one task provided by the `/implement` controller. +Do not read or execute unrelated tasks from the plan unless the controller explicitly asks. + +Load `docs/agents/implement-task.md` and only the task context, spec/plan excerpts, and docs provided or named by the controller. + +## Rules + +- Never work on `main`. +- Follow the provided task text, spec/plan context, and the repository docs the guide (`docs/agents/implement-task.md`) tells you to load for the area you touch. +- Follow TDD for behavior changes unless the task is explicitly docs-only, config-only, or trivial wiring. +- Make the smallest correct change. Make small, justified adaptations to fit the current codebase, and report them clearly. +- If you need to verify an exact file path, module boundary, or existing pattern before editing, dispatch an `Explore` subagent with a focused question rather than guessing. Use it only for read-only verification of your one task — do not re-plan, widen scope, or dispatch other implementers. +- Prefer `git mv` for moves/renames of tracked paths and `git rm` for removals of tracked paths. Use plain `mv`/`rm` only for untracked paths. +- Commit exactly the task changes with the commit message specified by the plan, or a concise message if the plan omitted one. +- Do not push, create pull requests, amend commits, delete branches, remove worktrees, or dispatch other implementers. +- If requirements are unclear, report `NEEDS_CONTEXT` before editing. +- If blocked after three attempts on the same issue, report `BLOCKED` with what you tried. + +Before reporting, self-review the diff for spec compliance, overbuilding, tests, and obvious defects. + +## Report format + +- **Status:** `DONE`, `DONE_WITH_CONCERNS`, `NEEDS_CONTEXT`, or `BLOCKED` +- **Commit:** commit SHA or `none` +- **Implemented:** concise summary +- **Verification:** exact commands run and results +- **Files changed:** paths +- **Concerns:** anything the controller should inspect From 30dacc086884cff2e279f397f694127e993c0758 Mon Sep 17 00:00:00 2001 From: Simon Flandergan Date: Fri, 26 Jun 2026 07:55:48 +0200 Subject: [PATCH 06/65] feat: add github-publish authored skill with push guard and PR opener --- core/agents/skills/github-publish/SKILL.md | 34 +++++++++++++++++++ .../skills/github-publish/scripts/open-pr.sh | 22 ++++++++++++ .../github-publish/scripts/push-branch.sh | 24 +++++++++++++ 3 files changed, 80 insertions(+) create mode 100644 core/agents/skills/github-publish/SKILL.md create mode 100755 core/agents/skills/github-publish/scripts/open-pr.sh create mode 100755 core/agents/skills/github-publish/scripts/push-branch.sh diff --git a/core/agents/skills/github-publish/SKILL.md b/core/agents/skills/github-publish/SKILL.md new file mode 100644 index 0000000..b8bf0c3 --- /dev/null +++ b/core/agents/skills/github-publish/SKILL.md @@ -0,0 +1,34 @@ +--- +name: github-publish +description: Use when pushing a branch or opening a pull request — guards against pushing to the default branch and against force-pushing +user-invocable: false +--- + +# GitHub Publish + +Safe publishing for GitHub-hosted repositories. Pushing and opening pull requests go through bundled scripts that **refuse to act on `main`** and refuse force-pushes. + +## Why a script, not a raw `git push` + +`git push origin $(git rev-parse --abbrev-ref HEAD)` does **not** protect `main`: while you are on `main` it expands to `git push origin main`, and permission globs cannot see through the command substitution to block it. The guard has to inspect the current branch at run time, which is what these scripts do. + +## Push the current branch + +```bash +bash .agents/skills/github-publish/scripts/push-branch.sh +``` + +It pushes the current branch to `origin`, refusing if the branch is `main` or a detached `HEAD`, and refusing any `--force` / `-f` / `--force-with-lease` argument. Extra arguments (e.g. `--set-upstream`) are passed through. + +## Open a pull request + +```bash +bash .agents/skills/github-publish/scripts/open-pr.sh [gh pr create flags] +``` + +It refuses on `main`, skips creation when a PR already exists for the current branch (printing the existing one), and otherwise runs `gh pr create` for the current branch. Pass `--fill` to derive the title/description from commits, or `--title`/`--description` explicitly. + +## Rules + +- Never bypass these scripts with a raw `git push` to publish work — the protection only holds if publishing goes through them. +- Force-pushing and pushing to `main` are out of scope for this skill; they require a deliberate, human-run command. diff --git a/core/agents/skills/github-publish/scripts/open-pr.sh b/core/agents/skills/github-publish/scripts/open-pr.sh new file mode 100755 index 0000000..0cdd22d --- /dev/null +++ b/core/agents/skills/github-publish/scripts/open-pr.sh @@ -0,0 +1,22 @@ +#!/usr/bin/env bash +set -euo pipefail + +branch="$(git rev-parse --abbrev-ref HEAD)" + +case "$branch" in + main|master|HEAD) + printf 'Refusing: current branch is "%s". Open a pull request from a feature branch.\n' "$branch" >&2 + exit 1 + ;; +esac + +# Skip creation if a pull request already exists for this branch. +existing="$(gh pr list --head "$branch" --json url --jq 'length')" +if [ "${existing:-0}" -gt 0 ]; then + printf 'A pull request already exists for branch "%s":\n' "$branch" + gh pr list --head "$branch" --json url,title --jq '.[] | " \(.title) — \(.url)"' + exit 0 +fi + +printf 'Opening pull request for branch "%s"...\n' "$branch" +gh pr create --head "$branch" "$@" diff --git a/core/agents/skills/github-publish/scripts/push-branch.sh b/core/agents/skills/github-publish/scripts/push-branch.sh new file mode 100755 index 0000000..788047c --- /dev/null +++ b/core/agents/skills/github-publish/scripts/push-branch.sh @@ -0,0 +1,24 @@ +#!/usr/bin/env bash +set -euo pipefail + +branch="$(git rev-parse --abbrev-ref HEAD)" + +case "$branch" in + main|master|HEAD) + printf 'Refusing to push: current branch is "%s". Create a scoped feature branch first.\n' "$branch" >&2 + exit 1 + ;; +esac + +# Force-pushing is never part of safe publishing. +for arg in "$@"; do + case "$arg" in + --force|-f|--force-with-lease|--force-with-lease=*) + printf 'Refusing to force-push from this script. Force-push must be a deliberate, human-run command.\n' >&2 + exit 1 + ;; + esac +done + +printf 'Pushing branch "%s" to origin...\n' "$branch" +git push origin "$branch" "$@" From 1a2c33bf39df2582f7685d7e1674359a57820d97 Mon Sep 17 00:00:00 2001 From: Simon Flandergan Date: Fri, 26 Jun 2026 07:56:18 +0200 Subject: [PATCH 07/65] feat: add gitlab-publish authored skill with push guard and MR opener --- core/agents/skills/gitlab-publish/SKILL.md | 34 +++++++++++++++++++ .../skills/gitlab-publish/scripts/open-mr.sh | 22 ++++++++++++ .../gitlab-publish/scripts/push-branch.sh | 24 +++++++++++++ 3 files changed, 80 insertions(+) create mode 100644 core/agents/skills/gitlab-publish/SKILL.md create mode 100755 core/agents/skills/gitlab-publish/scripts/open-mr.sh create mode 100755 core/agents/skills/gitlab-publish/scripts/push-branch.sh diff --git a/core/agents/skills/gitlab-publish/SKILL.md b/core/agents/skills/gitlab-publish/SKILL.md new file mode 100644 index 0000000..5a12de5 --- /dev/null +++ b/core/agents/skills/gitlab-publish/SKILL.md @@ -0,0 +1,34 @@ +--- +name: gitlab-publish +description: Use when pushing a branch or opening a merge request on a GitLab-hosted repository — guards against pushing to the default branch and against force-pushing +user-invocable: false +--- + +# GitLab Publish + +Safe publishing for GitLab-hosted repositories. Pushing and opening merge requests go through bundled scripts that **refuse to act on `main`/`master`** and refuse force-pushes. + +## Why a script, not a raw `git push` + +`git push origin $(git rev-parse --abbrev-ref HEAD)` does **not** protect `main`: while you are on `main` it expands to `git push origin main`, and permission globs cannot see through the command substitution to block it. The guard has to inspect the current branch at run time, which is what these scripts do. + +## Push the current branch + +```bash +bash .agents/skills/gitlab-publish/scripts/push-branch.sh +``` + +It pushes the current branch to `origin`, refusing if the branch is `main`, `master`, or a detached `HEAD`, and refusing any `--force` / `-f` / `--force-with-lease` argument. Extra arguments (e.g. `--set-upstream`) are passed through. + +## Open a merge request + +```bash +bash .agents/skills/gitlab-publish/scripts/open-mr.sh [glab mr create flags] +``` + +It refuses on `main`/`master`, skips creation when an MR already exists for the current branch (printing the existing one), and otherwise runs `glab mr create` for the current branch. Pass `--fill` to derive the title/description from commits, or `--title`/`--description` explicitly. + +## Rules + +- Never bypass these scripts with a raw `git push` to publish work — the protection only holds if publishing goes through them. +- Force-pushing and pushing to `main`/`master` are out of scope for this skill; they require a deliberate, human-run command. diff --git a/core/agents/skills/gitlab-publish/scripts/open-mr.sh b/core/agents/skills/gitlab-publish/scripts/open-mr.sh new file mode 100755 index 0000000..bcad898 --- /dev/null +++ b/core/agents/skills/gitlab-publish/scripts/open-mr.sh @@ -0,0 +1,22 @@ +#!/usr/bin/env bash +set -euo pipefail + +branch="$(git rev-parse --abbrev-ref HEAD)" + +case "$branch" in + main|master|HEAD) + printf 'Refusing: current branch is "%s". Open a merge request from a feature branch.\n' "$branch" >&2 + exit 1 + ;; +esac + +# Skip creation if a merge request already exists for this branch. +existing="$(glab mr list --source-branch "$branch" -F json 2>/dev/null | jq -r 'length' || echo 0)" +if [ "${existing:-0}" -gt 0 ]; then + printf 'A merge request already exists for branch "%s":\n' "$branch" + glab mr list --source-branch "$branch" + exit 0 +fi + +printf 'Opening merge request for branch "%s"...\n' "$branch" +glab mr create --source-branch "$branch" "$@" diff --git a/core/agents/skills/gitlab-publish/scripts/push-branch.sh b/core/agents/skills/gitlab-publish/scripts/push-branch.sh new file mode 100755 index 0000000..788047c --- /dev/null +++ b/core/agents/skills/gitlab-publish/scripts/push-branch.sh @@ -0,0 +1,24 @@ +#!/usr/bin/env bash +set -euo pipefail + +branch="$(git rev-parse --abbrev-ref HEAD)" + +case "$branch" in + main|master|HEAD) + printf 'Refusing to push: current branch is "%s". Create a scoped feature branch first.\n' "$branch" >&2 + exit 1 + ;; +esac + +# Force-pushing is never part of safe publishing. +for arg in "$@"; do + case "$arg" in + --force|-f|--force-with-lease|--force-with-lease=*) + printf 'Refusing to force-push from this script. Force-push must be a deliberate, human-run command.\n' >&2 + exit 1 + ;; + esac +done + +printf 'Pushing branch "%s" to origin...\n' "$branch" +git push origin "$branch" "$@" From 2ff5cd4f808c439c18923e5dba599eec789a3f72 Mon Sep 17 00:00:00 2001 From: Simon Flandergan Date: Fri, 26 Jun 2026 07:56:43 +0200 Subject: [PATCH 08/65] feat: add gitlab-mr-comments authored skill with MR discussion fetch and reply --- .../agents/skills/gitlab-mr-comments/SKILL.md | 86 +++++++++++++++++++ .../scripts/fetch-mr-comments.sh | 71 +++++++++++++++ .../scripts/reply-to-mr-comment.sh | 33 +++++++ 3 files changed, 190 insertions(+) create mode 100644 core/agents/skills/gitlab-mr-comments/SKILL.md create mode 100755 core/agents/skills/gitlab-mr-comments/scripts/fetch-mr-comments.sh create mode 100755 core/agents/skills/gitlab-mr-comments/scripts/reply-to-mr-comment.sh diff --git a/core/agents/skills/gitlab-mr-comments/SKILL.md b/core/agents/skills/gitlab-mr-comments/SKILL.md new file mode 100644 index 0000000..2563f85 --- /dev/null +++ b/core/agents/skills/gitlab-mr-comments/SKILL.md @@ -0,0 +1,86 @@ +--- +name: gitlab-mr-comments +description: Use when GitLab merge request feedback lives in plain notes, inline diff discussions, or discussion threads +user-invocable: false +--- + +# GitLab MR Comments + +Use this for team merge request review workflows where feedback is stored as GitLab notes and discussions. This is the GitLab equivalent of `github-pr-comments`. + +## Baseline Failure To Avoid + +Agents naturally mix the GitLab note surfaces: they may read a standalone conversation note when feedback is actually an unresolved inline diff discussion, post a new top-level note instead of replying inside the existing thread, or edit someone else's note instead of replying to it. + +## Skill Scope + +This skill owns MR note mechanics: fetching notes, discussions, and the diff; distinguishing standalone conversation notes from inline diff discussions; obtaining exact discussion IDs; and posting approved replies through project scripts. + +This skill does not own role-level review orchestration. The calling review agent decides how to interpret notes, validate technical claims, combine them with other findings, suggest fixes, edit files, dispatch implementers, or perform final self-review. + +## Read Notes + +Use the bundled read-only helper before proposing fixes. It fetches standalone conversation notes, unresolved inline diff discussions, and the MR diff: + +```bash +bash .agents/skills/gitlab-mr-comments/scripts/fetch-mr-comments.sh [] +``` + +When `` is omitted, the script auto-detects the MR internal ID (`iid`) from the current branch. + +Run the command exactly as shown, without quoting the script path. The review agents have explicit auto-permissions for this command form. + +The helper prints a compact summary first, then full MR metadata, the discussions JSON, and the MR diff. Use the summary for grouping and the full JSON sections for exact discussion IDs. + +Optional read-only modes: + +```bash +bash .agents/skills/gitlab-mr-comments/scripts/fetch-mr-comments.sh [] --comments-only +bash .agents/skills/gitlab-mr-comments/scripts/fetch-mr-comments.sh [] --diff-only +bash .agents/skills/gitlab-mr-comments/scripts/fetch-mr-comments.sh [] --json +``` + +Do not call `glab` directly for reading MR metadata, notes, discussions, or diffs. The helper is the stable interface for this workflow. + +## Classify Notes + +- Standalone conversation notes: top-level MR discussion entries (`individual_note: true`), the GitLab analog of a plain comment. +- Inline diff discussions: resolvable threads whose notes carry a `diff position` (file path and line). Surface only those that are unresolved. +- Outdated inline discussions may still be valid; verify against the current diff before dismissing. + +## Review Workflow + +1. Fetch MR notes and diff when the caller's workflow involves an MR. +2. Use the summary to group target types, then use the full discussions JSON for exact discussion IDs. +3. Distinguish standalone conversation notes from inline diff discussions before posting replies. +4. Surface outdated inline discussions as context; the calling review agent decides whether they still apply. +5. For posting, require an exact approved reply batch with the discussion ID and body. +6. Post only the exact approved reply batch. + +## Replies + +Replying mutates GitLab state, so it is not hidden behind the read helper. Approval for edits, fixes, planning, or any other non-GitLab action does not authorize posting GitLab notes. + +Before posting, present the exact reply batch to the user. Include the discussion ID and body. Wait for explicit approval for that batch. + +After approval, reply inside the existing thread through the project script. Use the `id` of the discussion from the read helper as `discussion_id`: + +Pass a JSON array as the final argument: + +```bash +bash .agents/skills/gitlab-mr-comments/scripts/reply-to-mr-comment.sh [] '[ + { "discussion_id": "a1b2c3d4...", "body": "Fixed in abc123." }, + { "discussion_id": "e5f6g7h8...", "body": "Good catch, updated." } +]' +``` + +The MR number is optional; when omitted, the script auto-detects it from the current branch. Use a one-element array for a single reply. This script replies inside existing discussion threads; it does not open new standalone notes. + +## Common Mistakes + +- Treating standalone conversation notes as complete enough for inline diff review. +- Posting a new top-level note when the user asked to reply inside an inline thread. +- Resolving, editing, or deleting notes without explicit approval. +- Applying external feedback without checking whether it is technically correct. +- Treating approval for edits, fixes, planning, or other non-GitLab work as approval to post GitLab replies. +- Posting a reply batch that differs from the exact batch the user approved. diff --git a/core/agents/skills/gitlab-mr-comments/scripts/fetch-mr-comments.sh b/core/agents/skills/gitlab-mr-comments/scripts/fetch-mr-comments.sh new file mode 100755 index 0000000..99d69f6 --- /dev/null +++ b/core/agents/skills/gitlab-mr-comments/scripts/fetch-mr-comments.sh @@ -0,0 +1,71 @@ +#!/usr/bin/env bash +set -euo pipefail + +if [ "$#" -gt 2 ]; then + printf 'Usage: %s [] [--comments-only|--diff-only|--json]\n' "$0" >&2 + exit 2 +fi + +if [[ "${1:-}" =~ ^[0-9]+$ ]]; then + mr="$1" + mode="${2:-}" +else + mr="$(glab mr view -F json | jq -r '.iid')" + mode="${1:-}" +fi +case "$mode" in + ""|--comments-only|--diff-only|--json) ;; + *) + printf 'Unknown mode: %s\n' "$mode" >&2 + printf 'Usage: %s [] [--comments-only|--diff-only|--json]\n' "$0" >&2 + exit 2 + ;; +esac + +if [ "$mode" = "--diff-only" ]; then + glab mr diff "$mr" + exit 0 +fi + +mr_json="$(glab mr view "$mr" -F json)" +discussions_json="$(glab api --paginate "projects/:id/merge_requests/$mr/discussions?per_page=100")" + +if [ "$mode" = "--json" ]; then + jq -n \ + --argjson mr "$mr_json" \ + --argjson discussions "$discussions_json" \ + '{ mr: $mr, discussions: $discussions }' + exit 0 +fi + +printf '## Note Summary\n' +jq -r \ + --argjson mr "$mr_json" ' + def summarize: (. // "" | gsub("\\s+"; " ") | .[0:180]); + "MR !\($mr.iid): \($mr.title)", + "Branch: \($mr.source_branch) -> \($mr.target_branch)", + "URL: \($mr.web_url)", + "", + "Standalone conversation notes (\([.[] | select(.individual_note == true)] | length)):", + ( .[] | select(.individual_note == true) | .notes[] | select(.system == false) + | "- discussion_id=\(.id // "?") note=\(.id) author=\(.author.username) updated=\(.updated_at): \(.body | summarize)" ), + "", + "Unresolved inline diff discussions:", + ( .[] | select(.individual_note != true) | . as $d + | select([.notes[] | select(.resolvable == true and .resolved == false)] | length > 0) + | .notes[0] as $n + | "- discussion_id=\($d.id) \($n.position.new_path // $n.position.old_path // "?"):\($n.position.new_line // $n.position.old_line // "?") author=\($n.author.username) updated=\($n.updated_at): \($n.body | summarize)" ) + ' <<<"$discussions_json" + +printf '\n## MR\n' +printf '%s\n' "$mr_json" + +printf '\n## Discussions\n' +printf '%s\n' "$discussions_json" + +if [ "$mode" = "--comments-only" ]; then + exit 0 +fi + +printf '\n## Diff\n' +glab mr diff "$mr" diff --git a/core/agents/skills/gitlab-mr-comments/scripts/reply-to-mr-comment.sh b/core/agents/skills/gitlab-mr-comments/scripts/reply-to-mr-comment.sh new file mode 100755 index 0000000..791e976 --- /dev/null +++ b/core/agents/skills/gitlab-mr-comments/scripts/reply-to-mr-comment.sh @@ -0,0 +1,33 @@ +#!/usr/bin/env bash +set -euo pipefail + +if [ "$#" -eq 1 ]; then + mr="$(glab mr view -F json | jq -r '.iid')" + replies_json="$1" +elif [ "$#" -eq 2 ] && [[ "$1" =~ ^[0-9]+$ ]]; then + mr="$1" + replies_json="$2" +else + printf 'Usage: %s [] \n' "$0" >&2 + exit 2 +fi + +if ! jq -e 'type == "array" and all(.[]; (.discussion_id | type == "string") and (.body | type == "string"))' \ + >/dev/null <<<"$replies_json"; then + printf 'Reply JSON must be an array of { "discussion_id": string, "body": string } objects.\n' >&2 + exit 2 +fi + +count=$(jq length <<<"$replies_json") +printf 'Posting %d replies to MR !%s...\n' "$count" "$mr" + +while IFS= read -r reply; do + discussion_id=$(jq -r '.discussion_id' <<<"$reply") + body=$(jq -r '.body' <<<"$reply") + + printf ' Replying to discussion %s... ' "$discussion_id" + glab mr note create "$mr" --reply "$discussion_id" -m "$body" + printf 'done\n' +done < <(jq -c '.[]' <<<"$replies_json") + +printf 'All %d replies posted.\n' "$count" From c1feff5140157abb74c48fed695d2f66eb4db329 Mon Sep 17 00:00:00 2001 From: Simon Flandergan Date: Fri, 26 Jun 2026 07:57:49 +0200 Subject: [PATCH 09/65] feat: wire publish and gitlab skills into Claude settings, finish, and brainstorm --- core/claude/settings.json | 20 ++++++++++++++++++-- core/claude/skills/brainstorm/SKILL.md | 3 +-- core/claude/skills/finish/SKILL.md | 13 +++++++------ 3 files changed, 26 insertions(+), 10 deletions(-) diff --git a/core/claude/settings.json b/core/claude/settings.json index 8d62b85..29b0292 100644 --- a/core/claude/settings.json +++ b/core/claude/settings.json @@ -46,7 +46,16 @@ "Bash(bash .claude/skills/workflow-bug-analysis/scripts/create-bug-issue.sh:*)", "Bash(gh issue list:*)", "Bash(gh issue view:*)", - "Bash(gh search issues:*)" + "Bash(gh search issues:*)", + + "Bash(bash .claude/skills/github-publish/scripts/push-branch.sh:*)", + "Bash(bash .claude/skills/gitlab-publish/scripts/push-branch.sh:*)", + "Bash(bash .claude/skills/gitlab-mr-comments/scripts/fetch-mr-comments.sh:*)", + "Bash(glab mr view:*)", + "Bash(glab mr diff:*)", + "Bash(glab mr list:*)", + "Bash(glab issue view:*)", + "Bash(glab issue list:*)" ], "ask": [ "Bash(git push:*)", @@ -56,7 +65,14 @@ "Bash(rm:*)", "Bash(rm -rf:*)", "Bash(bash .claude/skills/github-pr-comments/scripts/reply-to-pr-comment.sh:*)", - "Bash(bash .claude/skills/workflow-bug-analysis/scripts/update-bug-issue.sh:*)" + "Bash(bash .claude/skills/workflow-bug-analysis/scripts/update-bug-issue.sh:*)", + "Bash(bash .claude/skills/github-publish/scripts/open-pr.sh:*)", + "Bash(bash .claude/skills/gitlab-publish/scripts/open-mr.sh:*)", + "Bash(bash .claude/skills/gitlab-mr-comments/scripts/reply-to-mr-comment.sh:*)", + "Bash(glab mr create:*)", + "Bash(glab mr note create:*)", + "Bash(glab issue create:*)", + "Bash(glab issue update:*)" ], "deny": [ "Bash(git branch -d:*)", diff --git a/core/claude/skills/brainstorm/SKILL.md b/core/claude/skills/brainstorm/SKILL.md index d34810c..806d640 100644 --- a/core/claude/skills/brainstorm/SKILL.md +++ b/core/claude/skills/brainstorm/SKILL.md @@ -31,8 +31,7 @@ Use `grill-with-docs` when the brainstorm needs domain grilling. - Prefer relative workspace paths in commands and examples (e.g. `mkdir -p plans/2026-05-30-feature-name`). Avoid absolute workspace paths unless a tool requires them. -- Always use `git push origin $(git rev-parse --abbrev-ref HEAD)` — never use bare - `git push` to avoid accidentally pushing to `main`. +- Publish through the appropriate publish skill — `bash .claude/skills/github-publish/scripts/push-branch.sh` (GitHub) or `bash .claude/skills/gitlab-publish/scripts/push-branch.sh` (GitLab). Never hand-roll `git push`. ## Stop conditions diff --git a/core/claude/skills/finish/SKILL.md b/core/claude/skills/finish/SKILL.md index 35d0cfc..47a1697 100644 --- a/core/claude/skills/finish/SKILL.md +++ b/core/claude/skills/finish/SKILL.md @@ -47,12 +47,13 @@ explore subagent with a focused question. feature doc is written and the user approves cleanup. Use `git rm` for tracked files; use plain `rm` only for untracked paths. 5. **Commit and push.** Commit the feature doc and cleanup when the user requests it, - then push the current scoped branch with - `git push origin $(git rev-parse --abbrev-ref HEAD)`. + then push using the appropriate publish skill: + - GitHub: `bash .claude/skills/github-publish/scripts/push-branch.sh` + - GitLab: `bash .claude/skills/gitlab-publish/scripts/push-branch.sh` ## Push boundaries -Push only with `git push origin $(git rev-parse --abbrev-ref HEAD)`. Never use bare -`git push`, push to `main`, force-push, delete remote refs, push tags, or push -arbitrary refspecs without explicit approval. Do not create PRs, amend commits, delete -branches, close comments, or remove worktrees. +Push only with the publish skill scripts. Never use bare `git push`, push to `main`, +force-push, delete remote refs, push tags, or push arbitrary refspecs without explicit +approval. Do not create PRs, amend commits, delete branches, close comments, or remove +worktrees. From 0496f87f6360ccc1c7bfc94fe7661bf9a8dfc3ab Mon Sep 17 00:00:00 2001 From: Simon Flandergan Date: Fri, 26 Jun 2026 07:57:52 +0200 Subject: [PATCH 10/65] refactor: wire github-publish skill into OpenCode implement and finish agents --- core/opencode/agents/finish.md | 9 ++++++--- core/opencode/agents/implement.md | 11 +++++++---- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/core/opencode/agents/finish.md b/core/opencode/agents/finish.md index dff8c62..873581d 100644 --- a/core/opencode/agents/finish.md +++ b/core/opencode/agents/finish.md @@ -46,7 +46,9 @@ permission: "git push origin *:*": ask "git push origin --tags*": ask "git push origin tag *": ask - "git push origin $(git rev-parse --abbrev-ref HEAD)": allow + + "bash .agents/skills/github-publish/scripts/push-branch.sh*": allow + "bash .agents/skills/github-publish/scripts/open-pr.sh*": ask task: "*": deny "explore": allow @@ -55,6 +57,7 @@ permission: "workflow-verification": allow "feature-documentation": allow "grill-with-docs": allow + "github-publish": allow --- You are the finishing agent. @@ -74,6 +77,6 @@ Finish workflow: 3. Treat the feature doc as durable reference documentation, not a project-status report. 4. Reconcile the domain docs: if implementation or review changed the domain language, or introduced or invalidated a decision, update the relevant `docs/contexts//CONTEXT.md` glossary and add or supersede ADRs under `docs/adr/` before finalizing. This is offered reconciliation, not a full grilling session — use `grill-with-docs` only when a divergence genuinely needs interrogating. Keep `CONTEXT.md` a glossary only. 5. Remove both `plans/YYYY-MM-DD-feature-name/spec.md` and `plans/YYYY-MM-DD-feature-name/plan.md` after the feature doc is written. Use `git rm` for tracked plan files. Use plain `rm` only for untracked paths. -6. Commit the feature doc and cleanup, then push the current scoped branch with `git push origin $(git rev-parse --abbrev-ref HEAD)`. +6. Commit the feature doc and cleanup, then push the current scoped branch with `bash .agents/skills/github-publish/scripts/push-branch.sh`. Open a PR with `bash .agents/skills/github-publish/scripts/open-pr.sh` if needed. -Push automatically only with `git push origin $(git rev-parse --abbrev-ref HEAD)`. Never use bare `git push`, push to `main`, force-push, delete remote refs, push tags, or push arbitrary refspecs without explicit approval. Do not create PRs, amend commits, delete branches, close comments, or remove worktrees. +Push automatically only through the `github-publish` skill. Never hand-roll `git push`, push to `main`, force-push, delete remote refs, push tags, or push arbitrary refspecs without explicit approval. Do not create PRs manually, amend commits, delete branches, close comments, or remove worktrees. diff --git a/core/opencode/agents/implement.md b/core/opencode/agents/implement.md index 113a49d..3bbb6aa 100644 --- a/core/opencode/agents/implement.md +++ b/core/opencode/agents/implement.md @@ -53,7 +53,9 @@ permission: "git push origin *:*": ask "git push origin --tags*": ask "git push origin tag *": ask - "git push origin $(git rev-parse --abbrev-ref HEAD)": allow + + "bash .agents/skills/github-publish/scripts/push-branch.sh*": allow + "bash .agents/skills/github-publish/scripts/open-pr.sh*": ask "cat *": allow "diff *": allow @@ -86,6 +88,7 @@ permission: "*": deny "workflow-implementation": allow "workflow-verification": allow + "github-publish": allow --- You are the implementation controller. @@ -97,8 +100,8 @@ Execution rules: - Never implement on `main`; create or ask for a scoped branch if needed. - Prefer `git mv` for moves and renames of tracked paths. Use plain `mv` only for untracked paths or operations git cannot express cleanly. - Prefer `git rm` for removals of tracked paths. Use plain `rm` only for untracked paths. -- Always use `git push origin $(git rev-parse --abbrev-ref HEAD)` — never use bare `git push` to avoid accidentally pushing to `main`. -- Before creating a PR, check if one already exists for the current branch with `gh pr list --head $(git rev-parse --abbrev-ref HEAD)`. Only create a new PR if none exists. +- Publish through the `github-publish` skill — `bash .agents/skills/github-publish/scripts/push-branch.sh` to push, which refuses `main`. Never hand-roll `git push`: `git push origin $(...)` silently pushes `main` when the current branch is `main`. +- Open a pull request with `bash .agents/skills/github-publish/scripts/open-pr.sh` — it skips creation when a PR already exists for the current branch. - **Default behavior:** Execute the plan task-by-task by dispatching a fresh `@implement-task` worker for each task. This is the standard workflow — do not deviate unless the user explicitly requests inline implementation. - **Inline implementation:** Acceptable only when the user explicitly asks you to implement directly rather than delegating. When executing inline, apply the same task/review gates as delegated workers. - **Controller duties:** Your primary role is orchestration — dispatch tasks, package context for workers, review worker reports and diffs, enforce spec compliance and code quality review gates, and run verification before any completion claim. @@ -110,6 +113,6 @@ Execution rules: - Stop and ask for feedback only when the same task fails more than 3 times, the plan conflicts with code reality, or an architectural decision is required. - If a task is too complex or requires an architectural decision, report the blocker and recommend human escalation. - Run targeted verification while iterating and the required final verification before claiming completion. -- After final verification, commit all changes, push the branch with `git push origin $(git rev-parse --abbrev-ref HEAD)`, and create a GitHub pull request if one does not already exist. Check existence with `gh pr list --head $(git rev-parse --abbrev-ref HEAD)`. Never push to `main`. +- After final verification, commit all changes, push the branch with `bash .agents/skills/github-publish/scripts/push-branch.sh`, and open a GitHub pull request with `bash .agents/skills/github-publish/scripts/open-pr.sh` (it no-ops when a PR already exists). The push script refuses `main`. Use `workflow-verification` before any completion claim. Do not say work is complete, fixed, or passing unless the relevant commands have just run successfully. From 53e44c598117b1362fea405010723bd804467d4b Mon Sep 17 00:00:00 2001 From: Simon Flandergan Date: Fri, 26 Jun 2026 07:58:35 +0200 Subject: [PATCH 11/65] feat: add gitlab-publish permissions and glab CLI access to OpenCode agents --- core/opencode.json | 10 +++++++++- core/opencode/agents/finish.md | 4 ++++ core/opencode/agents/implement.md | 4 ++++ 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/core/opencode.json b/core/opencode.json index f37da5d..ea4a40e 100644 --- a/core/opencode.json +++ b/core/opencode.json @@ -37,7 +37,15 @@ "*": "ask", "git branch -d *": "deny", "git branch -D *": "deny", - "git worktree remove *": "deny" + "git worktree remove *": "deny", + "glab mr create *": "ask", + "glab mr list *": "allow", + "glab mr view *": "allow", + "glab mr diff *": "allow", + "glab issue create *": "ask", + "glab issue view *": "allow", + "glab issue list *": "allow", + "glab issue update *": "ask" }, "edit": { "*": "allow" diff --git a/core/opencode/agents/finish.md b/core/opencode/agents/finish.md index 873581d..6fd3984 100644 --- a/core/opencode/agents/finish.md +++ b/core/opencode/agents/finish.md @@ -49,6 +49,9 @@ permission: "bash .agents/skills/github-publish/scripts/push-branch.sh*": allow "bash .agents/skills/github-publish/scripts/open-pr.sh*": ask + + "bash .agents/skills/gitlab-publish/scripts/push-branch.sh*": allow + "bash .agents/skills/gitlab-publish/scripts/open-mr.sh*": ask task: "*": deny "explore": allow @@ -58,6 +61,7 @@ permission: "feature-documentation": allow "grill-with-docs": allow "github-publish": allow + "gitlab-publish": allow --- You are the finishing agent. diff --git a/core/opencode/agents/implement.md b/core/opencode/agents/implement.md index 3bbb6aa..b9c69f0 100644 --- a/core/opencode/agents/implement.md +++ b/core/opencode/agents/implement.md @@ -57,6 +57,9 @@ permission: "bash .agents/skills/github-publish/scripts/push-branch.sh*": allow "bash .agents/skills/github-publish/scripts/open-pr.sh*": ask + "bash .agents/skills/gitlab-publish/scripts/push-branch.sh*": allow + "bash .agents/skills/gitlab-publish/scripts/open-mr.sh*": ask + "cat *": allow "diff *": allow "find *": allow @@ -89,6 +92,7 @@ permission: "workflow-implementation": allow "workflow-verification": allow "github-publish": allow + "gitlab-publish": allow --- You are the implementation controller. From a864ee3108d05b2a37fa9f8c4ee7d425fa7b54c0 Mon Sep 17 00:00:00 2001 From: Simon Flandergan Date: Fri, 26 Jun 2026 08:00:57 +0200 Subject: [PATCH 12/65] refactor: update Claude planner for dual-harness /implement handoff --- core/claude/skills/planner/SKILL.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/claude/skills/planner/SKILL.md b/core/claude/skills/planner/SKILL.md index ad2849b..5665e8f 100644 --- a/core/claude/skills/planner/SKILL.md +++ b/core/claude/skills/planner/SKILL.md @@ -74,5 +74,5 @@ inlining them here. - Write the plan to `plans/YYYY-MM-DD-feature-name/plan.md`, next to the spec. Commit the spec/plan markdown only when the user asks for committed workflow artifacts. - After the plan is written, **stop**. Optionally suggest `/review-plan` before handoff. -- Implementation runs in **OpenCode** (`@implement` / `@implement-task`), not Claude Code. - Hand off to OpenCode for execution. +- Implementation can run in either harness: Claude Code (`/implement`) or OpenCode + (`@implement`). Pick one per branch. Suggest the user's preferred harness. From 875b360d48075aed68abb433d17623274ba933f1 Mon Sep 17 00:00:00 2001 From: Simon Flandergan Date: Fri, 26 Jun 2026 08:01:24 +0200 Subject: [PATCH 13/65] docs: update Claude README for /implement controller and GitLab skills --- core/claude/README.md | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/core/claude/README.md b/core/claude/README.md index e634d98..aa7823f 100644 --- a/core/claude/README.md +++ b/core/claude/README.md @@ -1,11 +1,9 @@ # Claude Code agent setup -Claude Code runs the **conversational** half of the agent pipeline. The -**implementation** half stays in OpenCode. There is deliberately -**no orchestrator**: the OpenCode hand-off ends the Claude Code session, and reviews are -triggered by hand, so the workflows are discrete, manually-invoked entry points. +Claude Code runs both the **conversational** and **implementation** halves of the +agent pipeline. OpenCode provides the same pipeline; pick one harness per branch. -## The six skills +## The seven skills Each is a real `SKILL.md` under `.claude/skills//`, marked `disable-model-invocation: true` — they never auto-trigger and stay out of the always-loaded @@ -14,15 +12,16 @@ skill index. You start them with `/name`. | Skill (`/name`) | OpenCode counterpart | Role | | --- | --- | --- | | `/brainstorm` | `@brainstorm` | Idea → approved `spec.md` (interactive; offers domain grilling) | -| `/bugfix` | `@bugfix` | Investigate bug → structured GitHub issue; does not fix | +| `/bugfix` | `@bugfix` | Investigate bug → structured issue; does not fix | | `/planner` | `@planner` | Spec → task-by-task `plan.md` (offers grilling only when new domain language or non-trivial decisions appear) | -| `/review-plan` | `@review-plan` | Review + finalize the OpenCode hand-off plan | -| `/review-code` | `@review-code` | Review a diff/PR → fix-plan hand-off doc | +| `/implement` | `@implement` | Execute plan task-by-task via `implement-task` workers, verify, commit | +| `/review-plan` | `@review-plan` | Review + finalize the hand-off plan | +| `/review-code` | `@review-code` | Review a diff/PR/MR → fix-plan hand-off doc | | `/finish` | `@finish` | Durable feature doc, light glossary/ADR reconciliation, cleanup | ## Design principle: delegate to shared authored skills -The six entry-point skills carry per-agent glue (workflow steps, stop/hand-off gates, +The seven entry-point skills carry per-agent glue (workflow steps, stop/hand-off gates, escalation rules) but delegate the heavy-lift methodology to authored skills under `.agents/skills/`. This avoids inlining duplicate copies of shared workflows. @@ -37,6 +36,9 @@ These shared skills are symlinked into `.claude/skills/` from `.agents/skills/`: - `workflow-verification` — used by `/finish` - `feature-documentation` — used by `/finish` - `github-pr-comments` — used by `/review-plan`, `/review-code` (+ OpenCode) +- `github-publish` — used by `/implement`, `/finish` (+ OpenCode) +- `gitlab-publish` — used by `/implement`, `/finish` (+ OpenCode; GitLab equivalent) +- `gitlab-mr-comments` — used by `/review-plan`, `/review-code` (+ OpenCode; GitLab equivalent of `github-pr-comments`) Remote skills (e.g. `context7-cli`, `next-best-practices`, `shadcn`, `zoom-out`, `write-a-skill`) are declared in `skills-lock.json` and installed via the @@ -65,11 +67,12 @@ All three skills load the shared `grill-with-docs` skill on demand. ## Skill inventory in `.claude/skills/` -- **Authored agent skills (real dirs):** `brainstorm`, `bugfix`, `planner`, `review-plan`, - `review-code`, `finish`. +- **Authored agent skills (real dirs):** `brainstorm`, `bugfix`, `planner`, `implement`, + `review-plan`, `review-code`, `finish`. - **Symlinked shared skills (auto-invocable):** `grill-with-docs`, `workflow-bug-analysis`, `workflow-brainstorming`, `workflow-planning`, - `workflow-verification`, `feature-documentation`, `github-pr-comments`. + `workflow-verification`, `feature-documentation`, `github-pr-comments`, + `github-publish`, `gitlab-publish`, `gitlab-mr-comments`. To add a newly-installed shared skill: `ln -s ../../.agents/skills/ .claude/skills/`. `.claude/skills/` is hand-managed. @@ -78,9 +81,11 @@ To add a newly-installed shared skill: `settings.json` encodes the project-wide permission union the skills need: edit allowed; read-only git and common Unix commands allowed; `git push` / `gh pr create` / -`rm` ask first; branch-delete, worktree-remove denied. +`glab mr create` / `rm` ask first; branch-delete, worktree-remove denied. Both GitHub +and GitLab publish/comment skill scripts (`github-publish`, `gitlab-publish`, +`github-pr-comments`, `gitlab-mr-comments`) are available. ## Usage -Type `/brainstorm`, `/bugfix`, `/planner`, `/review-plan`, `/review-code`, or `/finish` +Type `/brainstorm`, `/bugfix`, `/implement`, `/planner`, `/review-plan`, `/review-code`, or `/finish` (optionally with an argument, e.g. `/planner plans/2026-05-30-foo/spec.md`). From b928b3972f8964ab54b84f6ad1cf4b5534bf9e9b Mon Sep 17 00:00:00 2001 From: Simon Flandergan Date: Fri, 26 Jun 2026 08:02:19 +0200 Subject: [PATCH 14/65] feat: add gitlab skills and claude agents to installers, wrap publish-branch.sh --- scripts/copy.sh | 28 ++++++++++++++++++++++++++++ scripts/init.sh | 20 ++++++++++++++++++++ scripts/publish-branch.sh | 19 ++++--------------- 3 files changed, 52 insertions(+), 15 deletions(-) diff --git a/scripts/copy.sh b/scripts/copy.sh index f14bc66..5930ea5 100755 --- a/scripts/copy.sh +++ b/scripts/copy.sh @@ -406,6 +406,31 @@ for agent_file in "$STAGE/.opencode/agents/"*.md; do fi done +# --------------------------------------------------------------------------- +# 10b. .claude/agents/*.md handling +# --------------------------------------------------------------------------- +echo "" +for agent_file in "$STAGE/.claude/agents/"*.md; do + [[ -f "$agent_file" ]] || continue + fname="$(basename "$agent_file")" + dst="$TARGET/.claude/agents/$fname" + if [[ -e "$dst" ]]; then + if [[ "$SKILLS_MODE" == "override" ]]; then + mkdir -p "$TARGET/.claude/agents" + cp "$agent_file" "$dst" + COPIED+=(".claude/agents/$fname (overwritten)") + else + SKIPPED+=(".claude/agents/$fname (existing, skipped)") + fi + elif [[ "$SKILLS_MODE" == "skip" ]]; then + SKIPPED+=(".claude/agents/$fname (new, skipped: don't modify)") + else + mkdir -p "$TARGET/.claude/agents" + cp "$agent_file" "$dst" + COPIED+=(".claude/agents/$fname (new)") + fi +done + # --------------------------------------------------------------------------- # 11. .claude/skills/{brainstorm,bugfix,finish,planner,review-code,review-plan}/ # --------------------------------------------------------------------------- @@ -444,6 +469,9 @@ AUTHORED_SKILLS=( workflow-verification feature-documentation github-pr-comments + github-publish + gitlab-publish + gitlab-mr-comments ) for skill_name in "${AUTHORED_SKILLS[@]}"; do src="$STAGE/.agents/skills/$skill_name" diff --git a/scripts/init.sh b/scripts/init.sh index f0eec50..eda6b18 100755 --- a/scripts/init.sh +++ b/scripts/init.sh @@ -238,6 +238,9 @@ AUTHORED_SKILLS=( "workflow-verification" "feature-documentation" "github-pr-comments" + "github-publish" + "gitlab-publish" + "gitlab-mr-comments" ) mkdir -p "$TARGET/.claude/skills" @@ -258,6 +261,23 @@ for skill_name in "${AUTHORED_SKILLS[@]}"; do fi done +# --------------------------------------------------------------------------- +# 7b. .claude/agents/*.md handling +# --------------------------------------------------------------------------- +echo "" +for agent_file in "$STAGE/.claude/agents/"*.md; do + [[ -f "$agent_file" ]] || continue + fname="$(basename "$agent_file")" + dst="$TARGET/.claude/agents/$fname" + if [[ -e "$dst" ]]; then + echo " Skipping .claude/agents/$fname (already exists)" + else + mkdir -p "$TARGET/.claude/agents" + cp "$agent_file" "$dst" + echo " Installed .claude/agents/$fname" + fi +done + # --------------------------------------------------------------------------- # 8. Install remote skills from merged lock file # --------------------------------------------------------------------------- diff --git a/scripts/publish-branch.sh b/scripts/publish-branch.sh index f855ba3..0782a51 100755 --- a/scripts/publish-branch.sh +++ b/scripts/publish-branch.sh @@ -1,18 +1,7 @@ #!/usr/bin/env bash set -euo pipefail -branch="$(git rev-parse --abbrev-ref HEAD)" - -if [ "$branch" = "main" ]; then - printf 'Refusing to publish protected branch: %s\n' "$branch" >&2 - exit 1 -fi - -git push -u origin "$branch" - -pr_url="$(gh pr list --head "$branch" --json url --jq '.[0].url')" -if [ -n "$pr_url" ]; then - printf '%s\n' "$pr_url" -else - gh pr create --fill -fi +# Compatibility wrapper: this repo's self-maintenance agents still invoke +# scripts/publish-branch.sh. It delegates to the github-publish authored skill. +bash core/agents/skills/github-publish/scripts/push-branch.sh --set-upstream +bash core/agents/skills/github-publish/scripts/open-pr.sh --fill From 5798ceee018d736a6bd93829f8e297e7a670e134 Mon Sep 17 00:00:00 2001 From: Simon Flandergan Date: Fri, 26 Jun 2026 08:03:40 +0200 Subject: [PATCH 15/65] refactor: replace remaining raw push references with publish skills --- .../skills/workflow-implementation/SKILL.md | 2 +- core/claude/skills/planner/SKILL.md | 3 +-- core/claude/skills/review-plan/SKILL.md | 3 +-- core/opencode/agents/brainstorm.md | 16 +++------------- core/opencode/agents/planner.md | 16 +++------------- core/opencode/agents/review-plan.md | 6 +++--- 6 files changed, 12 insertions(+), 34 deletions(-) diff --git a/core/agents/skills/workflow-implementation/SKILL.md b/core/agents/skills/workflow-implementation/SKILL.md index 86df5db..f61ad6c 100644 --- a/core/agents/skills/workflow-implementation/SKILL.md +++ b/core/agents/skills/workflow-implementation/SKILL.md @@ -97,7 +97,7 @@ Implementer subagents report one of four statuses. Handle each appropriately: ## Boundaries - The controller agent owns dispatch, model choice, human handoff, push, PR, and finish decisions. -- After final verification, the controller commits all changes, pushes the branch with `git push origin $(git rev-parse --abbrev-ref HEAD)`, and creates a GitHub pull request if one does not already exist. Never push to `main`. +- After final verification, the controller commits all changes, pushes the branch with 'bash .agents/skills/github-publish/scripts/push-branch.sh', and opens a GitHub pull request with 'bash .agents/skills/github-publish/scripts/open-pr.sh' if one does not already exist. Never push to 'main'. - This skill only defines execution discipline and review gates. - Workers follow TDD instructions embedded in the approved plan for behavior changes. - Inline execution is acceptable only when the user explicitly requests it or subagent delegation is genuinely unavailable, but keep the same task/review gates. diff --git a/core/claude/skills/planner/SKILL.md b/core/claude/skills/planner/SKILL.md index 5665e8f..74bfec8 100644 --- a/core/claude/skills/planner/SKILL.md +++ b/core/claude/skills/planner/SKILL.md @@ -66,8 +66,7 @@ inlining them here. - Prefer relative workspace paths in commands and examples (e.g. `mkdir -p plans/2026-05-30-feature-name`). Avoid absolute workspace paths unless a tool requires them. -- Always use `git push origin $(git rev-parse --abbrev-ref HEAD)` — never use bare - `git push` to avoid accidentally pushing to `main`. +- Publish through the appropriate publish skill — 'bash .claude/skills/github-publish/scripts/push-branch.sh' (GitHub) or 'bash .claude/skills/gitlab-publish/scripts/push-branch.sh' (GitLab). Never hand-roll 'git push'. ## Stop conditions diff --git a/core/claude/skills/review-plan/SKILL.md b/core/claude/skills/review-plan/SKILL.md index 97897fc..53a2c7e 100644 --- a/core/claude/skills/review-plan/SKILL.md +++ b/core/claude/skills/review-plan/SKILL.md @@ -77,8 +77,7 @@ document. The gate is approval, not capability: config — only the `plans/**` artifacts. 4. Report the finalized plan path and confirm it is ready for OpenCode handoff. -When pushing approved spec/plan edits, always use -`git push origin $(git rev-parse --abbrev-ref HEAD)`. Never push to `main`. +Publish through the appropriate publish skill — 'bash .claude/skills/github-publish/scripts/push-branch.sh' (GitHub) or 'bash .claude/skills/gitlab-publish/scripts/push-branch.sh' (GitLab). Never hand-roll 'git push'. ## External / GitHub comments diff --git a/core/opencode/agents/brainstorm.md b/core/opencode/agents/brainstorm.md index fac9a20..1ac9f49 100644 --- a/core/opencode/agents/brainstorm.md +++ b/core/opencode/agents/brainstorm.md @@ -29,18 +29,8 @@ permission: "git branch -D *": deny "git worktree remove *": deny - "git push origin *": allow - "git push --force *": deny - "git push -f *": deny - "git push --force-with-lease *": ask - "git push origin --force *": deny - "git push origin -f *": deny - "git push origin --force-with-lease *": ask - "git push * --force *": deny - "git push * -f *": deny - "git push * --force-with-lease *": ask - "git push origin main*": deny - "git push origin +main*": deny + "bash .agents/skills/github-publish/scripts/push-branch.sh*": allow + "bash .agents/skills/gitlab-publish/scripts/push-branch.sh*": allow "ls *": allow "mkdir plans/*": allow @@ -94,6 +84,6 @@ Shell guidance: - Prefer relative workspace paths in shell commands and examples (e.g., `mkdir -p plans/2026-05-25-feature-name`). - Avoid absolute workspace paths in shell commands unless a tool explicitly requires them. -- Always use `git push origin $(git rev-parse --abbrev-ref HEAD)` — never use bare `git push` to avoid accidentally pushing to `main`. +- Publish through the appropriate publish skill — 'bash .agents/skills/github-publish/scripts/push-branch.sh' (GitHub) or 'bash .agents/skills/gitlab-publish/scripts/push-branch.sh' (GitLab). Never hand-roll 'git push'. When writing specs, include goal, non-goals, architecture, data flow, testing expectations, rollout or migration notes, and open questions if any remain. diff --git a/core/opencode/agents/planner.md b/core/opencode/agents/planner.md index c573601..cdf7e9e 100644 --- a/core/opencode/agents/planner.md +++ b/core/opencode/agents/planner.md @@ -26,18 +26,8 @@ permission: "git commit *": allow "git worktree remove *": deny - "git push origin *": allow - "git push --force *": deny - "git push -f *": deny - "git push --force-with-lease *": ask - "git push origin --force *": deny - "git push origin -f *": deny - "git push origin --force-with-lease *": ask - "git push * --force *": deny - "git push * -f *": deny - "git push * --force-with-lease *": ask - "git push origin main*": deny - "git push origin +main*": deny + "bash .agents/skills/github-publish/scripts/push-branch.sh*": allow + "bash .agents/skills/gitlab-publish/scripts/push-branch.sh*": allow "grep *": allow "ls *": allow @@ -88,7 +78,7 @@ Shell guidance: - Prefer relative workspace paths in shell commands and examples (e.g., `mkdir -p plans/2026-05-25-feature-name`). - Avoid absolute workspace paths in shell commands unless a tool explicitly requires them. -- Always use `git push origin $(git rev-parse --abbrev-ref HEAD)` — never use bare `git push` to avoid accidentally pushing to `main`. +- Publish through the appropriate publish skill — 'bash .agents/skills/github-publish/scripts/push-branch.sh' (GitHub) or 'bash .agents/skills/gitlab-publish/scripts/push-branch.sh' (GitLab). Never hand-roll 'git push'. Do not invoke brainstorming automatically. If requirements are unclear enough that planning would be speculative, ask the user whether to switch to `@brainstorm`. diff --git a/core/opencode/agents/review-plan.md b/core/opencode/agents/review-plan.md index a0c65c4..300d951 100644 --- a/core/opencode/agents/review-plan.md +++ b/core/opencode/agents/review-plan.md @@ -21,8 +21,8 @@ permission: "git add plans/*": allow "git commit *": allow - "git push *": allow - "git push origin main*": deny + "bash .agents/skills/github-publish/scripts/push-branch.sh*": allow + "bash .agents/skills/gitlab-publish/scripts/push-branch.sh*": allow "git worktree remove *": deny "bash .agents/skills/github-pr-comments/scripts/fetch-pr-comments.sh *": allow @@ -70,4 +70,4 @@ Use this standard review-plan workflow unless the user explicitly requests a dif When reviewing external or GitHub comments, use `github-pr-comments`. Always check open PR comments by default unless the user explicitly says not to. Verify each technical claim before recommending changes. Suggest changes only. Before posting any GitHub issue comment, PR conversation comment, or inline review reply, present the exact draft reply and wait for explicit user approval. Approval to edit `plans/**` does not authorize posting GitHub comments. -When pushing approved spec/plan edits, always use `git push origin $(git rev-parse --abbrev-ref HEAD)`. Never push to `main`. +Publish through the appropriate publish skill — 'bash .agents/skills/github-publish/scripts/push-branch.sh' (GitHub) or 'bash .agents/skills/gitlab-publish/scripts/push-branch.sh' (GitLab). Never hand-roll 'git push'. From fb7cbfc78bd3c36031fca3972b7b93828fe99087 Mon Sep 17 00:00:00 2001 From: Simon Flandergan Date: Fri, 26 Jun 2026 08:03:40 +0200 Subject: [PATCH 16/65] docs: update README for dual-harness /implement and GitLab skills --- README.md | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 88bbe28..3a6f21c 100644 --- a/README.md +++ b/README.md @@ -95,13 +95,13 @@ Under `.opencode/agents/`: Under `.claude/skills/` (all marked `disable-model-invocation: true`): -`brainstorm`, `bugfix`, `finish`, `planner`, `review-code`, `review-plan` +`brainstorm`, `bugfix`, `implement`, `finish`, `planner`, `review-code`, `review-plan` ### Authored Reusable Skills Under `.agents/skills/`: -`grill-with-docs`, `workflow-bug-analysis`, `workflow-brainstorming`, `workflow-planning`, `workflow-implementation`, `workflow-verification`, `feature-documentation`, `github-pr-comments` +`grill-with-docs`, `workflow-bug-analysis`, `workflow-brainstorming`, `workflow-planning`, `workflow-implementation`, `workflow-verification`, `feature-documentation`, `github-publish`, `github-pr-comments`, `gitlab-publish`, `gitlab-mr-comments` ### DDD Docs @@ -126,7 +126,7 @@ Under `docs/agents/` — per-agent loading contracts. See the individual files f ## Claude Symlink Model -The 6 workflow entry skills are real directories. The 7 authored skills are symlinked into `.claude/skills/` from `.agents/skills/`: +The 6 workflow entry skills are real directories. The 11 authored skills are symlinked into `.claude/skills/` from `.agents/skills/`: | Skill | Symlink Target | |---|---| @@ -137,11 +137,12 @@ The 6 workflow entry skills are real directories. The 7 authored skills are syml | `workflow-verification` | `../../.agents/skills/workflow-verification` | | `feature-documentation` | `../../.agents/skills/feature-documentation` | | `github-pr-comments` | `../../.agents/skills/github-pr-comments` | +| `github-publish` | `../../.agents/skills/github-publish` | +| `gitlab-publish` | `../../.agents/skills/gitlab-publish` | +| `gitlab-mr-comments` | `../../.agents/skills/gitlab-mr-comments` | Each symlinked skill has `user-invocable: false` in its `SKILL.md` frontmatter so it stays hidden from Claude Code's user-facing skill list. -> **Note:** `workflow-implementation` is **not** symlinked into Claude — it is reserved for OpenCode's `@implement` / `@implement-task` flow. - ## Recommended Human-in-the-Loop Workflow ![Workflow diagram showing the human-in-the-loop cycle: ideation and planning (steps 1–6) followed by an implementation cycle (steps 7–11). Blue icons represent human input; robot icons represent LLM agents; purple steps are think-and-plan; orange steps are reviews; green is implementation; dark is finish.](workflow.PNG) @@ -163,7 +164,7 @@ The diagram above maps the full cycle from brainstorming a feature through to sh | # | Step | Invocation | |---|---|---| -| 7 | **Implement task-by-task** — dispatch one worker per plan task, verify, and commit. | OpenCode `@implement` (controller) which spawns `@implement-task` workers. | +| 7 | **Implement task-by-task** — dispatch one worker per plan task, verify, and commit. | Claude `/implement` or OpenCode `@implement` (controller) which spawns implement-task workers. Pick one harness per branch. | | 8 | **Human comments code** — review the diff and leave inline comments or GitHub review notes. | Human checkpoint (no agent invocation). | | 9 | **Review code** — analyze review feedback and determine required changes. | OpenCode `@review-code` or Claude `/review-code`. | | 10 | **Review / Remark plan** — if code review surfaces scope changes, update the plan and loop back to step 7. Repeat until the plan is sound and complete. | OpenCode `@planner` or Claude `/planner` to revise; then re-enter implementation at step 7. | From 4c7111df62b925ff358ecbe9e73c0b800fe4ac2b Mon Sep 17 00:00:00 2001 From: Simon Flandergan Date: Sat, 27 Jun 2026 09:02:46 +0200 Subject: [PATCH 17/65] fix(copy.sh): include Claude /implement skill in installed assets --- scripts/copy.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/copy.sh b/scripts/copy.sh index 5930ea5..9f07bd0 100755 --- a/scripts/copy.sh +++ b/scripts/copy.sh @@ -432,10 +432,10 @@ for agent_file in "$STAGE/.claude/agents/"*.md; do done # --------------------------------------------------------------------------- -# 11. .claude/skills/{brainstorm,bugfix,finish,planner,review-code,review-plan}/ +# 11. .claude/skills/{brainstorm,bugfix,finish,implement,planner,review-code,review-plan}/ # --------------------------------------------------------------------------- echo "" -CLAUDE_SKILLS=(brainstorm bugfix finish planner review-code review-plan) +CLAUDE_SKILLS=(brainstorm bugfix finish implement planner review-code review-plan) for skill_name in "${CLAUDE_SKILLS[@]}"; do src="$STAGE/.claude/skills/$skill_name" dst="$TARGET/.claude/skills/$skill_name" From ed2aa434f29dd95b3476b2379cad0649ac35a6e7 Mon Sep 17 00:00:00 2001 From: Simon Flandergan Date: Sat, 27 Jun 2026 09:03:53 +0200 Subject: [PATCH 18/65] feat(review): wire gitlab-mr-comments into review agents --- core/claude/skills/review-code/SKILL.md | 2 +- core/claude/skills/review-plan/SKILL.md | 2 +- core/docs/agents/review-code.md | 2 ++ core/docs/agents/review-plan.md | 2 ++ core/opencode/agents/review-code.md | 4 ++++ core/opencode/agents/review-plan.md | 4 ++++ 6 files changed, 14 insertions(+), 2 deletions(-) diff --git a/core/claude/skills/review-code/SKILL.md b/core/claude/skills/review-code/SKILL.md index ac464af..9c69be3 100644 --- a/core/claude/skills/review-code/SKILL.md +++ b/core/claude/skills/review-code/SKILL.md @@ -15,7 +15,7 @@ Scope (if provided): $ARGUMENTS Read `docs/agents/review-code.md` before reviewing and follow its document list exactly. -Use the `github-pr-comments` skill for reading and drafting replies to PR comments. +Use `github-pr-comments` for GitHub remotes and `gitlab-mr-comments` for non-GitHub (commonly self-hosted GitLab) remotes when reading and drafting replies to PR/MR comments. ## Review priorities diff --git a/core/claude/skills/review-plan/SKILL.md b/core/claude/skills/review-plan/SKILL.md index 53a2c7e..228fd2d 100644 --- a/core/claude/skills/review-plan/SKILL.md +++ b/core/claude/skills/review-plan/SKILL.md @@ -16,7 +16,7 @@ Spec or plan to review (if provided): $ARGUMENTS Read `docs/agents/review-plan.md` before every review and follow its document list exactly. -Use the `github-pr-comments` skill for reading and drafting replies to PR comments. +Use `github-pr-comments` for GitHub remotes and `gitlab-mr-comments` for non-GitHub (commonly self-hosted GitLab) remotes when reading and drafting replies to PR/MR comments. ## Review goals diff --git a/core/docs/agents/review-code.md b/core/docs/agents/review-code.md index c05a92d..e242316 100644 --- a/core/docs/agents/review-code.md +++ b/core/docs/agents/review-code.md @@ -11,6 +11,8 @@ - `CONTEXT-MAP.md` and relevant `docs/contexts//CONTEXT.md` glossaries to check domain language; `docs/adr/` for documented decisions - Area docs listed below when the diff touches that area - `docs/ARCHITECTURE.md` when the change crosses package or ownership boundaries +- `github-pr-comments` skill for reading and drafting replies to GitHub PR feedback +- `gitlab-mr-comments` skill for reading and drafting replies to GitLab MR feedback ## Area Docs diff --git a/core/docs/agents/review-plan.md b/core/docs/agents/review-plan.md index 3199135..363c522 100644 --- a/core/docs/agents/review-plan.md +++ b/core/docs/agents/review-plan.md @@ -8,6 +8,8 @@ - `docs/TESTING.md` - `CONTEXT-MAP.md` and relevant `docs/contexts//CONTEXT.md` glossaries to check domain language; `docs/adr/` for documented decisions - Area docs listed below when the reviewed work touches that area +- `github-pr-comments` skill for reading and drafting replies to GitHub PR feedback +- `gitlab-mr-comments` skill for reading and drafting replies to GitLab MR feedback ## Area Docs diff --git a/core/opencode/agents/review-code.md b/core/opencode/agents/review-code.md index 1c07234..b3bde71 100644 --- a/core/opencode/agents/review-code.md +++ b/core/opencode/agents/review-code.md @@ -30,6 +30,9 @@ permission: 'bash ".agents/skills/github-pr-comments/scripts/fetch-pr-comments.sh" *': allow "bash .agents/skills/github-pr-comments/scripts/reply-to-pr-comment.sh *": ask 'bash ".agents/skills/github-pr-comments/scripts/reply-to-pr-comment.sh" *': ask + + "bash .agents/skills/gitlab-mr-comments/scripts/fetch-mr-comments.sh*": allow + "bash .agents/skills/gitlab-mr-comments/scripts/reply-to-mr-comment.sh*": ask task: "*": deny "explore": allow @@ -37,6 +40,7 @@ permission: skill: "*": deny "github-pr-comments": allow + "gitlab-mr-comments": allow --- You are the code review agent. diff --git a/core/opencode/agents/review-plan.md b/core/opencode/agents/review-plan.md index 300d951..f5a2958 100644 --- a/core/opencode/agents/review-plan.md +++ b/core/opencode/agents/review-plan.md @@ -29,12 +29,16 @@ permission: 'bash ".agents/skills/github-pr-comments/scripts/fetch-pr-comments.sh" *': allow "bash .agents/skills/github-pr-comments/scripts/reply-to-pr-comment.sh *": allow 'bash ".agents/skills/github-pr-comments/scripts/reply-to-pr-comment.sh" *': allow + + "bash .agents/skills/gitlab-mr-comments/scripts/fetch-mr-comments.sh*": allow + "bash .agents/skills/gitlab-mr-comments/scripts/reply-to-mr-comment.sh*": ask task: "*": deny "explore": allow skill: "*": deny "github-pr-comments": allow + "gitlab-mr-comments": allow --- You are the spec and plan review agent. From 8e01f6261e92ecbf96de8a8193aaaefafef8ef31 Mon Sep 17 00:00:00 2001 From: Simon Flandergan Date: Sat, 27 Jun 2026 09:04:34 +0200 Subject: [PATCH 19/65] refactor(opencode): use host-based publish skill selection in implement and finish --- core/opencode/agents/finish.md | 6 ++++-- core/opencode/agents/implement.md | 12 +++++++++--- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/core/opencode/agents/finish.md b/core/opencode/agents/finish.md index 6fd3984..d724e7a 100644 --- a/core/opencode/agents/finish.md +++ b/core/opencode/agents/finish.md @@ -81,6 +81,8 @@ Finish workflow: 3. Treat the feature doc as durable reference documentation, not a project-status report. 4. Reconcile the domain docs: if implementation or review changed the domain language, or introduced or invalidated a decision, update the relevant `docs/contexts//CONTEXT.md` glossary and add or supersede ADRs under `docs/adr/` before finalizing. This is offered reconciliation, not a full grilling session — use `grill-with-docs` only when a divergence genuinely needs interrogating. Keep `CONTEXT.md` a glossary only. 5. Remove both `plans/YYYY-MM-DD-feature-name/spec.md` and `plans/YYYY-MM-DD-feature-name/plan.md` after the feature doc is written. Use `git rm` for tracked plan files. Use plain `rm` only for untracked paths. -6. Commit the feature doc and cleanup, then push the current scoped branch with `bash .agents/skills/github-publish/scripts/push-branch.sh`. Open a PR with `bash .agents/skills/github-publish/scripts/open-pr.sh` if needed. +6. Commit the feature doc and cleanup, then publish. Detect host from `git remote get-url origin`: + - GitHub (contains `github.com` or starts with `git@github.com:`) → push with `bash .agents/skills/github-publish/scripts/push-branch.sh`, open a PR with `bash .agents/skills/github-publish/scripts/open-pr.sh` if needed + - Otherwise → push with `bash .agents/skills/gitlab-publish/scripts/push-branch.sh`, open an MR with `bash .agents/skills/gitlab-publish/scripts/open-mr.sh` if needed -Push automatically only through the `github-publish` skill. Never hand-roll `git push`, push to `main`, force-push, delete remote refs, push tags, or push arbitrary refspecs without explicit approval. Do not create PRs manually, amend commits, delete branches, close comments, or remove worktrees. +Push automatically only through the host-appropriate publish skill. Never hand-roll `git push`, push to `main`, force-push, delete remote refs, push tags, or push arbitrary refspecs without explicit approval. Do not create PRs/MRs manually, amend commits, delete branches, close comments, or remove worktrees. diff --git a/core/opencode/agents/implement.md b/core/opencode/agents/implement.md index b9c69f0..540a407 100644 --- a/core/opencode/agents/implement.md +++ b/core/opencode/agents/implement.md @@ -104,8 +104,11 @@ Execution rules: - Never implement on `main`; create or ask for a scoped branch if needed. - Prefer `git mv` for moves and renames of tracked paths. Use plain `mv` only for untracked paths or operations git cannot express cleanly. - Prefer `git rm` for removals of tracked paths. Use plain `rm` only for untracked paths. -- Publish through the `github-publish` skill — `bash .agents/skills/github-publish/scripts/push-branch.sh` to push, which refuses `main`. Never hand-roll `git push`: `git push origin $(...)` silently pushes `main` when the current branch is `main`. -- Open a pull request with `bash .agents/skills/github-publish/scripts/open-pr.sh` — it skips creation when a PR already exists for the current branch. +- Publish through the host-appropriate skill. Detect host from `git remote get-url origin`: + - GitHub (contains `github.com` or starts with `git@github.com:`) → use `github-publish` + - Otherwise → use `gitlab-publish` + Run `push-branch.sh` to push, which refuses `main`. Never hand-roll `git push`: `git push origin $(...)` silently pushes `main` when the current branch is `main`. +- Open a pull/merge request with `open-pr.sh` (GitHub) or `open-mr.sh` (GitLab) — both skip creation when one already exists for the current branch. - **Default behavior:** Execute the plan task-by-task by dispatching a fresh `@implement-task` worker for each task. This is the standard workflow — do not deviate unless the user explicitly requests inline implementation. - **Inline implementation:** Acceptable only when the user explicitly asks you to implement directly rather than delegating. When executing inline, apply the same task/review gates as delegated workers. - **Controller duties:** Your primary role is orchestration — dispatch tasks, package context for workers, review worker reports and diffs, enforce spec compliance and code quality review gates, and run verification before any completion claim. @@ -117,6 +120,9 @@ Execution rules: - Stop and ask for feedback only when the same task fails more than 3 times, the plan conflicts with code reality, or an architectural decision is required. - If a task is too complex or requires an architectural decision, report the blocker and recommend human escalation. - Run targeted verification while iterating and the required final verification before claiming completion. -- After final verification, commit all changes, push the branch with `bash .agents/skills/github-publish/scripts/push-branch.sh`, and open a GitHub pull request with `bash .agents/skills/github-publish/scripts/open-pr.sh` (it no-ops when a PR already exists). The push script refuses `main`. +- After final verification, commit all changes and publish. Detect host from `git remote get-url origin`: + - GitHub (contains `github.com` or starts with `git@github.com:`) → push with `bash .agents/skills/github-publish/scripts/push-branch.sh`, open a PR with `bash .agents/skills/github-publish/scripts/open-pr.sh` (no-ops when a PR already exists) + - Otherwise → push with `bash .agents/skills/gitlab-publish/scripts/push-branch.sh`, open an MR with `bash .agents/skills/gitlab-publish/scripts/open-mr.sh` (no-ops when an MR already exists) + The push script refuses `main`. Use `workflow-verification` before any completion claim. Do not say work is complete, fixed, or passing unless the relevant commands have just run successfully. From 06fc8d602e352e79c14ec38b78d83aed2a4c2aca Mon Sep 17 00:00:00 2001 From: Simon Flandergan Date: Sat, 27 Jun 2026 09:05:07 +0200 Subject: [PATCH 20/65] docs(readme): remove hard-coded skill counts --- README.md | 2 +- core/claude/README.md | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 3a6f21c..8185833 100644 --- a/README.md +++ b/README.md @@ -126,7 +126,7 @@ Under `docs/agents/` — per-agent loading contracts. See the individual files f ## Claude Symlink Model -The 6 workflow entry skills are real directories. The 11 authored skills are symlinked into `.claude/skills/` from `.agents/skills/`: +The workflow entry skills are real directories. The authored skills are symlinked into `.claude/skills/` from `.agents/skills/`: | Skill | Symlink Target | |---|---| diff --git a/core/claude/README.md b/core/claude/README.md index aa7823f..f687cbc 100644 --- a/core/claude/README.md +++ b/core/claude/README.md @@ -3,7 +3,7 @@ Claude Code runs both the **conversational** and **implementation** halves of the agent pipeline. OpenCode provides the same pipeline; pick one harness per branch. -## The seven skills +## The skills Each is a real `SKILL.md` under `.claude/skills//`, marked `disable-model-invocation: true` — they never auto-trigger and stay out of the always-loaded @@ -21,7 +21,7 @@ skill index. You start them with `/name`. ## Design principle: delegate to shared authored skills -The seven entry-point skills carry per-agent glue (workflow steps, stop/hand-off gates, +The entry-point skills carry per-agent glue (workflow steps, stop/hand-off gates, escalation rules) but delegate the heavy-lift methodology to authored skills under `.agents/skills/`. This avoids inlining duplicate copies of shared workflows. From befa7c63d2604cfdd5619278f6dc5d5a62eb28bc Mon Sep 17 00:00:00 2001 From: Simon Flandergan Date: Sat, 27 Jun 2026 09:07:22 +0200 Subject: [PATCH 21/65] docs: add host-based publish and comment skill selection guidance --- core/agents/skills/workflow-implementation/SKILL.md | 5 ++++- core/claude/skills/brainstorm/SKILL.md | 5 ++++- core/claude/skills/finish/SKILL.md | 7 ++++--- core/claude/skills/implement/SKILL.md | 7 ++++--- core/claude/skills/planner/SKILL.md | 5 ++++- core/claude/skills/review-plan/SKILL.md | 5 ++++- core/opencode/agents/brainstorm.md | 5 ++++- core/opencode/agents/planner.md | 5 ++++- core/opencode/agents/review-code.md | 2 ++ core/opencode/agents/review-plan.md | 7 ++++++- 10 files changed, 40 insertions(+), 13 deletions(-) diff --git a/core/agents/skills/workflow-implementation/SKILL.md b/core/agents/skills/workflow-implementation/SKILL.md index f61ad6c..6e296fa 100644 --- a/core/agents/skills/workflow-implementation/SKILL.md +++ b/core/agents/skills/workflow-implementation/SKILL.md @@ -97,7 +97,10 @@ Implementer subagents report one of four statuses. Handle each appropriately: ## Boundaries - The controller agent owns dispatch, model choice, human handoff, push, PR, and finish decisions. -- After final verification, the controller commits all changes, pushes the branch with 'bash .agents/skills/github-publish/scripts/push-branch.sh', and opens a GitHub pull request with 'bash .agents/skills/github-publish/scripts/open-pr.sh' if one does not already exist. Never push to 'main'. +- After final verification, the controller commits all changes, then pushes and opens a PR/MR using the host-appropriate publish skill. Detect host from `git remote get-url origin`: + - GitHub (contains `github.com` or starts with `git@github.com:`) → push with `bash .agents/skills/github-publish/scripts/push-branch.sh`, open a PR with `bash .agents/skills/github-publish/scripts/open-pr.sh` if one does not already exist + - Otherwise → push with `bash .agents/skills/gitlab-publish/scripts/push-branch.sh`, open an MR with `bash .agents/skills/gitlab-publish/scripts/open-mr.sh` if one does not already exist + Never push to 'main'. - This skill only defines execution discipline and review gates. - Workers follow TDD instructions embedded in the approved plan for behavior changes. - Inline execution is acceptable only when the user explicitly requests it or subagent delegation is genuinely unavailable, but keep the same task/review gates. diff --git a/core/claude/skills/brainstorm/SKILL.md b/core/claude/skills/brainstorm/SKILL.md index 806d640..956fed5 100644 --- a/core/claude/skills/brainstorm/SKILL.md +++ b/core/claude/skills/brainstorm/SKILL.md @@ -31,7 +31,10 @@ Use `grill-with-docs` when the brainstorm needs domain grilling. - Prefer relative workspace paths in commands and examples (e.g. `mkdir -p plans/2026-05-30-feature-name`). Avoid absolute workspace paths unless a tool requires them. -- Publish through the appropriate publish skill — `bash .claude/skills/github-publish/scripts/push-branch.sh` (GitHub) or `bash .claude/skills/gitlab-publish/scripts/push-branch.sh` (GitLab). Never hand-roll `git push`. +- Publish through the host-appropriate publish skill. Detect host from `git remote get-url origin`: + - GitHub (contains `github.com` or starts with `git@github.com:`) → `bash .claude/skills/github-publish/scripts/push-branch.sh` + - Otherwise → `bash .claude/skills/gitlab-publish/scripts/push-branch.sh` — GitLab is commonly self-hosted + Never hand-roll `git push`. ## Stop conditions diff --git a/core/claude/skills/finish/SKILL.md b/core/claude/skills/finish/SKILL.md index 47a1697..9af210e 100644 --- a/core/claude/skills/finish/SKILL.md +++ b/core/claude/skills/finish/SKILL.md @@ -47,9 +47,10 @@ explore subagent with a focused question. feature doc is written and the user approves cleanup. Use `git rm` for tracked files; use plain `rm` only for untracked paths. 5. **Commit and push.** Commit the feature doc and cleanup when the user requests it, - then push using the appropriate publish skill: - - GitHub: `bash .claude/skills/github-publish/scripts/push-branch.sh` - - GitLab: `bash .claude/skills/gitlab-publish/scripts/push-branch.sh` + then push using the host-appropriate publish skill. Detect host from + `git remote get-url origin`: + - GitHub (contains `github.com` or starts with `git@github.com:`) → `bash .claude/skills/github-publish/scripts/push-branch.sh` + - Otherwise → `bash .claude/skills/gitlab-publish/scripts/push-branch.sh` — GitLab is commonly self-hosted ## Push boundaries diff --git a/core/claude/skills/implement/SKILL.md b/core/claude/skills/implement/SKILL.md index 61f109b..f98d44d 100644 --- a/core/claude/skills/implement/SKILL.md +++ b/core/claude/skills/implement/SKILL.md @@ -46,8 +46,9 @@ Run targeted verification while iterating and the required final verification be ## Finishing -After final verification, commit all changes and push the branch using the publish skill: -- GitHub: `bash .claude/skills/github-publish/scripts/push-branch.sh` then `bash .claude/skills/github-publish/scripts/open-pr.sh` -- GitLab: `bash .claude/skills/gitlab-publish/scripts/push-branch.sh` then `bash .claude/skills/gitlab-publish/scripts/open-mr.sh` +After final verification, commit all changes and push the branch using the host-appropriate publish skill. +Detect host from `git remote get-url origin`: +- GitHub (contains `github.com` or starts with `git@github.com:`) → `bash .claude/skills/github-publish/scripts/push-branch.sh` then `bash .claude/skills/github-publish/scripts/open-pr.sh` +- Otherwise → `bash .claude/skills/gitlab-publish/scripts/push-branch.sh` then `bash .claude/skills/gitlab-publish/scripts/open-mr.sh` — GitLab is commonly self-hosted The publish scripts refuse `main`/`master` and skip creation when a PR/MR already exists for the branch. diff --git a/core/claude/skills/planner/SKILL.md b/core/claude/skills/planner/SKILL.md index 74bfec8..3398221 100644 --- a/core/claude/skills/planner/SKILL.md +++ b/core/claude/skills/planner/SKILL.md @@ -66,7 +66,10 @@ inlining them here. - Prefer relative workspace paths in commands and examples (e.g. `mkdir -p plans/2026-05-30-feature-name`). Avoid absolute workspace paths unless a tool requires them. -- Publish through the appropriate publish skill — 'bash .claude/skills/github-publish/scripts/push-branch.sh' (GitHub) or 'bash .claude/skills/gitlab-publish/scripts/push-branch.sh' (GitLab). Never hand-roll 'git push'. +- Publish through the host-appropriate publish skill. Detect host from `git remote get-url origin`: + - GitHub (contains `github.com` or starts with `git@github.com:`) → `bash .claude/skills/github-publish/scripts/push-branch.sh` + - Otherwise → `bash .claude/skills/gitlab-publish/scripts/push-branch.sh` — GitLab is commonly self-hosted + Never hand-roll `git push`. ## Stop conditions diff --git a/core/claude/skills/review-plan/SKILL.md b/core/claude/skills/review-plan/SKILL.md index 228fd2d..671d81f 100644 --- a/core/claude/skills/review-plan/SKILL.md +++ b/core/claude/skills/review-plan/SKILL.md @@ -77,7 +77,10 @@ document. The gate is approval, not capability: config — only the `plans/**` artifacts. 4. Report the finalized plan path and confirm it is ready for OpenCode handoff. -Publish through the appropriate publish skill — 'bash .claude/skills/github-publish/scripts/push-branch.sh' (GitHub) or 'bash .claude/skills/gitlab-publish/scripts/push-branch.sh' (GitLab). Never hand-roll 'git push'. +Publish through the host-appropriate publish skill. Detect host from `git remote get-url origin`: +- GitHub (contains `github.com` or starts with `git@github.com:`) → `bash .claude/skills/github-publish/scripts/push-branch.sh` +- Otherwise → `bash .claude/skills/gitlab-publish/scripts/push-branch.sh` — GitLab is commonly self-hosted +Never hand-roll `git push`. ## External / GitHub comments diff --git a/core/opencode/agents/brainstorm.md b/core/opencode/agents/brainstorm.md index 1ac9f49..8fb5901 100644 --- a/core/opencode/agents/brainstorm.md +++ b/core/opencode/agents/brainstorm.md @@ -84,6 +84,9 @@ Shell guidance: - Prefer relative workspace paths in shell commands and examples (e.g., `mkdir -p plans/2026-05-25-feature-name`). - Avoid absolute workspace paths in shell commands unless a tool explicitly requires them. -- Publish through the appropriate publish skill — 'bash .agents/skills/github-publish/scripts/push-branch.sh' (GitHub) or 'bash .agents/skills/gitlab-publish/scripts/push-branch.sh' (GitLab). Never hand-roll 'git push'. +- Publish through the host-appropriate publish skill. Detect host from `git remote get-url origin`: + - GitHub (contains `github.com` or starts with `git@github.com:`) → `bash .agents/skills/github-publish/scripts/push-branch.sh` + - Otherwise → `bash .agents/skills/gitlab-publish/scripts/push-branch.sh` — GitLab is commonly self-hosted + Never hand-roll `git push`. When writing specs, include goal, non-goals, architecture, data flow, testing expectations, rollout or migration notes, and open questions if any remain. diff --git a/core/opencode/agents/planner.md b/core/opencode/agents/planner.md index cdf7e9e..43b8624 100644 --- a/core/opencode/agents/planner.md +++ b/core/opencode/agents/planner.md @@ -78,7 +78,10 @@ Shell guidance: - Prefer relative workspace paths in shell commands and examples (e.g., `mkdir -p plans/2026-05-25-feature-name`). - Avoid absolute workspace paths in shell commands unless a tool explicitly requires them. -- Publish through the appropriate publish skill — 'bash .agents/skills/github-publish/scripts/push-branch.sh' (GitHub) or 'bash .agents/skills/gitlab-publish/scripts/push-branch.sh' (GitLab). Never hand-roll 'git push'. +- Publish through the host-appropriate publish skill. Detect host from `git remote get-url origin`: + - GitHub (contains `github.com` or starts with `git@github.com:`) → `bash .agents/skills/github-publish/scripts/push-branch.sh` + - Otherwise → `bash .agents/skills/gitlab-publish/scripts/push-branch.sh` — GitLab is commonly self-hosted + Never hand-roll `git push`. Do not invoke brainstorming automatically. If requirements are unclear enough that planning would be speculative, ask the user whether to switch to `@brainstorm`. diff --git a/core/opencode/agents/review-code.md b/core/opencode/agents/review-code.md index b3bde71..4b8fed1 100644 --- a/core/opencode/agents/review-code.md +++ b/core/opencode/agents/review-code.md @@ -47,6 +47,8 @@ You are the code review agent. Load `docs/agents/review-code.md` before reviewing and follow its document list exactly. +Use `github-pr-comments` for GitHub remotes and `gitlab-mr-comments` for non-GitHub (commonly self-hosted GitLab) remotes when reading and drafting replies to PR/MR comments. + Review priorities: - Bugs, behavior regressions, data corruption, security, race conditions, and broken error handling. diff --git a/core/opencode/agents/review-plan.md b/core/opencode/agents/review-plan.md index f5a2958..74b4cee 100644 --- a/core/opencode/agents/review-plan.md +++ b/core/opencode/agents/review-plan.md @@ -45,6 +45,8 @@ You are the spec and plan review agent. Load `docs/agents/review-plan.md` before every review and follow its document list exactly. +Use `github-pr-comments` for GitHub remotes and `gitlab-mr-comments` for non-GitHub (commonly self-hosted GitLab) remotes when reading and drafting replies to PR/MR comments. + Review goals: - For specs: check clarity, completeness, scope, non-goals, architecture fit, data boundaries, missing edge cases, and testability. @@ -74,4 +76,7 @@ Use this standard review-plan workflow unless the user explicitly requests a dif When reviewing external or GitHub comments, use `github-pr-comments`. Always check open PR comments by default unless the user explicitly says not to. Verify each technical claim before recommending changes. Suggest changes only. Before posting any GitHub issue comment, PR conversation comment, or inline review reply, present the exact draft reply and wait for explicit user approval. Approval to edit `plans/**` does not authorize posting GitHub comments. -Publish through the appropriate publish skill — 'bash .agents/skills/github-publish/scripts/push-branch.sh' (GitHub) or 'bash .agents/skills/gitlab-publish/scripts/push-branch.sh' (GitLab). Never hand-roll 'git push'. +Publish through the host-appropriate publish skill. Detect host from `git remote get-url origin`: +- GitHub (contains `github.com` or starts with `git@github.com:`) → `bash .agents/skills/github-publish/scripts/push-branch.sh` +- Otherwise → `bash .agents/skills/gitlab-publish/scripts/push-branch.sh` — GitLab is commonly self-hosted +Never hand-roll `git push`. From d454e1e4dc86923d77a5e06596b40a130116eb8f Mon Sep 17 00:00:00 2001 From: Simon Flandergan Date: Sun, 28 Jun 2026 10:57:41 +0200 Subject: [PATCH 22/65] docs: update provider boundary plan --- plans/2026-06-27-provider-boundaries/plan.md | 479 +++++++++++++++++++ 1 file changed, 479 insertions(+) create mode 100644 plans/2026-06-27-provider-boundaries/plan.md diff --git a/plans/2026-06-27-provider-boundaries/plan.md b/plans/2026-06-27-provider-boundaries/plan.md new file mode 100644 index 0000000..20685c0 --- /dev/null +++ b/plans/2026-06-27-provider-boundaries/plan.md @@ -0,0 +1,479 @@ +# Plan: Fix provider-internal leakage from workflow skills + +## Objective + +Generic workflow skills and agents must stop exposing GitHub/GitLab implementation details. Workflow-facing files should describe repository operations in host-neutral terms and call stable neutral skills. Provider-specific mechanics should remain isolated behind integration/provider skills. + +The recurring leakage to remove includes: + +- `gh` / `glab` +- `github-publish` / `gitlab-publish` +- `github-pr-comments` / `gitlab-mr-comments` +- `open-pr.sh` / `open-mr.sh` +- `fetch-pr-comments.sh` / `fetch-mr-comments.sh` +- repeated `git remote get-url origin` host-detection snippets +- GitHub-only “PR comments” wording in generic workflows +- Claude workflow skills naming OpenCode internals such as `@implement`, `@implement-task`, or “OpenCode handoff” + +## Target architecture + +Workflow-facing files should use these neutral authored skills: + +- `git-publish` — safe branch push for any git remote. +- `change-request-publish` — open a change request after detecting the host. +- `change-request-comments` — fetch and reply to change-request comments. +- `issue-tracker` — create/update tracker issues and perform duplicate checks. + +Provider-specific skills remain implementation details behind those neutral interfaces: + +- `github-publish` +- `gitlab-publish` +- `github-pr-comments` +- `gitlab-mr-comments` + +## Scope and file mapping + +This change is in `core/`, so verify whether stack overlays need matching changes. Initial investigation found no relevant workflow-provider leakage under `stacks/pnpm` or `stacks/maven`, but each task that changes wording must re-check stack ripple. + +Template mapping to keep in mind: + +| Source | Installed target | +|---|---| +| `core/agents/skills/*` | `.agents/skills/*` plus symlinked `.claude/skills/*` authored skills | +| `core/claude/skills/*` | `.claude/skills/*` workflow entry skills | +| `core/opencode/agents/*` | `.opencode/agents/*` | +| `core/docs/*` | `docs/*` | + +Lockfile expectation: no lockfile changes are expected because the new skills are authored local skills, not remote skills. + +--- + +## Task 1 — Add neutral repository integration skills + +### Files to add + +```text +core/agents/skills/git-publish/SKILL.md +core/agents/skills/git-publish/scripts/push-branch.sh + +core/agents/skills/change-request-publish/SKILL.md +core/agents/skills/change-request-publish/scripts/open-change-request.sh + +core/agents/skills/change-request-comments/SKILL.md +core/agents/skills/change-request-comments/scripts/fetch-comments.sh +core/agents/skills/change-request-comments/scripts/reply-to-comment.sh + +core/agents/skills/issue-tracker/SKILL.md +core/agents/skills/issue-tracker/scripts/create-issue.sh +core/agents/skills/issue-tracker/scripts/update-issue.sh +``` + +### Requirements + +- Each `SKILL.md` must have frontmatter with: + - `name` + - `description` + - `user-invocable: false` +- `git-publish` scripts are provider-agnostic and use only `git`. +- `change-request-publish`, `change-request-comments`, and `issue-tracker` scripts own host detection. +- Neutral integration scripts delegate to existing provider-specific skills/scripts where possible. +- Host-specific details may appear inside these neutral integration skills because they are the boundary layer. +- Workflow-facing files must call only these neutral skills/scripts. + +### Suggested implementation notes + +- `git-publish/scripts/push-branch.sh` should push the current branch to `origin` using only `git`, refusing if the branch is the default branch or a detached `HEAD`, and refusing any `--force` / `-f` / `--force-with-lease` argument. It must not inspect the remote host. +- `change-request-publish/scripts/open-change-request.sh` should detect the host and call either: + - `.agents/skills/github-publish/scripts/open-pr.sh` + - `.agents/skills/gitlab-publish/scripts/open-mr.sh` +- `change-request-comments` should wrap the existing GitHub/GitLab comment helpers. +- `issue-tracker` should provide a host-neutral interface for issue creation/update and duplicate checks. + +### Verification + +```bash +bash -n core/agents/skills/git-publish/scripts/*.sh +bash -n core/agents/skills/change-request-publish/scripts/*.sh +bash -n core/agents/skills/change-request-comments/scripts/*.sh +bash -n core/agents/skills/issue-tracker/scripts/*.sh +shellcheck core/agents/skills/git-publish/scripts/*.sh +shellcheck core/agents/skills/change-request-publish/scripts/*.sh +shellcheck core/agents/skills/change-request-comments/scripts/*.sh +shellcheck core/agents/skills/issue-tracker/scripts/*.sh +``` + +### Smoke `git-publish` against a local bare remote + +```bash +mkdir -p .temp/git-publish-smoke +rm -rf .temp/git-publish-smoke/* +git init --bare .temp/git-publish-smoke/origin.git +git init .temp/git-publish-smoke/work +git -C .temp/git-publish-smoke/work remote add origin ../origin.git +git -C .temp/git-publish-smoke/work config user.email "test@example.com" +git -C .temp/git-publish-smoke/work config user.name "Test" +echo "init" > .temp/git-publish-smoke/work/README.md +git -C .temp/git-publish-smoke/work add README.md +git -C .temp/git-publish-smoke/work commit -m "init" +git -C .temp/git-publish-smoke/work checkout -b feature/test +( cd .temp/git-publish-smoke/work && bash .agents/skills/git-publish/scripts/push-branch.sh ) +rm -rf .temp/git-publish-smoke +``` + +### Commit boundary + +One commit: + +```text +Add neutral repository integration skills +``` + +--- + +## Task 2 — Move bug issue mechanics behind `issue-tracker` + +### Files to update + +```text +core/agents/skills/workflow-bug-analysis/SKILL.md +core/opencode/agents/bugfix.md +core/claude/skills/bugfix/SKILL.md +core/claude/settings.json +``` + +### Files to remove, move, or convert to compatibility wrappers + +```text +core/agents/skills/workflow-bug-analysis/scripts/create-bug-issue.sh +core/agents/skills/workflow-bug-analysis/scripts/update-bug-issue.sh +``` + +### Requirements + +- Replace “structured GitHub issue” with “structured tracker issue”. +- Remove direct `gh` / `glab` instructions from workflow-facing bug files. +- `workflow-bug-analysis` owns investigation and structured issue content. +- `issue-tracker` owns issue creation/update mechanics. +- OpenCode and Claude bugfix entry points should call `workflow-bug-analysis` plus `issue-tracker`; they should not name provider CLIs or provider-specific scripts. + +### Verification + +```bash +rg -n "GitHub|GitLab|gh |glab|create-bug-issue|update-bug-issue" \ + core/agents/skills/workflow-bug-analysis \ + core/opencode/agents/bugfix.md \ + core/claude/skills/bugfix/SKILL.md + +bash -n core/agents/skills/issue-tracker/scripts/*.sh +shellcheck core/agents/skills/issue-tracker/scripts/*.sh +``` + +Expected result: no provider-specific leakage remains in generic bug workflow files. Any remaining hit must be provider-boundary documentation or a compatibility wrapper with an explicit migration reason. + +### Commit boundary + +One commit: + +```text +Move bug issue publishing behind issue tracker skill +``` + +--- + +## Task 3 — Replace provider-specific workflow wording + +### Shared workflow files to update + +```text +core/agents/skills/workflow-implementation/SKILL.md +core/agents/skills/workflow-implementation/implementer-prompt.md +core/agents/skills/workflow-implementation/spec-reviewer-prompt.md +core/agents/skills/workflow-implementation/code-quality-reviewer-prompt.md +core/agents/skills/workflow-planning/plan-document-reviewer-prompt.md +core/agents/skills/workflow-verification/SKILL.md +``` + +### OpenCode agent files to update + +```text +core/opencode/agents/brainstorm.md +core/opencode/agents/planner.md +core/opencode/agents/implement.md +core/opencode/agents/finish.md +core/opencode/agents/review-plan.md +core/opencode/agents/review-code.md +core/opencode/agents/bugfix.md +``` + +### Claude workflow skill files to update + +```text +core/claude/skills/brainstorm/SKILL.md +core/claude/skills/planner/SKILL.md +core/claude/skills/implement/SKILL.md +core/claude/skills/finish/SKILL.md +core/claude/skills/review-plan/SKILL.md +core/claude/skills/review-code/SKILL.md +core/claude/skills/bugfix/SKILL.md +``` + +### Replacement language + +Use host-neutral language: + +```text +Push branches through git-publish. +Open a change request through change-request-publish. +Read change-request comments through change-request-comments. +Create or update tracker issues through issue-tracker. +``` + +Avoid in generic workflow files: + +```text +github-publish +gitlab-publish +github-pr-comments +gitlab-mr-comments +gh +glab +open-pr.sh +open-mr.sh +fetch-pr-comments.sh +fetch-mr-comments.sh +``` + +Also remove Claude workflow references to OpenCode internals, including: + +```text +OpenCode handoff +@implement +@implement-task +``` + +unless the section is explicitly documenting high-level cross-harness availability rather than directing the Claude workflow to use OpenCode internals. + +### Verification + +```bash +rg -n "github-publish|gitlab-publish|github-pr-comments|gitlab-mr-comments|gh |glab|open-pr\.sh|open-mr\.sh|fetch-pr-comments|fetch-mr-comments" \ + core/agents/skills/workflow-* \ + core/claude/skills \ + core/opencode/agents + +rg -n "OpenCode handoff|@implement|@implement-task" core/claude/skills +``` + +Expected result: no hits in generic workflow files, or each remaining hit is explicitly justified and not a provider implementation leak. + +### Commit boundary + +One commit: + +```text +Use neutral repository interfaces in workflows +``` + +--- + +## Task 4 — Register new authored skills in installers and docs + +### Files to update + +```text +scripts/init.sh +scripts/copy.sh +README.md +core/docs/agents/agent-workflow-extension.md +core/claude/settings.json +``` + +### Installer requirements + +Add these authored skills to both installer skill lists: + +```text +git-publish +change-request-publish +change-request-comments +issue-tracker +``` + +Relevant current locations: + +- `scripts/init.sh` authored skills array near the Claude authored-skill symlink step. +- `scripts/copy.sh` authored skills array for `.agents/skills//` handling. + +### README requirements + +Update: + +- Installed authored reusable skill list. +- Claude symlink table. +- Recommended workflow wording where generic text says GitHub comments or PR-only language. + +### Extension guide requirements + +Update `core/docs/agents/agent-workflow-extension.md`: + +- Replace “GitHub PR comment workflow boundary” with “change-request comment workflow boundary”. +- Document that provider-specific mechanics belong only in provider or neutral integration skills. +- Keep existing OpenCode/Claude boundary guidance. + +### Claude settings requirements + +Update `core/claude/settings.json`: + +- Allow neutral wrapper scripts. +- Keep mutation operations in `ask` where appropriate. +- Keep provider script permissions only as implementation support for the wrapper layer, not as workflow instructions. + +### Stack ripple check + +```bash +rg -n "github|gitlab|PR|MR|gh |glab" stacks/pnpm stacks/maven +``` + +Update stack overlays only if they contain affected workflow wording. + +### Verification + +```bash +bash -n scripts/init.sh scripts/copy.sh +shellcheck scripts/init.sh scripts/copy.sh +jq . core/claude/settings.json +``` + +Smoke `init.sh` enough to verify new symlinks: + +```bash +mkdir -p .temp/smoke-test +printf "1\n1\n.temp/smoke-test/target\n" | bash scripts/init.sh +ls -la .temp/smoke-test/target/.claude/skills +rm -rf .temp/smoke-test +``` + +### Commit boundary + +One commit: + +```text +Register neutral repository skills in installers +``` + +--- + +## Task 5 — Add workflow boundary regression check + +### File to add + +```text +scripts/check-workflow-boundaries.sh +``` + +### Requirements + +The script should fail when generic workflow-facing files contain direct provider internals. + +Scan at least: + +```text +core/agents/skills/workflow-* +core/claude/skills +core/opencode/agents +``` + +Disallowed examples in generic workflow files: + +```text +github-publish +gitlab-publish +github-pr-comments +gitlab-mr-comments +gh +glab +open-pr.sh +open-mr.sh +fetch-pr-comments.sh +fetch-mr-comments.sh +``` + +Allow provider-specific references in boundary locations: + +```text +core/agents/skills/github-* +core/agents/skills/gitlab-* +core/agents/skills/change-request-publish +core/agents/skills/change-request-comments +core/agents/skills/issue-tracker +scripts/init.sh +scripts/copy.sh +README.md +``` + +### Verification + +```bash +bash -n scripts/check-workflow-boundaries.sh +shellcheck scripts/check-workflow-boundaries.sh +bash scripts/check-workflow-boundaries.sh +``` + +### Commit boundary + +One commit: + +```text +Add workflow provider boundary check +``` + +--- + +## Task 6 — Final verification and acceptance + +### Full verification + +```bash +bash -n scripts/init.sh scripts/copy.sh scripts/check-workflow-boundaries.sh +shellcheck scripts/init.sh scripts/copy.sh scripts/check-workflow-boundaries.sh +codespell README.md core/agents/skills core/claude/skills core/opencode/agents core/docs/agents +bash scripts/check-workflow-boundaries.sh +``` + +### Smoke `init.sh` + +```bash +mkdir -p .temp/smoke-init +printf "1\n1\n.temp/smoke-init/target\n" | bash scripts/init.sh +ls -la .temp/smoke-init/target/.claude/skills +``` + +### Smoke `copy.sh` + +```bash +mkdir -p .temp/smoke-copy/target +git -C .temp/smoke-copy/target init +touch .temp/smoke-copy/target/README.md +git -C .temp/smoke-copy/target add README.md +git -C .temp/smoke-copy/target commit -m "init" +printf "1\n1\n" | bash scripts/copy.sh .temp/smoke-copy/target +ls -la .temp/smoke-copy/target/.claude/skills +``` + +### Cleanup + +```bash +rm -rf .temp/smoke-init .temp/smoke-copy +``` + +### Acceptance criteria + +- Generic workflow skills no longer expose GitHub/GitLab mechanics. +- Provider-specific mechanics are isolated to provider skills or neutral integration skills. +- New authored skills are installed by `init.sh` and `copy.sh`. +- Claude symlinks resolve for all new authored skills. +- README skill lists and symlink table match actual installed assets. +- Stack overlays are checked for ripple effects. +- Boundary check prevents future provider-internal leakage. +- Bash scripts pass `bash -n` and `shellcheck`. +- Smoke installs succeed under `.temp/`. From 5d0b80b4d527935d2acf9b7ef7a3e75f729bbbce Mon Sep 17 00:00:00 2001 From: Simon Flandergan Date: Sun, 28 Jun 2026 11:50:39 +0200 Subject: [PATCH 23/65] docs: detail provider-boundary implementation plan --- plans/2026-06-27-provider-boundaries/plan.md | 955 +++++++++++++++++-- 1 file changed, 860 insertions(+), 95 deletions(-) diff --git a/plans/2026-06-27-provider-boundaries/plan.md b/plans/2026-06-27-provider-boundaries/plan.md index 20685c0..1219730 100644 --- a/plans/2026-06-27-provider-boundaries/plan.md +++ b/plans/2026-06-27-provider-boundaries/plan.md @@ -4,7 +4,7 @@ Generic workflow skills and agents must stop exposing GitHub/GitLab implementation details. Workflow-facing files should describe repository operations in host-neutral terms and call stable neutral skills. Provider-specific mechanics should remain isolated behind integration/provider skills. -The recurring leakage to remove includes: +## Recurring leakage to remove - `gh` / `glab` - `github-publish` / `gitlab-publish` @@ -14,6 +14,7 @@ The recurring leakage to remove includes: - repeated `git remote get-url origin` host-detection snippets - GitHub-only “PR comments” wording in generic workflows - Claude workflow skills naming OpenCode internals such as `@implement`, `@implement-task`, or “OpenCode handoff” +- Base `core/opencode.json` permission entries for `glab` (provider-specific CLI should not appear in generic config) ## Target architecture @@ -24,12 +25,13 @@ Workflow-facing files should use these neutral authored skills: - `change-request-comments` — fetch and reply to change-request comments. - `issue-tracker` — create/update tracker issues and perform duplicate checks. -Provider-specific skills remain implementation details behind those neutral interfaces: +Provider-specific CLI commands remain implementation details inside the neutral integration skills: -- `github-publish` -- `gitlab-publish` -- `github-pr-comments` -- `gitlab-mr-comments` +- `change-request-publish` directly runs `gh pr create` or `glab mr create` after host detection. +- `change-request-comments` delegates to the provider-specific `github-pr-comments` and `gitlab-mr-comments` skills. +- `issue-tracker` directly runs `gh issue ...` or `glab issue ...` after host detection. + +The old `github-publish` and `gitlab-publish` skills are removed entirely; their only remaining behavior (opening PRs/MRs) is absorbed into `change-request-publish`. ## Scope and file mapping @@ -44,7 +46,88 @@ Template mapping to keep in mind: | `core/opencode/agents/*` | `.opencode/agents/*` | | `core/docs/*` | `docs/*` | -Lockfile expectation: no lockfile changes are expected because the new skills are authored local skills, not remote skills. +Lockfile expectation: no lockfile changes are expected because the new skills are authored local skills, not remote skills. `core/skills-lock.json` tracks remote skills installed into target repos; `skills-lock.json` tracks self-maintenance remote skills for this repo. Neither lists authored skills. + +Files added or changed by this plan: + +```text +# New neutral integration skills + core/agents/skills/git-publish/SKILL.md + core/agents/skills/git-publish/scripts/push-branch.sh + core/agents/skills/change-request-publish/SKILL.md + core/agents/skills/change-request-publish/scripts/open-change-request.sh + core/agents/skills/change-request-comments/SKILL.md + core/agents/skills/change-request-comments/scripts/fetch-comments.sh + core/agents/skills/change-request-comments/scripts/reply-to-comment.sh + core/agents/skills/issue-tracker/SKILL.md + core/agents/skills/issue-tracker/scripts/create-issue.sh + core/agents/skills/issue-tracker/scripts/update-issue.sh + core/agents/skills/issue-tracker/scripts/find-duplicate-issues.sh + +# Bug workflow moved behind issue-tracker + core/agents/skills/workflow-bug-analysis/SKILL.md + core/agents/skills/workflow-bug-analysis/scripts/ (delete entire directory) + core/opencode/agents/bugfix.md + core/claude/skills/bugfix/SKILL.md + +# Provider publish skills replaced by change-request-publish + core/agents/skills/github-publish/ (delete entire directory) + core/agents/skills/gitlab-publish/ (delete entire directory) + core/agents/skills/change-request-publish/scripts/open-change-request.sh (absorbs open-pr.sh / open-mr.sh logic) + +# Shared workflow skills and prompts + core/agents/skills/workflow-implementation/SKILL.md + core/agents/skills/workflow-implementation/implementer-prompt.md + core/agents/skills/workflow-implementation/spec-reviewer-prompt.md + core/agents/skills/workflow-implementation/code-quality-reviewer-prompt.md + core/agents/skills/workflow-planning/plan-document-reviewer-prompt.md + core/agents/skills/workflow-verification/SKILL.md + +# OpenCode agents + core/opencode/agents/brainstorm.md + core/opencode/agents/planner.md + core/opencode/agents/implement.md + core/opencode/agents/implement-task.md (verify-only; currently clean) + core/opencode/agents/finish.md + core/opencode/agents/review-plan.md + core/opencode/agents/review-code.md + core/opencode.json + +# Claude workflow skills + core/claude/skills/brainstorm/SKILL.md + core/claude/skills/planner/SKILL.md + core/claude/skills/implement/SKILL.md + core/claude/skills/finish/SKILL.md + core/claude/skills/review-plan/SKILL.md + core/claude/skills/review-code/SKILL.md + core/claude/skills/bugfix/SKILL.md + +# Installers, docs, settings + scripts/init.sh + scripts/copy.sh + README.md + core/docs/agents/agent-workflow-extension.md + core/docs/agents/review-plan.md + core/docs/agents/review-code.md + core/claude/settings.json + +# Regression check + scripts/check-workflow-boundaries.sh +``` + +## Task dependencies + +```text +Task 1 ─┬─> Task 2 (issue-tracker must exist before bug workflow can call it) + ├─> Task 3a (shared workflow prompts reference neutral skills) + ├─> Task 3b (OpenCode agents reference neutral skills) + ├─> Task 3c (Claude skills reference neutral skills) + └─> Task 4a (installers must know about new skills) + +Task 3a/b/c ──> Task 5 (boundary check validates the updated workflow files) + +All tasks ──> Task 6 (final verification) +``` --- @@ -66,6 +149,7 @@ core/agents/skills/change-request-comments/scripts/reply-to-comment.sh core/agents/skills/issue-tracker/SKILL.md core/agents/skills/issue-tracker/scripts/create-issue.sh core/agents/skills/issue-tracker/scripts/update-issue.sh +core/agents/skills/issue-tracker/scripts/find-duplicate-issues.sh ``` ### Requirements @@ -80,14 +164,114 @@ core/agents/skills/issue-tracker/scripts/update-issue.sh - Host-specific details may appear inside these neutral integration skills because they are the boundary layer. - Workflow-facing files must call only these neutral skills/scripts. -### Suggested implementation notes +### Implementation notes + +#### `git-publish/scripts/push-branch.sh` + +- Push the current branch to `origin`. +- Refuse if the current branch is `main`, `master`, or a detached `HEAD`. +- Refuse any `--force` / `-f` / `--force-with-lease` argument. +- Pass through other extra arguments (e.g. `--set-upstream`). +- Do not inspect the remote host. + +For the initial implementation, protect `main|master|HEAD`. A future enhancement could query the remote default branch, but that requires network and is not needed to fix the leakage. + +#### `change-request-publish/scripts/open-change-request.sh` + +- Detect the host from `git remote get-url origin`: + - GitHub (contains `github.com` or starts with `git@github.com:`) → open a pull request with `gh pr create` + - Otherwise → open a merge request with `glab mr create` (GitLab is commonly self-hosted) +- Refuse if the current branch is `main`, `master`, or a detached `HEAD`. +- Skip creation when a change request already exists for the current branch, printing the existing one and exiting 0. +- Pass through all arguments (`"$@"`) to the provider CLI. +- Print the created change-request URL. + +Workflow instructions (Claude `.claude/skills/...`, OpenCode `.agents/skills/...`) must call only the neutral script. Provider CLI names (`gh pr create`, `glab mr create`) are allowed inside this script because it is the boundary layer. + +#### `change-request-comments/scripts/fetch-comments.sh` + +- Detect host from `git remote get-url origin`. +- GitHub → delegate to `.agents/skills/github-pr-comments/scripts/fetch-pr-comments.sh` +- GitLab → delegate to `.agents/skills/gitlab-mr-comments/scripts/fetch-mr-comments.sh` +- Pass through arguments and preserve exit code. + +#### `change-request-comments/scripts/reply-to-comment.sh` + +- Detect host from `git remote get-url origin`. +- GitHub → delegate to `.agents/skills/github-pr-comments/scripts/reply-to-pr-comment.sh` +- GitLab → delegate to `.agents/skills/gitlab-mr-comments/scripts/reply-to-mr-comment.sh` +- Pass through arguments and preserve exit code. + +#### `issue-tracker/scripts/create-issue.sh` + +- Accept `--title TITLE`, `--body-file PATH`, and optional `--labels LABELS`. +- Detect host from `git remote get-url origin`. +- GitHub → `gh issue create --title ... --body-file ... --label ...` +- GitLab → `glab issue create --title ... --description ... --label ...` +- Print the created issue URL. + +#### `issue-tracker/scripts/update-issue.sh` + +- Accept `--issue NUMBER` and `--body-file PATH`. +- Detect host from `git remote get-url origin`. +- GitHub → `gh issue edit --body-file ...` +- GitLab → `glab issue update --description ...` +- Print the issue URL. + +#### `issue-tracker/scripts/find-duplicate-issues.sh` + +- Accept `--title TITLE` and optional `--labels LABELS`. +- Detect host from `git remote get-url origin`. +- GitHub → `gh issue list --search ... --label ... --json number,title,url` +- GitLab → `glab issue list --search ... --label ... --output json` (or equivalent) +- Print a compact list of candidate duplicate issues, or nothing if none found. + +### Provider publish skill removal + +Because `change-request-publish` now owns opening PRs/MRs and `git-publish` owns pushing, the old `github-publish` and `gitlab-publish` skills are redundant. + +#### Files to delete + +```text +core/agents/skills/github-publish/ +core/agents/skills/gitlab-publish/ +``` + +Use `git rm -r` for these tracked directories. + +#### Files to update + +```text +core/agents/skills/change-request-publish/SKILL.md +``` + +Rewrite `change-request-publish/SKILL.md` to describe the neutral interface: + +```markdown +# Change Request Publish + +Open a change request (pull request or merge request) for the current branch after detecting the host. + +## Detect the host + +Inspect `git remote get-url origin`: + +- GitHub (contains `github.com` or starts with `git@github.com:`) → open a pull request with `gh pr create`. +- Otherwise → open a merge request with `glab mr create` (commonly self-hosted GitLab). -- `git-publish/scripts/push-branch.sh` should push the current branch to `origin` using only `git`, refusing if the branch is the default branch or a detached `HEAD`, and refusing any `--force` / `-f` / `--force-with-lease` argument. It must not inspect the remote host. -- `change-request-publish/scripts/open-change-request.sh` should detect the host and call either: - - `.agents/skills/github-publish/scripts/open-pr.sh` - - `.agents/skills/gitlab-publish/scripts/open-mr.sh` -- `change-request-comments` should wrap the existing GitHub/GitLab comment helpers. -- `issue-tracker` should provide a host-neutral interface for issue creation/update and duplicate checks. +## Open a change request + +```bash +bash .agents/skills/change-request-publish/scripts/open-change-request.sh [provider flags] +``` + +The script refuses on `main`/`master`/detached `HEAD` and skips creation when a change request already exists for the branch. Pass `--fill`, `--title`/`--description`, or other flags supported by the underlying CLI. + +## Rules + +- Do not call `gh pr create` or `glab mr create` directly from workflow agents — use this skill's script. +- Do not create change requests from the default branch. +``` ### Verification @@ -100,6 +284,12 @@ shellcheck core/agents/skills/git-publish/scripts/*.sh shellcheck core/agents/skills/change-request-publish/scripts/*.sh shellcheck core/agents/skills/change-request-comments/scripts/*.sh shellcheck core/agents/skills/issue-tracker/scripts/*.sh + +# Confirm old provider publish skills are gone +if [[ -d core/agents/skills/github-publish || -d core/agents/skills/gitlab-publish ]]; then + echo "ERROR: github-publish and gitlab-publish skill directories must be deleted" >&2 + exit 1 +fi ``` ### Smoke `git-publish` against a local bare remote @@ -117,6 +307,14 @@ git -C .temp/git-publish-smoke/work add README.md git -C .temp/git-publish-smoke/work commit -m "init" git -C .temp/git-publish-smoke/work checkout -b feature/test ( cd .temp/git-publish-smoke/work && bash .agents/skills/git-publish/scripts/push-branch.sh ) + +# Negative case: pushing main must be refused +git -C .temp/git-publish-smoke/work checkout main +if ( cd .temp/git-publish-smoke/work && bash .agents/skills/git-publish/scripts/push-branch.sh ); then + echo "ERROR: push-branch.sh should have refused main" >&2 + exit 1 +fi + rm -rf .temp/git-publish-smoke ``` @@ -125,13 +323,27 @@ rm -rf .temp/git-publish-smoke One commit: ```text -Add neutral repository integration skills +Add neutral repository skills and remove redundant provider push scripts ``` --- ## Task 2 — Move bug issue mechanics behind `issue-tracker` +### Decision + +- The `issue-tracker` scripts added in Task 1 supersede the bug-issue scripts. +- Delete the old `workflow-bug-analysis/scripts/` directory entirely after updating all references. Use `git rm -r` for the tracked directory. +- Update `workflow-bug-analysis/SKILL.md` to call `issue-tracker` scripts and use “tracker issue” language. +- Update OpenCode and Claude bugfix entry points to reference `issue-tracker`, not provider CLIs or provider-specific scripts. + +### Files to add/move/remove + +```text +# Superseded by issue-tracker scripts from Task 1; delete: +core/agents/skills/workflow-bug-analysis/scripts/ +``` + ### Files to update ```text @@ -139,27 +351,67 @@ core/agents/skills/workflow-bug-analysis/SKILL.md core/opencode/agents/bugfix.md core/claude/skills/bugfix/SKILL.md core/claude/settings.json -``` - -### Files to remove, move, or convert to compatibility wrappers - -```text -core/agents/skills/workflow-bug-analysis/scripts/create-bug-issue.sh -core/agents/skills/workflow-bug-analysis/scripts/update-bug-issue.sh +core/docs/agents/bugfix.md (verify-only; should already be neutral) ``` ### Requirements -- Replace “structured GitHub issue” with “structured tracker issue”. +- Replace “structured GitHub issue” with “structured tracker issue” everywhere in `workflow-bug-analysis/SKILL.md` and `bugfix/SKILL.md`. - Remove direct `gh` / `glab` instructions from workflow-facing bug files. - `workflow-bug-analysis` owns investigation and structured issue content. -- `issue-tracker` owns issue creation/update mechanics. +- `issue-tracker` owns issue creation/update/duplicate-check mechanics. - OpenCode and Claude bugfix entry points should call `workflow-bug-analysis` plus `issue-tracker`; they should not name provider CLIs or provider-specific scripts. +### Concrete wording changes + +In `core/agents/skills/workflow-bug-analysis/SKILL.md`: + +- Line 3 description: change `produces a structured GitHub issue` → `produces a structured tracker issue`. +- Line 9: change `produce a structured GitHub issue` → `produce a structured tracker issue`. +- Section 7: replace the `create-bug-issue.sh` invocation with: + + ```bash + bash .agents/skills/issue-tracker/scripts/create-issue.sh \ + --title "Concise bug summary" \ + --body-file .temp/-issue-body.md \ + --labels "bug" + ``` + +- Follow-up evidence: replace `update-bug-issue.sh` with `issue-tracker/scripts/update-issue.sh`. +- Add a step after hypothesis: check for duplicates with `issue-tracker/scripts/find-duplicate-issues.sh` before creating the issue. + +In `core/claude/skills/bugfix/SKILL.md`: + +- Line 3 description: `produces a structured GitHub issue` → `produces a structured tracker issue`. +- Line 9: `produce a well-structured GitHub issue` → `produce a well-structured tracker issue`. +- Remove the `gh` rules in the Rules section. Replace with: + + ```text + - Never call `gh` or `glab` directly — use the `issue-tracker` scripts for issue mutations. + - Use `issue-tracker/scripts/find-duplicate-issues.sh` for duplicate checking. + ``` + +In `core/opencode/agents/bugfix.md`: + +- Line 2 description: change `structured GitHub issue` → `structured tracker issue`. +- Replace the comment block that says `# GitHub — agent uses wrapper scripts for mutations; direct gh is denied` with a neutral note: `# Tracker issues — use issue-tracker scripts for mutations; direct gh/glab mutations are denied`. +- Keep read-only provider CLI entries as implementation support for the `issue-tracker` scripts (OpenCode checks the top-level Bash command, but keeping these allows also protects against accidental direct use): + - `gh issue list *`: allow + - `gh issue view *`: allow + - `gh search issues *`: allow + - `glab issue list *`: allow + - `glab issue view *`: allow +- Keep the blanket deny for mutations: + - `gh *`: deny + - `glab *`: deny +- Add allow entries for: + - `bash .agents/skills/issue-tracker/scripts/*.sh` +- Update instructions to say: “Use `issue-tracker/scripts/find-duplicate-issues.sh` for duplicate checks and `issue-tracker/scripts/create-issue.sh` to file the tracker issue.” + ### Verification ```bash -rg -n "GitHub|GitLab|gh |glab|create-bug-issue|update-bug-issue" \ +rg -n "GitHub issue|GitLab issue|gh |glab|create-bug-issue|update-bug-issue" \ core/agents/skills/workflow-bug-analysis \ core/opencode/agents/bugfix.md \ core/claude/skills/bugfix/SKILL.md @@ -168,21 +420,21 @@ bash -n core/agents/skills/issue-tracker/scripts/*.sh shellcheck core/agents/skills/issue-tracker/scripts/*.sh ``` -Expected result: no provider-specific leakage remains in generic bug workflow files. Any remaining hit must be provider-boundary documentation or a compatibility wrapper with an explicit migration reason. +Expected result: no provider-specific leakage remains in generic bug workflow files. Any remaining hit must be inside `issue-tracker` scripts (the boundary layer) or in a compatibility wrapper with an explicit migration reason. ### Commit boundary One commit: ```text -Move bug issue publishing behind issue tracker skill +Move bug issue publishing behind issue-tracker skill ``` --- -## Task 3 — Replace provider-specific workflow wording +## Task 3a — Neutralize shared workflow skills and prompts -### Shared workflow files to update +### Files to update ```text core/agents/skills/workflow-implementation/SKILL.md @@ -193,19 +445,227 @@ core/agents/skills/workflow-planning/plan-document-reviewer-prompt.md core/agents/skills/workflow-verification/SKILL.md ``` -### OpenCode agent files to update +### Replacement language + +Use host-neutral language: + +```text +Push branches through git-publish. +Open a change request through change-request-publish. +Read change-request comments through change-request-comments. +Create or update tracker issues through issue-tracker. +``` + +Avoid in generic workflow files: + +```text +github-publish +gitlab-publish +github-pr-comments +gitlab-mr-comments +gh +glab +open-pr.sh +open-mr.sh +fetch-pr-comments.sh +fetch-mr-comments.sh +``` + +### Concrete change in `workflow-implementation/SKILL.md` + +Replace the Boundaries block (currently lines 99–103): + +```markdown +- After final verification, the controller commits all changes, then pushes the branch with `git-publish` and opens a change request with `change-request-publish`. Never push to the default branch. +``` + +### Concrete change in `workflow-verification/SKILL.md` + +If it contains any host-detection or provider-specific publishing instructions, replace them with references to `git-publish` / `change-request-publish`. Verify first; this file is currently expected to be clean. + +### Verification + +```bash +rg -n "github-publish|gitlab-publish|github-pr-comments|gitlab-mr-comments|gh |glab|open-pr\.sh|open-mr\.sh|fetch-pr-comments|fetch-mr-comments" \ + core/agents/skills/workflow-* +``` + +Expected result: no hits in generic workflow skill files. + +### Commit boundary + +One commit: + +```text +Use neutral repository interfaces in shared workflow skills +``` + +--- + +## Task 3b — Neutralize OpenCode agents + +### Files to update ```text core/opencode/agents/brainstorm.md core/opencode/agents/planner.md core/opencode/agents/implement.md +core/opencode/agents/implement-task.md (verify-only) core/opencode/agents/finish.md core/opencode/agents/review-plan.md core/opencode/agents/review-code.md -core/opencode/agents/bugfix.md +core/opencode.json +``` + +### Permission changes + +In each agent `.md` frontmatter, replace provider-specific Bash allow patterns with neutral ones. + +#### `implement.md` + +Remove: + +```yaml + "bash .agents/skills/github-publish/scripts/push-branch.sh*": allow + "bash .agents/skills/github-publish/scripts/open-pr.sh*": ask + "bash .agents/skills/gitlab-publish/scripts/push-branch.sh*": allow + "bash .agents/skills/gitlab-publish/scripts/open-mr.sh*": ask +``` + +Add: + +```yaml + "bash .agents/skills/git-publish/scripts/push-branch.sh*": allow + "bash .agents/skills/change-request-publish/scripts/open-change-request.sh*": ask +``` + +Remove skill allows: + +```yaml + "github-publish": allow + "gitlab-publish": allow +``` + +Add: + +```yaml + "git-publish": allow + "change-request-publish": allow +``` + +#### `finish.md` + +Same pattern as `implement.md` for publishing permissions. `finish.md` does not open change requests by default, but keep `change-request-publish` in `ask` if the agent is ever extended to do so. + +#### `brainstorm.md` and `planner.md` + +Remove: + +```yaml + "bash .agents/skills/github-publish/scripts/push-branch.sh*": allow + "bash .agents/skills/gitlab-publish/scripts/push-branch.sh*": allow +``` + +Add: + +```yaml + "bash .agents/skills/git-publish/scripts/push-branch.sh*": allow +``` + +#### `review-plan.md` and `review-code.md` + +Remove: + +```yaml + "bash .agents/skills/github-pr-comments/scripts/fetch-pr-comments.sh *": allow + "bash .agents/skills/github-pr-comments/scripts/reply-to-pr-comment.sh *": allow + "bash .agents/skills/gitlab-mr-comments/scripts/fetch-mr-comments.sh*": allow + "bash .agents/skills/gitlab-mr-comments/scripts/reply-to-mr-comment.sh*": ask +``` + +Add: + +```yaml + "bash .agents/skills/change-request-comments/scripts/fetch-comments.sh *": allow + "bash .agents/skills/change-request-comments/scripts/reply-to-comment.sh *": ask +``` + +Remove skill allows: + +```yaml + "github-pr-comments": allow + "gitlab-mr-comments": allow +``` + +Add: + +```yaml + "change-request-comments": allow +``` + +#### `bugfix.md` + +See Task 2. + +#### `core/opencode.json` + +Remove all base `glab` permission entries from `permission.bash`: + +```json + "glab mr create *": "ask", + "glab mr list *": "allow", + "glab mr view *": "allow", + "glab mr diff *": "allow", + "glab issue create *": "ask", + "glab issue view *": "allow", + "glab issue list *": "allow", + "glab issue update *": "ask" +``` + +Generic agents should not need provider CLI permissions in the base config. Any provider CLI access needed by `issue-tracker` scripts is covered by the agent frontmatter that invokes those scripts (OpenCode checks the immediate Bash command; the script's internal CLI calls are not surfaced to the permission layer). + +### Instruction changes + +Replace every host-detection block of the form: + +```markdown +Detect host from `git remote get-url origin`: +- GitHub (contains `github.com` or starts with `git@github.com:`) → use `github-publish` +- Otherwise → use `gitlab-publish` +``` + +with: + +```markdown +Push the branch with `bash .agents/skills/git-publish/scripts/push-branch.sh`. To open a change request, use `bash .agents/skills/change-request-publish/scripts/open-change-request.sh`. ``` -### Claude workflow skill files to update +In `review-plan.md` and `review-code.md`, replace references to `github-pr-comments` / `gitlab-mr-comments` skills with `change-request-comments`. + +### Verification + +```bash +rg -n "github-publish|gitlab-publish|github-pr-comments|gitlab-mr-comments|gh |glab|open-pr\.sh|open-mr\.sh|fetch-pr-comments|fetch-mr-comments" \ + core/opencode/agents + +jq '.permission.bash | keys' core/opencode.json +``` + +Expected result: no provider-specific leakage in generic agent files. `core/opencode.json` should no longer contain `glab` keys. + +### Commit boundary + +One commit: + +```text +Use neutral repository interfaces in OpenCode agents +``` + +--- + +## Task 3c — Neutralize Claude workflow skills + +### Files to update ```text core/claude/skills/brainstorm/SKILL.md @@ -217,33 +677,44 @@ core/claude/skills/review-code/SKILL.md core/claude/skills/bugfix/SKILL.md ``` -### Replacement language +### Description/frontmatter updates -Use host-neutral language: +- `planner/SKILL.md`: change `ready for OpenCode handoff` → `ready for implementation handoff`. +- `review-plan/SKILL.md`: change `finalizes it into the OpenCode handoff document` → `finalizes it into the implementation handoff document`. +- `bugfix/SKILL.md`: change `produces a structured GitHub issue` → `produces a structured tracker issue` (also in body). -```text -Push branches through git-publish. -Open a change request through change-request-publish. -Read change-request comments through change-request-comments. -Create or update tracker issues through issue-tracker. +### Shell guidance updates + +Replace every occurrence of: + +```markdown +Publish through the host-appropriate publish skill. Detect host from `git remote get-url origin`: +- GitHub (contains `github.com` or starts with `git@github.com:`) → `bash .claude/skills/github-publish/scripts/push-branch.sh` +- Otherwise → `bash .claude/skills/gitlab-publish/scripts/push-branch.sh` — GitLab is commonly self-hosted +Never hand-roll `git push`. ``` -Avoid in generic workflow files: +with: -```text -github-publish -gitlab-publish -github-pr-comments -gitlab-mr-comments -gh -glab -open-pr.sh -open-mr.sh -fetch-pr-comments.sh -fetch-mr-comments.sh +```markdown +Publish through the neutral git-publish skill: +- Push the current branch with `bash .claude/skills/git-publish/scripts/push-branch.sh`. +- Open a change request with `bash .claude/skills/change-request-publish/scripts/open-change-request.sh` when needed. +Never hand-roll `git push`. ``` -Also remove Claude workflow references to OpenCode internals, including: +Apply this in `brainstorm/SKILL.md`, `planner/SKILL.md`, `implement/SKILL.md`, `finish/SKILL.md`, and `review-plan/SKILL.md`. + +### Skill reference updates + +In `review-plan/SKILL.md` and `review-code/SKILL.md`: + +- Replace `Use github-pr-comments for GitHub remotes and gitlab-mr-comments for non-GitHub ...` with `Use change-request-comments for reading and drafting replies to change-request comments.` +- Replace references to `github-pr-comments` / `gitlab-mr-comments` with `change-request-comments`. + +### OpenCode internal reference updates + +Remove in generic workflow body text: ```text OpenCode handoff @@ -251,46 +722,61 @@ OpenCode handoff @implement-task ``` -unless the section is explicitly documenting high-level cross-harness availability rather than directing the Claude workflow to use OpenCode internals. +Exceptions allowed only in an explicit cross-harness availability note. Keep such notes minimal and rephrase agent names as neutral harness references where possible: + +- `implement/SKILL.md` may keep a short cross-harness note such as: + ```markdown + This is the Claude Code implementation controller. OpenCode has an equivalent controller agent. + ``` + Do not keep `@implement` in normal workflow instructions. +- `review-code/SKILL.md` currently says: + ```markdown + In Claude Code, prefer writing the fix-plan handoff document and handing it to OpenCode (`@implement` / `@implement-task`) for TDD implementation. + ``` + Replace with: + ```markdown + In Claude Code, prefer writing the fix-plan handoff document and handing it to the OpenCode implement agent for TDD implementation. + ``` +- `planner/SKILL.md` currently says: + ```markdown + - Keep task boundaries small enough that the implementer executes without guessing. + - Implementation can run in either harness: Claude Code (`/implement`) or OpenCode (`@implement`). Pick one per branch. Suggest the user's preferred harness. + ``` + The second bullet is a cross-harness availability note and may stay, but remove `@implement` and replace with `the OpenCode implement agent`. ### Verification ```bash rg -n "github-publish|gitlab-publish|github-pr-comments|gitlab-mr-comments|gh |glab|open-pr\.sh|open-mr\.sh|fetch-pr-comments|fetch-mr-comments" \ - core/agents/skills/workflow-* \ - core/claude/skills \ - core/opencode/agents + core/claude/skills rg -n "OpenCode handoff|@implement|@implement-task" core/claude/skills ``` -Expected result: no hits in generic workflow files, or each remaining hit is explicitly justified and not a provider implementation leak. +Expected result: no hits in generic workflow files, or each remaining hit is explicitly justified as a cross-harness availability note and not a provider implementation leak. ### Commit boundary One commit: ```text -Use neutral repository interfaces in workflows +Use neutral repository interfaces in Claude workflow skills ``` --- -## Task 4 — Register new authored skills in installers and docs +## Task 4a — Register new authored skills in installers ### Files to update ```text scripts/init.sh scripts/copy.sh -README.md -core/docs/agents/agent-workflow-extension.md -core/claude/settings.json ``` ### Installer requirements -Add these authored skills to both installer skill lists: +Add these authored skills to both installer `AUTHORED_SKILLS` arrays: ```text git-publish @@ -299,34 +785,110 @@ change-request-comments issue-tracker ``` -Relevant current locations: +Place them after `feature-documentation` and before `github-pr-comments`: + +```bash +AUTHORED_SKILLS=( + grill-with-docs + workflow-bug-analysis + workflow-brainstorming + workflow-planning + workflow-verification + feature-documentation + git-publish + change-request-publish + change-request-comments + issue-tracker + github-pr-comments + gitlab-mr-comments +) +``` + +Note: `github-publish` and `gitlab-publish` are removed from the list because `change-request-publish` now handles opening PRs/MRs directly. + +The existing frontmatter verification loop in `init.sh` will automatically verify `user-invocable: false` for the new skills. + +### Verification + +```bash +bash -n scripts/init.sh scripts/copy.sh +shellcheck scripts/init.sh scripts/copy.sh + +mkdir -p .temp/smoke-test +printf "1\n1\n.temp/smoke-test/target\n" | bash scripts/init.sh +ls -la .temp/smoke-test/target/.claude/skills | grep -E 'git-publish|change-request-publish|change-request-comments|issue-tracker' +rm -rf .temp/smoke-test +``` + +Expected result: the new symlinks exist in `.claude/skills/`. + +### Commit boundary + +One commit: + +```text +Register neutral repository skills in installers +``` + +--- + +## Task 4b — Update README and role docs -- `scripts/init.sh` authored skills array near the Claude authored-skill symlink step. -- `scripts/copy.sh` authored skills array for `.agents/skills//` handling. +### Files to update + +```text +README.md +core/docs/agents/review-plan.md +core/docs/agents/review-code.md +core/docs/agents/agent-workflow-extension.md +``` ### README requirements -Update: +- **Installed authored reusable skill list** (line 104): add the four new skills and remove `github-publish`/`gitlab-publish` because `change-request-publish` replaces them. -- Installed authored reusable skill list. -- Claude symlink table. -- Recommended workflow wording where generic text says GitHub comments or PR-only language. + Current: + ```text + `grill-with-docs`, `workflow-bug-analysis`, `workflow-brainstorming`, `workflow-planning`, `workflow-implementation`, `workflow-verification`, `feature-documentation`, `github-publish`, `github-pr-comments`, `gitlab-publish`, `gitlab-mr-comments` + ``` -### Extension guide requirements + Updated: + ```text + `grill-with-docs`, `workflow-bug-analysis`, `workflow-brainstorming`, `workflow-planning`, `workflow-implementation`, `workflow-verification`, `feature-documentation`, `git-publish`, `change-request-publish`, `change-request-comments`, `issue-tracker`, `github-pr-comments`, `gitlab-mr-comments` + ``` -Update `core/docs/agents/agent-workflow-extension.md`: +- **Claude symlink table** (lines 131–142): add rows for the four new skills and remove the rows for `github-publish` and `gitlab-publish`. -- Replace “GitHub PR comment workflow boundary” with “change-request comment workflow boundary”. -- Document that provider-specific mechanics belong only in provider or neutral integration skills. -- Keep existing OpenCode/Claude boundary guidance. +- **Recommended workflow wording**: update step 8 caption from `leave inline comments or GitHub review notes` to `leave inline comments or change-request review notes`. -### Claude settings requirements +### Role doc requirements -Update `core/claude/settings.json`: +In `core/docs/agents/review-plan.md` and `core/docs/agents/review-code.md`, replace: -- Allow neutral wrapper scripts. -- Keep mutation operations in `ask` where appropriate. -- Keep provider script permissions only as implementation support for the wrapper layer, not as workflow instructions. +```markdown +- `github-pr-comments` skill for reading and drafting replies to GitHub PR feedback +- `gitlab-mr-comments` skill for reading and drafting replies to GitLab MR feedback +``` + +with: + +```markdown +- `change-request-comments` skill for reading and drafting replies to change-request feedback +``` + +In `review-code.md`, the `Git diff or PR diff under review` bullet is generic enough to keep, but optionally rephrase to `Git diff or change-request diff under review` if desired. + +### Extension guide requirements + +Update `core/docs/agents/agent-workflow-extension.md`: + +- Rename `## GitHub PR comment workflow boundary` to `## Change-request comment workflow boundary`. +- Replace the bullet `The github-pr-comments skill owns reading PR comments, classifying comment target types, obtaining exact IDs, and posting approved replies through project scripts.` with: + ```markdown + - The `change-request-comments` skill owns reading change-request comments, classifying comment target types, obtaining exact IDs, and posting approved replies through project scripts. + - Provider-specific mechanics (`github-pr-comments`, `gitlab-mr-comments`, `gh`, `glab`) belong only in provider skills or neutral integration skills, never in generic workflow skills or agent instructions. + ``` +- Keep existing OpenCode/Claude boundary guidance. ### Stack ripple check @@ -334,31 +896,127 @@ Update `core/claude/settings.json`: rg -n "github|gitlab|PR|MR|gh |glab" stacks/pnpm stacks/maven ``` -Update stack overlays only if they contain affected workflow wording. +Update stack overlays only if they contain affected workflow wording. The pre-flight check indicates no hits, so no overlay changes are expected. ### Verification ```bash -bash -n scripts/init.sh scripts/copy.sh -shellcheck scripts/init.sh scripts/copy.sh -jq . core/claude/settings.json +codespell README.md core/docs/agents + +rg -n "github-pr-comments|gitlab-mr-comments" README.md core/docs/agents +rg -n "GitHub PR comment workflow boundary" core/docs/agents ``` -Smoke `init.sh` enough to verify new symlinks: +Expected result: the old skill names no longer appear in generic docs; only `change-request-comments` and neutral wording remain. + +### Commit boundary + +One commit: + +```text +Document neutral repository skills in README and role docs +``` + +--- + +## Task 4c — Update Claude settings and core/opencode.json + +### Files to update + +```text +core/claude/settings.json +core/opencode.json +``` + +### Claude settings requirements + +Replace provider-specific workflow-facing allow entries with neutral wrapper scripts. Keep provider CLI entries only as implementation support for the wrapper layer (read-only issue/comment list commands used by `issue-tracker` and `change-request-comments`). + +In `permissions.allow`, replace: + +```json + "Bash(bash .claude/skills/github-pr-comments/scripts/fetch-pr-comments.sh:*)", + "Bash(bash .claude/skills/workflow-bug-analysis/scripts/create-bug-issue.sh:*)", + "Bash(gh issue list:*)", + "Bash(gh issue view:*)", + "Bash(gh search issues:*)", + "Bash(bash .claude/skills/github-publish/scripts/push-branch.sh:*)", + "Bash(bash .claude/skills/gitlab-publish/scripts/push-branch.sh:*)", + "Bash(bash .claude/skills/gitlab-mr-comments/scripts/fetch-mr-comments.sh:*)", + "Bash(glab mr view:*)", + "Bash(glab mr diff:*)", + "Bash(glab mr list:*)", + "Bash(glab issue view:*)", + "Bash(glab issue list:*)", +``` + +with: + +```json + "Bash(bash .claude/skills/git-publish/scripts/push-branch.sh:*)", + "Bash(bash .claude/skills/change-request-comments/scripts/fetch-comments.sh:*)", + "Bash(bash .claude/skills/issue-tracker/scripts/create-issue.sh:*)", + "Bash(bash .claude/skills/issue-tracker/scripts/update-issue.sh:*)", + "Bash(bash .claude/skills/issue-tracker/scripts/find-duplicate-issues.sh:*)", + "Bash(gh issue list:*)", + "Bash(gh issue view:*)", + "Bash(gh search issues:*)", + "Bash(glab issue list:*)", + "Bash(glab issue view:*)", +``` + +Note: `change-request-publish` opens a PR/MR, which is a mutation. The existing settings kept `open-pr.sh`/`open-mr.sh` in `ask`, so keep `change-request-publish/scripts/open-change-request.sh` in `ask` for parity. + +In `permissions.ask`, replace: + +```json + "Bash(bash .claude/skills/github-pr-comments/scripts/reply-to-pr-comment.sh:*)", + "Bash(bash .claude/skills/workflow-bug-analysis/scripts/update-bug-issue.sh:*)", + "Bash(bash .claude/skills/github-publish/scripts/open-pr.sh:*)", + "Bash(bash .claude/skills/gitlab-publish/scripts/open-mr.sh:*)", + "Bash(bash .claude/skills/gitlab-mr-comments/scripts/reply-to-mr-comment.sh:*)", +``` + +with: + +```json + "Bash(bash .claude/skills/change-request-publish/scripts/open-change-request.sh:*)", + "Bash(bash .claude/skills/change-request-comments/scripts/reply-to-comment.sh:*)", + "Bash(bash .claude/skills/issue-tracker/scripts/update-issue.sh:*)", +``` + +Remove direct `gh`/`glab` mutation entries from `ask` unless the wrapper layer still needs them. The wrapper scripts call `gh pr create` / `glab mr create` internally; Claude Code permissions are checked against the top-level Bash command, not subprocesses, so only the wrapper script path needs to be permitted. Remove: + +```json + "Bash(gh pr create:*)", + "Bash(glab mr create:*)", + "Bash(glab mr note create:*)", + "Bash(glab issue create:*)", + "Bash(glab issue update:*)", +``` + +### `core/opencode.json` requirements + +Remove all `glab` base permission entries (see Task 3b for the exact list). + +### Verification ```bash -mkdir -p .temp/smoke-test -printf "1\n1\n.temp/smoke-test/target\n" | bash scripts/init.sh -ls -la .temp/smoke-test/target/.claude/skills -rm -rf .temp/smoke-test +jq . core/claude/settings.json > /dev/null +jq . core/opencode.json > /dev/null + +# Confirm neutral entries are present and old workflow-facing entries are gone +rg -n "github-publish|gitlab-publish|github-pr-comments|gitlab-mr-comments|create-bug-issue|update-bug-issue" core/claude/settings.json core/opencode.json ``` +Expected result: only neutral wrapper script entries remain for workflow operations. Provider CLI entries remain only as read-only implementation support if still needed. + ### Commit boundary One commit: ```text -Register neutral repository skills in installers +Update permissions for neutral repository skills ``` --- @@ -373,9 +1031,9 @@ scripts/check-workflow-boundaries.sh ### Requirements -The script should fail when generic workflow-facing files contain direct provider internals. +The script must fail (exit non-zero) when generic workflow-facing files contain direct provider internals. -Scan at least: +#### Scan targets ```text core/agents/skills/workflow-* @@ -383,14 +1041,14 @@ core/claude/skills core/opencode/agents ``` -Disallowed examples in generic workflow files: +#### Disallowed patterns in generic workflow files ```text github-publish gitlab-publish github-pr-comments gitlab-mr-comments -gh +gh glab open-pr.sh open-mr.sh @@ -398,11 +1056,14 @@ fetch-pr-comments.sh fetch-mr-comments.sh ``` -Allow provider-specific references in boundary locations: +#### Allowed boundary locations + +Provider-specific references are permitted only in: ```text core/agents/skills/github-* core/agents/skills/gitlab-* +core/agents/skills/git-publish core/agents/skills/change-request-publish core/agents/skills/change-request-comments core/agents/skills/issue-tracker @@ -411,6 +1072,71 @@ scripts/copy.sh README.md ``` +#### Implementation outline + +```bash +#!/usr/bin/env bash +set -euo pipefail + +ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +cd "$ROOT" + +TARGETS=( + core/agents/skills/workflow-* + core/claude/skills + core/opencode/agents +) + +EXCLUDES=( + core/agents/skills/github-* + core/agents/skills/gitlab-* + core/agents/skills/git-publish + core/agents/skills/change-request-publish + core/agents/skills/change-request-comments + core/agents/skills/issue-tracker + scripts/init.sh + scripts/copy.sh + README.md +) + +PATTERNS=( + 'github-publish' + 'gitlab-publish' + 'github-pr-comments' + 'gitlab-mr-comments' + 'gh ' + 'glab ' + 'open-pr\.sh' + 'open-mr\.sh' + 'fetch-pr-comments\.sh' + 'fetch-mr-comments\.sh' +) + +# Build rg exclude globs +EXCLUDE_ARGS=() +for e in "${EXCLUDES[@]}"; do + EXCLUDE_ARGS+=(--glob="!$e") +done + +FAILED=0 +for pattern in "${PATTERNS[@]}"; do + if rg --line-number --glob='*' "${EXCLUDE_ARGS[@]}" "$pattern" "${TARGETS[@]}"; then + FAILED=1 + fi +done + +if [[ "$FAILED" -ne 0 ]]; then + echo "ERROR: provider-internal references found in generic workflow files." >&2 + exit 1 +fi + +echo "OK: no provider-internal leakage in generic workflow files." +``` + +#### Optional extension + +Add a second pass that scans Claude workflow skills for OpenCode internals (`OpenCode handoff`, `@implement`, `@implement-task`). Allow them only in explicit cross-harness availability notes. This is optional because Task 3c already verifies it with `rg`. + ### Verification ```bash @@ -419,6 +1145,8 @@ shellcheck scripts/check-workflow-boundaries.sh bash scripts/check-workflow-boundaries.sh ``` +Expected result: script exits 0 after all Task 3 changes are complete; it should fail against the current `main` state (confirming it catches leakage). + ### Commit boundary One commit: @@ -448,6 +1176,8 @@ printf "1\n1\n.temp/smoke-init/target\n" | bash scripts/init.sh ls -la .temp/smoke-init/target/.claude/skills ``` +Expected result: all four new skills appear as symlinks in `.claude/skills/`. + ### Smoke `copy.sh` ```bash @@ -460,6 +1190,8 @@ printf "1\n1\n" | bash scripts/copy.sh .temp/smoke-copy/target ls -la .temp/smoke-copy/target/.claude/skills ``` +Expected result: all four new skills appear as symlinks in `.claude/skills/`. + ### Cleanup ```bash @@ -470,10 +1202,43 @@ rm -rf .temp/smoke-init .temp/smoke-copy - Generic workflow skills no longer expose GitHub/GitLab mechanics. - Provider-specific mechanics are isolated to provider skills or neutral integration skills. +- Old provider publish skills (`github-publish/`, `gitlab-publish/`) are removed; `change-request-publish` and `git-publish` are the only publishing paths. - New authored skills are installed by `init.sh` and `copy.sh`. - Claude symlinks resolve for all new authored skills. - README skill lists and symlink table match actual installed assets. +- `core/docs/agents/review-plan.md`, `review-code.md`, and `agent-workflow-extension.md` use neutral skill names. +- `core/opencode.json` no longer contains provider-specific `glab` base permissions. +- `core/claude/settings.json` allows neutral wrapper scripts and no longer lists workflow-facing provider scripts. - Stack overlays are checked for ripple effects. - Boundary check prevents future provider-internal leakage. - Bash scripts pass `bash -n` and `shellcheck`. - Smoke installs succeed under `.temp/`. + +--- + +## Open questions / decisions + +1. **Provider publish skills.** `github-publish/` and `gitlab-publish/` are removed entirely. `git-publish` owns safe branch pushes and `change-request-publish` owns opening PRs/MRs. Provider CLI commands (`gh pr create`, `glab mr create`) live only inside `change-request-publish/scripts/open-change-request.sh`. + +2. **Default branch detection in `git-publish`.** Decision: protect `main|master|HEAD` for the initial implementation. This matches the existing provider scripts and is sufficient for the leakage fix. + +3. **Duplicate-check interface.** Decision: add `issue-tracker/scripts/find-duplicate-issues.sh` with `--title` and optional `--labels`. Return a compact list; callers decide what constitutes a duplicate. + +4. **`core/opencode.json` `glab` removal.** Decision: remove all base `glab` entries. Any OpenCode agent that still needs provider CLI access must declare it in its own frontmatter, but generic workflow agents should not. + +5. **Claude `change-request-publish` permission tier.** Decision: keep `change-request-publish/scripts/open-change-request.sh` in `ask` to match the current `open-pr.sh`/`open-mr.sh` behavior. If the workflow is later changed to auto-open change requests, move it to `allow`. + +--- + +## Pre-flight baseline + +Run these commands before starting implementation to confirm the current leakage: + +```bash +rg -n "github-publish|gitlab-publish|github-pr-comments|gitlab-mr-comments|gh |glab|open-pr\.sh|open-mr\.sh|fetch-pr-comments|fetch-mr-comments" \ + core/agents/skills/workflow-* core/claude/skills core/opencode/agents + +rg -n "OpenCode handoff|@implement|@implement-task" core/claude/skills + +jq '.permission.bash | keys' core/opencode.json +``` From 07c0fe138531eecd98bbeb53aa7719ab4e3717c5 Mon Sep 17 00:00:00 2001 From: Simon Flandergan Date: Sun, 28 Jun 2026 12:22:38 +0200 Subject: [PATCH 24/65] Add neutral repository skills and remove redundant provider push scripts --- .../skills/change-request-comments/SKILL.md | 31 +++++++ .../scripts/fetch-comments.sh | 14 ++++ .../scripts/reply-to-comment.sh | 14 ++++ .../skills/change-request-publish/SKILL.md | 31 +++++++ .../scripts/open-change-request.sh | 47 +++++++++++ core/agents/skills/git-publish/SKILL.md | 26 ++++++ .../scripts/push-branch.sh | 0 core/agents/skills/github-publish/SKILL.md | 34 -------- .../skills/github-publish/scripts/open-pr.sh | 22 ----- core/agents/skills/gitlab-publish/SKILL.md | 34 -------- .../skills/gitlab-publish/scripts/open-mr.sh | 22 ----- .../gitlab-publish/scripts/push-branch.sh | 24 ------ core/agents/skills/issue-tracker/SKILL.md | 42 ++++++++++ .../issue-tracker/scripts/create-issue.sh | 80 +++++++++++++++++++ .../scripts/find-duplicate-issues.sh | 65 +++++++++++++++ .../issue-tracker/scripts/update-issue.sh | 73 +++++++++++++++++ 16 files changed, 423 insertions(+), 136 deletions(-) create mode 100644 core/agents/skills/change-request-comments/SKILL.md create mode 100644 core/agents/skills/change-request-comments/scripts/fetch-comments.sh create mode 100644 core/agents/skills/change-request-comments/scripts/reply-to-comment.sh create mode 100644 core/agents/skills/change-request-publish/SKILL.md create mode 100644 core/agents/skills/change-request-publish/scripts/open-change-request.sh create mode 100644 core/agents/skills/git-publish/SKILL.md rename core/agents/skills/{github-publish => git-publish}/scripts/push-branch.sh (100%) mode change 100755 => 100644 delete mode 100644 core/agents/skills/github-publish/SKILL.md delete mode 100755 core/agents/skills/github-publish/scripts/open-pr.sh delete mode 100644 core/agents/skills/gitlab-publish/SKILL.md delete mode 100755 core/agents/skills/gitlab-publish/scripts/open-mr.sh delete mode 100755 core/agents/skills/gitlab-publish/scripts/push-branch.sh create mode 100644 core/agents/skills/issue-tracker/SKILL.md create mode 100644 core/agents/skills/issue-tracker/scripts/create-issue.sh create mode 100644 core/agents/skills/issue-tracker/scripts/find-duplicate-issues.sh create mode 100644 core/agents/skills/issue-tracker/scripts/update-issue.sh diff --git a/core/agents/skills/change-request-comments/SKILL.md b/core/agents/skills/change-request-comments/SKILL.md new file mode 100644 index 0000000..a8a57dc --- /dev/null +++ b/core/agents/skills/change-request-comments/SKILL.md @@ -0,0 +1,31 @@ +--- +name: change-request-comments +description: Use when reading or replying to pull request or merge request comments — detects GitHub vs GitLab and delegates to provider-specific skills +user-invocable: false +--- + +# Change Request Comments + +Host-agnostic interface for reading and replying to change-request (PR/MR) comments. The script detects whether the repository is on GitHub or GitLab and delegates to the corresponding provider-specific skill. + +## Fetch comments + +```bash +bash .agents/skills/change-request-comments/scripts/fetch-comments.sh [] [--comments-only|--diff-only|--json] +``` + +- **Host detection**: reads `git remote get-url origin` to determine the host. + - GitHub → delegates to `.agents/skills/github-pr-comments/scripts/fetch-pr-comments.sh` + - GitLab → delegates to `.agents/skills/gitlab-mr-comments/scripts/fetch-mr-comments.sh` +- Arguments and exit code are preserved. + +## Reply to a comment + +```bash +bash .agents/skills/change-request-comments/scripts/reply-to-comment.sh [] '' +``` + +- **Host detection**: reads `git remote get-url origin` to determine the host. + - GitHub → delegates to `.agents/skills/github-pr-comments/scripts/reply-to-pr-comment.sh` + - GitLab → delegates to `.agents/skills/gitlab-mr-comments/scripts/reply-to-mr-comment.sh` +- Arguments and exit code are preserved. diff --git a/core/agents/skills/change-request-comments/scripts/fetch-comments.sh b/core/agents/skills/change-request-comments/scripts/fetch-comments.sh new file mode 100644 index 0000000..23b9f7a --- /dev/null +++ b/core/agents/skills/change-request-comments/scripts/fetch-comments.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Detect host from the remote URL. +remote_url="$(git remote get-url origin)" + +case "$remote_url" in + *github.com*) + exec bash .agents/skills/github-pr-comments/scripts/fetch-pr-comments.sh "$@" + ;; + *) + exec bash .agents/skills/gitlab-mr-comments/scripts/fetch-mr-comments.sh "$@" + ;; +esac diff --git a/core/agents/skills/change-request-comments/scripts/reply-to-comment.sh b/core/agents/skills/change-request-comments/scripts/reply-to-comment.sh new file mode 100644 index 0000000..bb48cee --- /dev/null +++ b/core/agents/skills/change-request-comments/scripts/reply-to-comment.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Detect host from the remote URL. +remote_url="$(git remote get-url origin)" + +case "$remote_url" in + *github.com*) + exec bash .agents/skills/github-pr-comments/scripts/reply-to-pr-comment.sh "$@" + ;; + *) + exec bash .agents/skills/gitlab-mr-comments/scripts/reply-to-mr-comment.sh "$@" + ;; +esac diff --git a/core/agents/skills/change-request-publish/SKILL.md b/core/agents/skills/change-request-publish/SKILL.md new file mode 100644 index 0000000..1864bd8 --- /dev/null +++ b/core/agents/skills/change-request-publish/SKILL.md @@ -0,0 +1,31 @@ +--- +name: change-request-publish +description: Use when opening a pull request or merge request — detects GitHub vs GitLab and delegates to the appropriate CLI +user-invocable: false +--- + +# Change Request Publish + +Safe publishing for any Git-hosted repository. Opening a change request (pull request or merge request) goes through a bundled script that **detects the host** from the remote URL and delegates to the appropriate CLI. + +## Why a script, not a raw `gh pr create` or `glab mr create` + +The script inspects the current branch, checks whether a change request already exists, and then delegates to the correct provider CLI. This means workflow-facing files never need to know whether the repository is hosted on GitHub or GitLab. + +## Open a change request + +```bash +bash .agents/skills/change-request-publish/scripts/open-change-request.sh [--title TITLE --description DESCRIPTION] +``` + +- **Host detection**: reads `git remote get-url origin` to determine the host. + - GitHub (`github.com` or `git@github.com:`) → opens a pull request with `gh pr create`. + - Otherwise (GitLab) → opens a merge request with `glab mr create` (GitLab is commonly self-hosted). +- **Branch guard**: refuses on `main`, `master`, or detached `HEAD`. +- **Idempotent**: skips creation when a change request already exists for the current branch, printing the existing one and exiting 0. +- **Pass-through**: all extra arguments are forwarded to the provider CLI. +- **Output**: prints the created change-request URL. + +## Rules + +- Force-pushing and pushing to `main`/`master` are out of scope for this skill; they require a deliberate, human-run command. diff --git a/core/agents/skills/change-request-publish/scripts/open-change-request.sh b/core/agents/skills/change-request-publish/scripts/open-change-request.sh new file mode 100644 index 0000000..37c1b4a --- /dev/null +++ b/core/agents/skills/change-request-publish/scripts/open-change-request.sh @@ -0,0 +1,47 @@ +#!/usr/bin/env bash +set -euo pipefail + +branch="$(git rev-parse --abbrev-ref HEAD)" + +case "$branch" in + main|master|HEAD) + printf 'Refusing: current branch is "%s". Open a change request from a feature branch.\n' "$branch" >&2 + exit 1 + ;; +esac + +# Detect host from the remote URL. +remote_url="$(git remote get-url origin)" + +case "$remote_url" in + *github.com*) + provider="github" + ;; + *) + provider="gitlab" + ;; +esac + +if [ "$provider" = "github" ]; then + # Skip creation if a pull request already exists for this branch. + existing="$(gh pr list --head "$branch" --json url --jq 'length')" + if [ "${existing:-0}" -gt 0 ]; then + printf 'A pull request already exists for branch "%s":\n' "$branch" + gh pr list --head "$branch" --json url,title --jq '.[] | " \(.title) — \(.url)"' + exit 0 + fi + + printf 'Opening pull request for branch "%s"...\n' "$branch" + gh pr create --head "$branch" "$@" +else + # Skip creation if a merge request already exists for this branch. + existing="$(glab mr list --source-branch "$branch" -F json 2>/dev/null | jq -r 'length' || echo 0)" + if [ "${existing:-0}" -gt 0 ]; then + printf 'A merge request already exists for branch "%s":\n' "$branch" + glab mr list --source-branch "$branch" + exit 0 + fi + + printf 'Opening merge request for branch "%s"...\n' "$branch" + glab mr create --source-branch "$branch" "$@" +fi diff --git a/core/agents/skills/git-publish/SKILL.md b/core/agents/skills/git-publish/SKILL.md new file mode 100644 index 0000000..3db4f0e --- /dev/null +++ b/core/agents/skills/git-publish/SKILL.md @@ -0,0 +1,26 @@ +--- +name: git-publish +description: Use when pushing a branch to a remote — guards against pushing to the default branch and against force-pushing +user-invocable: false +--- + +# Git Publish + +Safe publishing for any Git-hosted repository. Pushing goes through a bundled script that **refuses to act on `main`/`master`** and refuses force-pushes. + +## Why a script, not a raw `git push` + +`git push origin $(git rev-parse --abbrev-ref HEAD)` does **not** protect `main`: while you are on `main` it expands to `git push origin main`, and permission globs cannot see through the command substitution to block it. The guard has to inspect the current branch at run time, which is what this script does. + +## Push the current branch + +```bash +bash .agents/skills/git-publish/scripts/push-branch.sh +``` + +It pushes the current branch to `origin`, refusing if the branch is `main`, `master`, or a detached `HEAD`, and refusing any `--force` / `-f` / `--force-with-lease` argument. Extra arguments (e.g. `--set-upstream`) are passed through. + +## Rules + +- Never bypass this script with a raw `git push` to publish work — the protection only holds if publishing goes through it. +- Force-pushing and pushing to `main`/`master` are out of scope for this skill; they require a deliberate, human-run command. diff --git a/core/agents/skills/github-publish/scripts/push-branch.sh b/core/agents/skills/git-publish/scripts/push-branch.sh old mode 100755 new mode 100644 similarity index 100% rename from core/agents/skills/github-publish/scripts/push-branch.sh rename to core/agents/skills/git-publish/scripts/push-branch.sh diff --git a/core/agents/skills/github-publish/SKILL.md b/core/agents/skills/github-publish/SKILL.md deleted file mode 100644 index b8bf0c3..0000000 --- a/core/agents/skills/github-publish/SKILL.md +++ /dev/null @@ -1,34 +0,0 @@ ---- -name: github-publish -description: Use when pushing a branch or opening a pull request — guards against pushing to the default branch and against force-pushing -user-invocable: false ---- - -# GitHub Publish - -Safe publishing for GitHub-hosted repositories. Pushing and opening pull requests go through bundled scripts that **refuse to act on `main`** and refuse force-pushes. - -## Why a script, not a raw `git push` - -`git push origin $(git rev-parse --abbrev-ref HEAD)` does **not** protect `main`: while you are on `main` it expands to `git push origin main`, and permission globs cannot see through the command substitution to block it. The guard has to inspect the current branch at run time, which is what these scripts do. - -## Push the current branch - -```bash -bash .agents/skills/github-publish/scripts/push-branch.sh -``` - -It pushes the current branch to `origin`, refusing if the branch is `main` or a detached `HEAD`, and refusing any `--force` / `-f` / `--force-with-lease` argument. Extra arguments (e.g. `--set-upstream`) are passed through. - -## Open a pull request - -```bash -bash .agents/skills/github-publish/scripts/open-pr.sh [gh pr create flags] -``` - -It refuses on `main`, skips creation when a PR already exists for the current branch (printing the existing one), and otherwise runs `gh pr create` for the current branch. Pass `--fill` to derive the title/description from commits, or `--title`/`--description` explicitly. - -## Rules - -- Never bypass these scripts with a raw `git push` to publish work — the protection only holds if publishing goes through them. -- Force-pushing and pushing to `main` are out of scope for this skill; they require a deliberate, human-run command. diff --git a/core/agents/skills/github-publish/scripts/open-pr.sh b/core/agents/skills/github-publish/scripts/open-pr.sh deleted file mode 100755 index 0cdd22d..0000000 --- a/core/agents/skills/github-publish/scripts/open-pr.sh +++ /dev/null @@ -1,22 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -branch="$(git rev-parse --abbrev-ref HEAD)" - -case "$branch" in - main|master|HEAD) - printf 'Refusing: current branch is "%s". Open a pull request from a feature branch.\n' "$branch" >&2 - exit 1 - ;; -esac - -# Skip creation if a pull request already exists for this branch. -existing="$(gh pr list --head "$branch" --json url --jq 'length')" -if [ "${existing:-0}" -gt 0 ]; then - printf 'A pull request already exists for branch "%s":\n' "$branch" - gh pr list --head "$branch" --json url,title --jq '.[] | " \(.title) — \(.url)"' - exit 0 -fi - -printf 'Opening pull request for branch "%s"...\n' "$branch" -gh pr create --head "$branch" "$@" diff --git a/core/agents/skills/gitlab-publish/SKILL.md b/core/agents/skills/gitlab-publish/SKILL.md deleted file mode 100644 index 5a12de5..0000000 --- a/core/agents/skills/gitlab-publish/SKILL.md +++ /dev/null @@ -1,34 +0,0 @@ ---- -name: gitlab-publish -description: Use when pushing a branch or opening a merge request on a GitLab-hosted repository — guards against pushing to the default branch and against force-pushing -user-invocable: false ---- - -# GitLab Publish - -Safe publishing for GitLab-hosted repositories. Pushing and opening merge requests go through bundled scripts that **refuse to act on `main`/`master`** and refuse force-pushes. - -## Why a script, not a raw `git push` - -`git push origin $(git rev-parse --abbrev-ref HEAD)` does **not** protect `main`: while you are on `main` it expands to `git push origin main`, and permission globs cannot see through the command substitution to block it. The guard has to inspect the current branch at run time, which is what these scripts do. - -## Push the current branch - -```bash -bash .agents/skills/gitlab-publish/scripts/push-branch.sh -``` - -It pushes the current branch to `origin`, refusing if the branch is `main`, `master`, or a detached `HEAD`, and refusing any `--force` / `-f` / `--force-with-lease` argument. Extra arguments (e.g. `--set-upstream`) are passed through. - -## Open a merge request - -```bash -bash .agents/skills/gitlab-publish/scripts/open-mr.sh [glab mr create flags] -``` - -It refuses on `main`/`master`, skips creation when an MR already exists for the current branch (printing the existing one), and otherwise runs `glab mr create` for the current branch. Pass `--fill` to derive the title/description from commits, or `--title`/`--description` explicitly. - -## Rules - -- Never bypass these scripts with a raw `git push` to publish work — the protection only holds if publishing goes through them. -- Force-pushing and pushing to `main`/`master` are out of scope for this skill; they require a deliberate, human-run command. diff --git a/core/agents/skills/gitlab-publish/scripts/open-mr.sh b/core/agents/skills/gitlab-publish/scripts/open-mr.sh deleted file mode 100755 index bcad898..0000000 --- a/core/agents/skills/gitlab-publish/scripts/open-mr.sh +++ /dev/null @@ -1,22 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -branch="$(git rev-parse --abbrev-ref HEAD)" - -case "$branch" in - main|master|HEAD) - printf 'Refusing: current branch is "%s". Open a merge request from a feature branch.\n' "$branch" >&2 - exit 1 - ;; -esac - -# Skip creation if a merge request already exists for this branch. -existing="$(glab mr list --source-branch "$branch" -F json 2>/dev/null | jq -r 'length' || echo 0)" -if [ "${existing:-0}" -gt 0 ]; then - printf 'A merge request already exists for branch "%s":\n' "$branch" - glab mr list --source-branch "$branch" - exit 0 -fi - -printf 'Opening merge request for branch "%s"...\n' "$branch" -glab mr create --source-branch "$branch" "$@" diff --git a/core/agents/skills/gitlab-publish/scripts/push-branch.sh b/core/agents/skills/gitlab-publish/scripts/push-branch.sh deleted file mode 100755 index 788047c..0000000 --- a/core/agents/skills/gitlab-publish/scripts/push-branch.sh +++ /dev/null @@ -1,24 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -branch="$(git rev-parse --abbrev-ref HEAD)" - -case "$branch" in - main|master|HEAD) - printf 'Refusing to push: current branch is "%s". Create a scoped feature branch first.\n' "$branch" >&2 - exit 1 - ;; -esac - -# Force-pushing is never part of safe publishing. -for arg in "$@"; do - case "$arg" in - --force|-f|--force-with-lease|--force-with-lease=*) - printf 'Refusing to force-push from this script. Force-push must be a deliberate, human-run command.\n' >&2 - exit 1 - ;; - esac -done - -printf 'Pushing branch "%s" to origin...\n' "$branch" -git push origin "$branch" "$@" diff --git a/core/agents/skills/issue-tracker/SKILL.md b/core/agents/skills/issue-tracker/SKILL.md new file mode 100644 index 0000000..c265fc2 --- /dev/null +++ b/core/agents/skills/issue-tracker/SKILL.md @@ -0,0 +1,42 @@ +--- +name: issue-tracker +description: Use when creating, updating, or searching for issues — detects GitHub vs GitLab and delegates to the appropriate CLI +user-invocable: false +--- + +# Issue Tracker + +Host-agnostic interface for issue management. Scripts detect whether the repository is hosted on GitHub or GitLab and delegate to the correct provider CLI (`gh` or `glab`). + +## Create an issue + +```bash +bash .agents/skills/issue-tracker/scripts/create-issue.sh --title TITLE --body-file PATH [--labels LABELS] +``` + +- **Host detection**: reads `git remote get-url origin` to determine the host. + - GitHub → `gh issue create --title ... --body-file ... --label ...` + - GitLab → `glab issue create --title ... --description ... --label ...` +- Prints the created issue URL. + +## Update an issue + +```bash +bash .agents/skills/issue-tracker/scripts/update-issue.sh --issue NUMBER --body-file PATH +``` + +- **Host detection**: reads `git remote get-url origin` to determine the host. + - GitHub → `gh issue edit --body-file ...` + - GitLab → `glab issue update --description ...` +- Prints the issue URL. + +## Find duplicate issues + +```bash +bash .agents/skills/issue-tracker/scripts/find-duplicate-issues.sh --title TITLE [--labels LABELS] +``` + +- **Host detection**: reads `git remote get-url origin` to determine the host. + - GitHub → `gh issue list --search ... --label ... --json number,title,url` + - GitLab → `glab issue list --search ... --label ... --output json` +- Prints a compact list of candidate duplicate issues, or nothing if none found. diff --git a/core/agents/skills/issue-tracker/scripts/create-issue.sh b/core/agents/skills/issue-tracker/scripts/create-issue.sh new file mode 100644 index 0000000..7616e19 --- /dev/null +++ b/core/agents/skills/issue-tracker/scripts/create-issue.sh @@ -0,0 +1,80 @@ +#!/usr/bin/env bash +set -euo pipefail + +usage() { + cat <&2 + usage + ;; + esac +done + +# Validate required arguments. +if [ -z "$TITLE" ]; then + echo "Error: --title is required" >&2 + usage +fi + +if [ -z "$BODY_FILE" ]; then + echo "Error: --body-file is required" >&2 + usage +fi + +if [ ! -f "$BODY_FILE" ]; then + echo "Error: body file '$BODY_FILE' does not exist" >&2 + exit 1 +fi + +if [ ! -s "$BODY_FILE" ]; then + echo "Error: body file '$BODY_FILE' is empty" >&2 + exit 1 +fi + +# Detect host from the remote URL. +remote_url="$(git remote get-url origin)" + +case "$remote_url" in + *github.com*) + if [ -n "$LABELS" ]; then + gh issue create --title "$TITLE" --body-file "$BODY_FILE" --label "$LABELS" + else + gh issue create --title "$TITLE" --body-file "$BODY_FILE" + fi + ;; + *) + if [ -n "$LABELS" ]; then + glab issue create --title "$TITLE" --description-file "$BODY_FILE" --label "$LABELS" + else + glab issue create --title "$TITLE" --description-file "$BODY_FILE" + fi + ;; +esac diff --git a/core/agents/skills/issue-tracker/scripts/find-duplicate-issues.sh b/core/agents/skills/issue-tracker/scripts/find-duplicate-issues.sh new file mode 100644 index 0000000..2e34ef7 --- /dev/null +++ b/core/agents/skills/issue-tracker/scripts/find-duplicate-issues.sh @@ -0,0 +1,65 @@ +#!/usr/bin/env bash +set -euo pipefail + +usage() { + cat <&2 + usage + ;; + esac +done + +# Validate required arguments. +if [ -z "$TITLE" ]; then + echo "Error: --title is required" >&2 + usage +fi + +# Detect host from the remote URL. +remote_url="$(git remote get-url origin)" + +case "$remote_url" in + *github.com*) + label_args=() + if [ -n "$LABELS" ]; then + IFS=',' read -ra label_arr <<< "$LABELS" + for label in "${label_arr[@]}"; do + label_args+=(--label "$label") + done + fi + gh issue list --search "$TITLE" "${label_args[@]}" --json number,title,url + ;; + *) + label_args=() + if [ -n "$LABELS" ]; then + IFS=',' read -ra label_arr <<< "$LABELS" + for label in "${label_arr[@]}"; do + label_args+=(--label "$label") + done + fi + glab issue list --search "$TITLE" "${label_args[@]}" --output json + ;; +esac diff --git a/core/agents/skills/issue-tracker/scripts/update-issue.sh b/core/agents/skills/issue-tracker/scripts/update-issue.sh new file mode 100644 index 0000000..d4656fc --- /dev/null +++ b/core/agents/skills/issue-tracker/scripts/update-issue.sh @@ -0,0 +1,73 @@ +#!/usr/bin/env bash +set -euo pipefail + +usage() { + cat <&2 + usage + ;; + esac +done + +# Validate required arguments. +if [ -z "$ISSUE" ]; then + echo "Error: --issue is required" >&2 + usage +fi + +if ! [[ "$ISSUE" =~ ^[0-9]+$ ]]; then + echo "Error: --issue must be a positive integer, got '$ISSUE'" >&2 + exit 1 +fi + +if [ -z "$BODY_FILE" ]; then + echo "Error: --body-file is required" >&2 + usage +fi + +if [ ! -f "$BODY_FILE" ]; then + echo "Error: body file '$BODY_FILE' does not exist" >&2 + exit 1 +fi + +if [ ! -s "$BODY_FILE" ]; then + echo "Error: body file '$BODY_FILE' is empty" >&2 + exit 1 +fi + +# Detect host from the remote URL. +remote_url="$(git remote get-url origin)" + +case "$remote_url" in + *github.com*) + gh issue edit "$ISSUE" --body-file "$BODY_FILE" + gh issue view "$ISSUE" --json url -q .url + ;; + *) + glab issue update "$ISSUE" --description-file "$BODY_FILE" + glab issue view "$ISSUE" -F json | jq -r '.web_url' + ;; +esac From f2ed5852f3e3cd9780db931da86303769df9d2d1 Mon Sep 17 00:00:00 2001 From: Simon Flandergan Date: Sun, 28 Jun 2026 12:28:01 +0200 Subject: [PATCH 25/65] Move bug issue publishing behind issue-tracker skill --- .../skills/workflow-bug-analysis/SKILL.md | 19 +++-- .../scripts/create-bug-issue.sh | 70 ------------------- .../scripts/update-bug-issue.sh | 70 ------------------- core/claude/settings.json | 5 +- core/claude/skills/bugfix/SKILL.md | 12 ++-- core/opencode/agents/bugfix.md | 15 ++-- 6 files changed, 31 insertions(+), 160 deletions(-) delete mode 100755 core/agents/skills/workflow-bug-analysis/scripts/create-bug-issue.sh delete mode 100755 core/agents/skills/workflow-bug-analysis/scripts/update-bug-issue.sh diff --git a/core/agents/skills/workflow-bug-analysis/SKILL.md b/core/agents/skills/workflow-bug-analysis/SKILL.md index c87236d..9a565fa 100644 --- a/core/agents/skills/workflow-bug-analysis/SKILL.md +++ b/core/agents/skills/workflow-bug-analysis/SKILL.md @@ -1,12 +1,12 @@ --- name: workflow-bug-analysis -description: Systematic bug investigation methodology — classify input, reproduce, trace code paths, inspect logs, form hypotheses, and produce a structured GitHub issue. +description: Systematic bug investigation methodology — classify input, reproduce, trace code paths, inspect logs, form hypotheses, and produce a structured tracker issue. user-invocable: false --- # Bugfix Analysis -Systematic investigation methodology for bug reports. The calling agent uses this skill to trace a bug from symptom to root cause and produce a structured GitHub issue. +Systematic investigation methodology for bug reports. The calling agent uses this skill to trace a bug from symptom to root cause and produce a structured tracker issue. ## Investigation Steps @@ -86,8 +86,17 @@ Structure findings into the issue template and save to `.temp/-issue-body. ### 7. Create the issue +First, check for duplicate issues: + +```bash +bash .agents/skills/issue-tracker/scripts/find-duplicate-issues.sh \ + --title "Concise bug summary" +``` + +If duplicates exist, link to them in the issue body. Then create the issue: + ```bash -bash .agents/skills/workflow-bug-analysis/scripts/create-bug-issue.sh \ +bash .agents/skills/issue-tracker/scripts/create-issue.sh \ --title "Concise bug summary" \ --body-file .temp/-issue-body.md \ --labels "bug" @@ -100,9 +109,9 @@ The script prints the created issue URL. Report this URL to the user. If the user provides additional evidence after the issue is created: 1. Update the issue body file in `.temp/` -2. Use `update-bug-issue.sh` to push the update: +2. Use `issue-tracker/scripts/update-issue.sh` to push the update: ```bash - bash .agents/skills/workflow-bug-analysis/scripts/update-bug-issue.sh \ + bash .agents/skills/issue-tracker/scripts/update-issue.sh \ --issue \ --body-file .temp/-issue-body-updated.md ``` diff --git a/core/agents/skills/workflow-bug-analysis/scripts/create-bug-issue.sh b/core/agents/skills/workflow-bug-analysis/scripts/create-bug-issue.sh deleted file mode 100755 index 8986c55..0000000 --- a/core/agents/skills/workflow-bug-analysis/scripts/create-bug-issue.sh +++ /dev/null @@ -1,70 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -usage() { - cat <&2 - usage - ;; - esac -done - -# Validate required arguments -if [ -z "$TITLE" ]; then - echo "Error: --title is required" >&2 - usage -fi - -if [ -z "$BODY_FILE" ]; then - echo "Error: --body-file is required" >&2 - usage -fi - -if [ ! -f "$BODY_FILE" ]; then - echo "Error: body file '$BODY_FILE' does not exist" >&2 - exit 1 -fi - -if [ ! -s "$BODY_FILE" ]; then - echo "Error: body file '$BODY_FILE' is empty" >&2 - exit 1 -fi - -# Check gh is available -if ! command -v gh >/dev/null 2>&1; then - echo "Error: GitHub CLI (gh) is not installed. Install it from https://cli.github.com/" >&2 - exit 1 -fi - -# Create the issue -URL=$(gh issue create --title "$TITLE" --body-file "$BODY_FILE" --label "$LABELS") -echo "$URL" diff --git a/core/agents/skills/workflow-bug-analysis/scripts/update-bug-issue.sh b/core/agents/skills/workflow-bug-analysis/scripts/update-bug-issue.sh deleted file mode 100755 index c79e941..0000000 --- a/core/agents/skills/workflow-bug-analysis/scripts/update-bug-issue.sh +++ /dev/null @@ -1,70 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -usage() { - cat <&2 - usage - ;; - esac -done - -# Validate required arguments -if [ -z "$ISSUE" ]; then - echo "Error: --issue is required" >&2 - usage -fi - -if ! [[ "$ISSUE" =~ ^[0-9]+$ ]]; then - echo "Error: --issue must be a positive integer, got '$ISSUE'" >&2 - exit 1 -fi - -if [ -z "$BODY_FILE" ]; then - echo "Error: --body-file is required" >&2 - usage -fi - -if [ ! -f "$BODY_FILE" ]; then - echo "Error: body file '$BODY_FILE' does not exist" >&2 - exit 1 -fi - -if [ ! -s "$BODY_FILE" ]; then - echo "Error: body file '$BODY_FILE' is empty" >&2 - exit 1 -fi - -# Check gh is available -if ! command -v gh >/dev/null 2>&1; then - echo "Error: GitHub CLI (gh) is not installed. Install it from https://cli.github.com/" >&2 - exit 1 -fi - -# Update the issue -gh issue edit "$ISSUE" --body-file "$BODY_FILE" -URL=$(gh issue view "$ISSUE" --json url -q .url) -echo "$URL" diff --git a/core/claude/settings.json b/core/claude/settings.json index 29b0292..a724baa 100644 --- a/core/claude/settings.json +++ b/core/claude/settings.json @@ -43,7 +43,8 @@ "Bash(mkdir:*)", "Bash(bash .claude/skills/github-pr-comments/scripts/fetch-pr-comments.sh:*)", - "Bash(bash .claude/skills/workflow-bug-analysis/scripts/create-bug-issue.sh:*)", + "Bash(bash .claude/skills/issue-tracker/scripts/create-issue.sh:*)", + "Bash(bash .claude/skills/issue-tracker/scripts/find-duplicate-issues.sh:*)", "Bash(gh issue list:*)", "Bash(gh issue view:*)", "Bash(gh search issues:*)", @@ -65,7 +66,7 @@ "Bash(rm:*)", "Bash(rm -rf:*)", "Bash(bash .claude/skills/github-pr-comments/scripts/reply-to-pr-comment.sh:*)", - "Bash(bash .claude/skills/workflow-bug-analysis/scripts/update-bug-issue.sh:*)", + "Bash(bash .claude/skills/issue-tracker/scripts/update-issue.sh:*)", "Bash(bash .claude/skills/github-publish/scripts/open-pr.sh:*)", "Bash(bash .claude/skills/gitlab-publish/scripts/open-mr.sh:*)", "Bash(bash .claude/skills/gitlab-mr-comments/scripts/reply-to-mr-comment.sh:*)", diff --git a/core/claude/skills/bugfix/SKILL.md b/core/claude/skills/bugfix/SKILL.md index 14cbbf5..d25ed29 100644 --- a/core/claude/skills/bugfix/SKILL.md +++ b/core/claude/skills/bugfix/SKILL.md @@ -1,12 +1,12 @@ --- name: bugfix -description: Investigates bugs from error logs or behavior descriptions, traces root cause through code and data, and produces a structured GitHub issue. Does not fix bugs. +description: Investigates bugs from error logs or behavior descriptions, traces root cause through code and data, and produces a structured tracker issue. Does not fix bugs. argument-hint: [error log, stack trace, or behavior description] disable-model-invocation: true --- You are the bugfix analysis agent for this repository. Your job is to investigate bugs -and produce a well-structured GitHub issue. You do not fix bugs. +and produce a well-structured tracker issue. You do not fix bugs. ## Load first @@ -32,8 +32,8 @@ when their questions are independent. 3. **Hypothesize** — Form a root-cause hypothesis based on gathered evidence. -4. **Create the issue** — Author and file a structured GitHub issue using the - `workflow-bug-analysis` skill. +4. **Create the issue** — Use `issue-tracker/scripts/find-duplicate-issues.sh` for duplicate checks and `issue-tracker/scripts/create-issue.sh` to file the tracker issue using the + `workflow-bug-analysis` skill for content. 5. **Report and stop** — Report the issue URL. The job is done. @@ -46,8 +46,8 @@ using the `workflow-bug-analysis` skill and report the updated issue URL. - Never commit, push, or create PRs. Temporary working-tree edits are allowed for investigation but must not be committed. -- Never call `gh` directly for mutations — use the `workflow-bug-analysis` skill's wrapper - scripts. +- Never call `gh` or `glab` directly — use the `issue-tracker` scripts for issue mutations. +- Use `issue-tracker/scripts/find-duplicate-issues.sh` for duplicate checking. - Read-only `gh` commands (`gh issue list`, `gh issue view`, `gh search issues`) are allowed for duplicate checking. - If the bug cannot be investigated with the available evidence, say so and list what diff --git a/core/opencode/agents/bugfix.md b/core/opencode/agents/bugfix.md index 2550204..6104b81 100644 --- a/core/opencode/agents/bugfix.md +++ b/core/opencode/agents/bugfix.md @@ -1,5 +1,5 @@ --- -description: Investigates bugs from error logs or behavior descriptions, traces root cause through code and data, and produces a structured GitHub issue. +description: Investigates bugs from error logs or behavior descriptions, traces root cause through code and data, and produces a structured tracker issue. mode: all temperature: 0.1 permission: @@ -11,8 +11,7 @@ permission: "*": ask # Skill scripts — primary tools - "bash .agents/skills/workflow-bug-analysis/scripts/create-bug-issue.sh *": allow - "bash .agents/skills/workflow-bug-analysis/scripts/update-bug-issue.sh *": allow + "bash .agents/skills/issue-tracker/scripts/*.sh": allow # Read-only git commands "git branch --show-current": allow @@ -34,12 +33,14 @@ permission: "mkdir -p .temp/*": allow "echo *": allow - # GitHub — agent uses wrapper scripts for mutations; direct gh is denied + # Tracker issues — use issue-tracker scripts for mutations; direct gh/glab mutations are denied "gh *": deny # Read-only issue inspection is allowed for duplicate checking "gh issue list *": allow "gh issue view *": allow "gh search issues *": allow + "glab issue list *": allow + "glab issue view *": allow # Denied — agent never persists changes or mutates GitHub directly "git push *": deny @@ -57,14 +58,14 @@ You are the bugfix analysis agent. Load `docs/agents/bugfix.md` and invoke the `workflow-bug-analysis` skill before investigating. -Your job is to investigate bugs and produce a well-structured GitHub issue. You do not fix bugs. +Your job is to investigate bugs and produce a well-structured tracker issue. You do not fix bugs. ## Workflow 1. **Intake** — Read the user's input (error log, stack trace, or behavior description). Classify the input type and extract key signals. 2. **Investigate** — Use the `workflow-bug-analysis` skill methodology. Launch `@explore` subagents when you need focused repository investigation. 3. **Hypothesize** — Form a root-cause hypothesis based on gathered evidence. -4. **Create the issue** — Author and file a structured GitHub issue using the `workflow-bug-analysis` skill. +4. **Create the issue** — Use `issue-tracker/scripts/find-duplicate-issues.sh` for duplicate checks and `issue-tracker/scripts/create-issue.sh` to file the tracker issue. 5. **Report and stop** — Report the issue URL. ## Subagent usage @@ -76,6 +77,6 @@ Concrete example: if the bug involves a service behavior the agent has not inspe ## Rules - Never commit, push, or create PRs. Temporary working-tree edits (e.g., a reproduction test or log statement) are allowed for investigation but must not be committed. -- Never call `gh` directly for mutations — use the skill's wrapper scripts. Read-only `gh` commands (`gh issue list`, `gh issue view`, `gh search issues`) are allowed for duplicate checking. +- Never call `gh` or `glab` directly for mutations — use the `issue-tracker` scripts. Read-only `gh`/`glab` commands (`issue list`, `issue view`, `search issues`) are allowed for duplicate checking. - The default workflow ends when the issue is created and the URL is reported. If the user provides follow-up evidence, update the issue and report the updated URL. - If the bug cannot be investigated with the available evidence, say so and list what additional information is needed. From 45db205eb4e69540f074b02c989be676ebf851bd Mon Sep 17 00:00:00 2001 From: Simon Flandergan Date: Sun, 28 Jun 2026 12:29:22 +0200 Subject: [PATCH 26/65] Use neutral repository interfaces in shared workflow skills --- core/agents/skills/workflow-implementation/SKILL.md | 5 +---- .../workflow-planning/plan-document-reviewer-prompt.md | 2 +- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/core/agents/skills/workflow-implementation/SKILL.md b/core/agents/skills/workflow-implementation/SKILL.md index 6e296fa..78249b5 100644 --- a/core/agents/skills/workflow-implementation/SKILL.md +++ b/core/agents/skills/workflow-implementation/SKILL.md @@ -97,10 +97,7 @@ Implementer subagents report one of four statuses. Handle each appropriately: ## Boundaries - The controller agent owns dispatch, model choice, human handoff, push, PR, and finish decisions. -- After final verification, the controller commits all changes, then pushes and opens a PR/MR using the host-appropriate publish skill. Detect host from `git remote get-url origin`: - - GitHub (contains `github.com` or starts with `git@github.com:`) → push with `bash .agents/skills/github-publish/scripts/push-branch.sh`, open a PR with `bash .agents/skills/github-publish/scripts/open-pr.sh` if one does not already exist - - Otherwise → push with `bash .agents/skills/gitlab-publish/scripts/push-branch.sh`, open an MR with `bash .agents/skills/gitlab-publish/scripts/open-mr.sh` if one does not already exist - Never push to 'main'. +- After final verification, the controller commits all changes, then pushes the branch with `git-publish` and opens a change request with `change-request-publish`. Never push to the default branch. - This skill only defines execution discipline and review gates. - Workers follow TDD instructions embedded in the approved plan for behavior changes. - Inline execution is acceptable only when the user explicitly requests it or subagent delegation is genuinely unavailable, but keep the same task/review gates. diff --git a/core/agents/skills/workflow-planning/plan-document-reviewer-prompt.md b/core/agents/skills/workflow-planning/plan-document-reviewer-prompt.md index 403b4b7..bea15da 100644 --- a/core/agents/skills/workflow-planning/plan-document-reviewer-prompt.md +++ b/core/agents/skills/workflow-planning/plan-document-reviewer-prompt.md @@ -42,7 +42,7 @@ OpenCode task tool: |-------|----------------------------------|--------| | Each spec requirement | Exact task/step or "missing" | Covered/Missing | | Each user note | Exact task/step or "missing" | Covered/Missing | - | Each external/GitHub remark included in the prompt | Exact task/step or "missing" | Covered/Missing | + | Each external remark included in the prompt | Exact task/step or "missing" | Covered/Missing | Use the matrix to catch silent drops. Do not include the full matrix in the response unless there is a gap; report gaps as blocking issues. From f174fe3602c5584d0655340b77b7a66799d3aaa0 Mon Sep 17 00:00:00 2001 From: Simon Flandergan Date: Sun, 28 Jun 2026 12:30:50 +0200 Subject: [PATCH 27/65] Use neutral repository interfaces in OpenCode agents --- core/opencode.json | 10 +--------- core/opencode/agents/brainstorm.md | 8 ++------ core/opencode/agents/finish.md | 17 ++++++---------- core/opencode/agents/implement.md | 23 +++++++--------------- core/opencode/agents/planner.md | 8 ++------ core/opencode/agents/review-code.md | 22 +++++++++------------ core/opencode/agents/review-plan.md | 30 +++++++++++------------------ 7 files changed, 38 insertions(+), 80 deletions(-) diff --git a/core/opencode.json b/core/opencode.json index ea4a40e..f37da5d 100644 --- a/core/opencode.json +++ b/core/opencode.json @@ -37,15 +37,7 @@ "*": "ask", "git branch -d *": "deny", "git branch -D *": "deny", - "git worktree remove *": "deny", - "glab mr create *": "ask", - "glab mr list *": "allow", - "glab mr view *": "allow", - "glab mr diff *": "allow", - "glab issue create *": "ask", - "glab issue view *": "allow", - "glab issue list *": "allow", - "glab issue update *": "ask" + "git worktree remove *": "deny" }, "edit": { "*": "allow" diff --git a/core/opencode/agents/brainstorm.md b/core/opencode/agents/brainstorm.md index 8fb5901..7f89811 100644 --- a/core/opencode/agents/brainstorm.md +++ b/core/opencode/agents/brainstorm.md @@ -29,8 +29,7 @@ permission: "git branch -D *": deny "git worktree remove *": deny - "bash .agents/skills/github-publish/scripts/push-branch.sh*": allow - "bash .agents/skills/gitlab-publish/scripts/push-branch.sh*": allow + "bash .agents/skills/git-publish/scripts/push-branch.sh*": allow "ls *": allow "mkdir plans/*": allow @@ -84,9 +83,6 @@ Shell guidance: - Prefer relative workspace paths in shell commands and examples (e.g., `mkdir -p plans/2026-05-25-feature-name`). - Avoid absolute workspace paths in shell commands unless a tool explicitly requires them. -- Publish through the host-appropriate publish skill. Detect host from `git remote get-url origin`: - - GitHub (contains `github.com` or starts with `git@github.com:`) → `bash .agents/skills/github-publish/scripts/push-branch.sh` - - Otherwise → `bash .agents/skills/gitlab-publish/scripts/push-branch.sh` — GitLab is commonly self-hosted - Never hand-roll `git push`. +- Push the branch with `bash .agents/skills/git-publish/scripts/push-branch.sh`. Never hand-roll `git push`. When writing specs, include goal, non-goals, architecture, data flow, testing expectations, rollout or migration notes, and open questions if any remain. diff --git a/core/opencode/agents/finish.md b/core/opencode/agents/finish.md index d724e7a..3663814 100644 --- a/core/opencode/agents/finish.md +++ b/core/opencode/agents/finish.md @@ -47,11 +47,8 @@ permission: "git push origin --tags*": ask "git push origin tag *": ask - "bash .agents/skills/github-publish/scripts/push-branch.sh*": allow - "bash .agents/skills/github-publish/scripts/open-pr.sh*": ask - - "bash .agents/skills/gitlab-publish/scripts/push-branch.sh*": allow - "bash .agents/skills/gitlab-publish/scripts/open-mr.sh*": ask + "bash .agents/skills/git-publish/scripts/push-branch.sh*": allow + "bash .agents/skills/change-request-publish/scripts/open-change-request.sh*": ask task: "*": deny "explore": allow @@ -60,8 +57,8 @@ permission: "workflow-verification": allow "feature-documentation": allow "grill-with-docs": allow - "github-publish": allow - "gitlab-publish": allow + "git-publish": allow + "change-request-publish": allow --- You are the finishing agent. @@ -81,8 +78,6 @@ Finish workflow: 3. Treat the feature doc as durable reference documentation, not a project-status report. 4. Reconcile the domain docs: if implementation or review changed the domain language, or introduced or invalidated a decision, update the relevant `docs/contexts//CONTEXT.md` glossary and add or supersede ADRs under `docs/adr/` before finalizing. This is offered reconciliation, not a full grilling session — use `grill-with-docs` only when a divergence genuinely needs interrogating. Keep `CONTEXT.md` a glossary only. 5. Remove both `plans/YYYY-MM-DD-feature-name/spec.md` and `plans/YYYY-MM-DD-feature-name/plan.md` after the feature doc is written. Use `git rm` for tracked plan files. Use plain `rm` only for untracked paths. -6. Commit the feature doc and cleanup, then publish. Detect host from `git remote get-url origin`: - - GitHub (contains `github.com` or starts with `git@github.com:`) → push with `bash .agents/skills/github-publish/scripts/push-branch.sh`, open a PR with `bash .agents/skills/github-publish/scripts/open-pr.sh` if needed - - Otherwise → push with `bash .agents/skills/gitlab-publish/scripts/push-branch.sh`, open an MR with `bash .agents/skills/gitlab-publish/scripts/open-mr.sh` if needed +6. Commit the feature doc and cleanup, then publish. Push the branch with `bash .agents/skills/git-publish/scripts/push-branch.sh`. To open a change request, use `bash .agents/skills/change-request-publish/scripts/open-change-request.sh` if needed. -Push automatically only through the host-appropriate publish skill. Never hand-roll `git push`, push to `main`, force-push, delete remote refs, push tags, or push arbitrary refspecs without explicit approval. Do not create PRs/MRs manually, amend commits, delete branches, close comments, or remove worktrees. +Push automatically only through the publish skill. Never hand-roll `git push`, push to `main`, force-push, delete remote refs, push tags, or push arbitrary refspecs without explicit approval. Do not create change requests manually, amend commits, delete branches, close comments, or remove worktrees. diff --git a/core/opencode/agents/implement.md b/core/opencode/agents/implement.md index 540a407..d1a7454 100644 --- a/core/opencode/agents/implement.md +++ b/core/opencode/agents/implement.md @@ -54,11 +54,8 @@ permission: "git push origin --tags*": ask "git push origin tag *": ask - "bash .agents/skills/github-publish/scripts/push-branch.sh*": allow - "bash .agents/skills/github-publish/scripts/open-pr.sh*": ask - - "bash .agents/skills/gitlab-publish/scripts/push-branch.sh*": allow - "bash .agents/skills/gitlab-publish/scripts/open-mr.sh*": ask + "bash .agents/skills/git-publish/scripts/push-branch.sh*": allow + "bash .agents/skills/change-request-publish/scripts/open-change-request.sh*": ask "cat *": allow "diff *": allow @@ -91,8 +88,8 @@ permission: "*": deny "workflow-implementation": allow "workflow-verification": allow - "github-publish": allow - "gitlab-publish": allow + "git-publish": allow + "change-request-publish": allow --- You are the implementation controller. @@ -104,11 +101,8 @@ Execution rules: - Never implement on `main`; create or ask for a scoped branch if needed. - Prefer `git mv` for moves and renames of tracked paths. Use plain `mv` only for untracked paths or operations git cannot express cleanly. - Prefer `git rm` for removals of tracked paths. Use plain `rm` only for untracked paths. -- Publish through the host-appropriate skill. Detect host from `git remote get-url origin`: - - GitHub (contains `github.com` or starts with `git@github.com:`) → use `github-publish` - - Otherwise → use `gitlab-publish` - Run `push-branch.sh` to push, which refuses `main`. Never hand-roll `git push`: `git push origin $(...)` silently pushes `main` when the current branch is `main`. -- Open a pull/merge request with `open-pr.sh` (GitHub) or `open-mr.sh` (GitLab) — both skip creation when one already exists for the current branch. +- Push the branch with `bash .agents/skills/git-publish/scripts/push-branch.sh`, which refuses `main`. Never hand-roll `git push`: `git push origin $(...)` silently pushes `main` when the current branch is `main`. +- To open a change request, use `bash .agents/skills/change-request-publish/scripts/open-change-request.sh` — it skips creation when one already exists for the current branch. - **Default behavior:** Execute the plan task-by-task by dispatching a fresh `@implement-task` worker for each task. This is the standard workflow — do not deviate unless the user explicitly requests inline implementation. - **Inline implementation:** Acceptable only when the user explicitly asks you to implement directly rather than delegating. When executing inline, apply the same task/review gates as delegated workers. - **Controller duties:** Your primary role is orchestration — dispatch tasks, package context for workers, review worker reports and diffs, enforce spec compliance and code quality review gates, and run verification before any completion claim. @@ -120,9 +114,6 @@ Execution rules: - Stop and ask for feedback only when the same task fails more than 3 times, the plan conflicts with code reality, or an architectural decision is required. - If a task is too complex or requires an architectural decision, report the blocker and recommend human escalation. - Run targeted verification while iterating and the required final verification before claiming completion. -- After final verification, commit all changes and publish. Detect host from `git remote get-url origin`: - - GitHub (contains `github.com` or starts with `git@github.com:`) → push with `bash .agents/skills/github-publish/scripts/push-branch.sh`, open a PR with `bash .agents/skills/github-publish/scripts/open-pr.sh` (no-ops when a PR already exists) - - Otherwise → push with `bash .agents/skills/gitlab-publish/scripts/push-branch.sh`, open an MR with `bash .agents/skills/gitlab-publish/scripts/open-mr.sh` (no-ops when an MR already exists) - The push script refuses `main`. +- After final verification, commit all changes and publish. Push the branch with `bash .agents/skills/git-publish/scripts/push-branch.sh`, then open a change request with `bash .agents/skills/change-request-publish/scripts/open-change-request.sh` (no-ops when one already exists for the current branch). The push script refuses `main`. Use `workflow-verification` before any completion claim. Do not say work is complete, fixed, or passing unless the relevant commands have just run successfully. diff --git a/core/opencode/agents/planner.md b/core/opencode/agents/planner.md index 43b8624..71c8ee4 100644 --- a/core/opencode/agents/planner.md +++ b/core/opencode/agents/planner.md @@ -26,8 +26,7 @@ permission: "git commit *": allow "git worktree remove *": deny - "bash .agents/skills/github-publish/scripts/push-branch.sh*": allow - "bash .agents/skills/gitlab-publish/scripts/push-branch.sh*": allow + "bash .agents/skills/git-publish/scripts/push-branch.sh*": allow "grep *": allow "ls *": allow @@ -78,10 +77,7 @@ Shell guidance: - Prefer relative workspace paths in shell commands and examples (e.g., `mkdir -p plans/2026-05-25-feature-name`). - Avoid absolute workspace paths in shell commands unless a tool explicitly requires them. -- Publish through the host-appropriate publish skill. Detect host from `git remote get-url origin`: - - GitHub (contains `github.com` or starts with `git@github.com:`) → `bash .agents/skills/github-publish/scripts/push-branch.sh` - - Otherwise → `bash .agents/skills/gitlab-publish/scripts/push-branch.sh` — GitLab is commonly self-hosted - Never hand-roll `git push`. +- Push the branch with `bash .agents/skills/git-publish/scripts/push-branch.sh`. Never hand-roll `git push`. Do not invoke brainstorming automatically. If requirements are unclear enough that planning would be speculative, ask the user whether to switch to `@brainstorm`. diff --git a/core/opencode/agents/review-code.md b/core/opencode/agents/review-code.md index 4b8fed1..dc53eed 100644 --- a/core/opencode/agents/review-code.md +++ b/core/opencode/agents/review-code.md @@ -26,28 +26,24 @@ permission: "git push *": ask - "bash .agents/skills/github-pr-comments/scripts/fetch-pr-comments.sh *": allow - 'bash ".agents/skills/github-pr-comments/scripts/fetch-pr-comments.sh" *': allow - "bash .agents/skills/github-pr-comments/scripts/reply-to-pr-comment.sh *": ask - 'bash ".agents/skills/github-pr-comments/scripts/reply-to-pr-comment.sh" *': ask - - "bash .agents/skills/gitlab-mr-comments/scripts/fetch-mr-comments.sh*": allow - "bash .agents/skills/gitlab-mr-comments/scripts/reply-to-mr-comment.sh*": ask + "bash .agents/skills/change-request-comments/scripts/fetch-comments.sh *": allow + 'bash ".agents/skills/change-request-comments/scripts/fetch-comments.sh" *': allow + "bash .agents/skills/change-request-comments/scripts/reply-to-comment.sh *": ask + 'bash ".agents/skills/change-request-comments/scripts/reply-to-comment.sh" *': ask task: "*": deny "explore": allow "implement-task": allow skill: "*": deny - "github-pr-comments": allow - "gitlab-mr-comments": allow + "change-request-comments": allow --- You are the code review agent. Load `docs/agents/review-code.md` before reviewing and follow its document list exactly. -Use `github-pr-comments` for GitHub remotes and `gitlab-mr-comments` for non-GitHub (commonly self-hosted GitLab) remotes when reading and drafting replies to PR/MR comments. +Use `change-request-comments` when reading and drafting replies to change request comments. Review priorities: @@ -70,7 +66,7 @@ Review priorities: Use this standard review-code workflow unless the user explicitly requests a different scope: -1. Read open PR comments first by using the `github-pr-comments` skill. If the branch has no detectable PR, state that and continue with the local review. +1. Read open change request comments first by using the `change-request-comments` skill. If the branch has no detectable change request, state that and continue with the local review. 2. Identify the plan/spec under review. If multiple candidate plans exist and the user did not state which one to use, ask before continuing the plan-conformance part of the review. 3. Review the code yourself against architecture, coding guidelines, testing guidance, logging guidance, the approved plan/spec, documented domain language, ADRs, and any area docs loaded from `docs/agents/review-code.md`. 4. Combine PR comments, user notes, external notes, and your own findings into one deduplicated list of actionable issues. @@ -78,7 +74,7 @@ Use this standard review-code workflow unless the user explicitly requests a dif 6. After user approval, write a fix/refactoring plan under `plans/**` when the fixes need planning or exceed trivial review-scoped changes. Do not adapt an unrelated existing implementation plan for new review findings. Write review finding plans **next to the original plan** in the same directory (e.g. `plans//review-findings.md`). Do not create new date-prefixed folders for review findings. 7. If the user approves dispatching `implement-task` for trivial review-scoped fixes, dispatch focused tasks only after presenting the exact fix instructions. 8. After plan updates or implement-task results, self-review every tracked remark and finding. Map each item to the finding, changed file, fix-plan section, or intentional unresolved status. -9. Draft exact GitHub replies for resolved PR comments and ask for explicit approval before posting. Approval to dispatch fixes, write a fix plan, or edit files does not authorize posting GitHub comments. +9. Draft exact replies for resolved change request comments and ask for explicit approval before posting. Approval to dispatch fixes, write a fix plan, or edit files does not authorize posting comments. Output findings first, ordered by severity, with file and line references. If no findings are found, say so and note any areas you could not verify from the diff alone. @@ -99,6 +95,6 @@ When escalating, clearly state: 2. Why the issues exceed review-fix scope 3. Which agent (`@planner` or `@brainstorm`) should handle it and why -When reviewing external or GitHub comments, use `github-pr-comments`. Always check open PR comments by default unless the user explicitly says not to. Verify each technical claim before recommending changes. Suggest changes only. Before posting any GitHub issue comment, PR conversation comment, or inline review reply, present the exact draft reply and wait for explicit user approval. Approval to dispatch fixes, write a fix plan, or edit files does not authorize posting GitHub comments. +When reviewing external comments, use `change-request-comments`. Always check open change request comments by default unless the user explicitly says not to. Verify each technical claim before recommending changes. Suggest changes only. Before posting any comment reply, present the exact draft reply and wait for explicit user approval. Approval to dispatch fixes, write a fix plan, or edit files does not authorize posting comments. When fixes are needed (and escalation rules do not apply), dispatch `@implement-task` with the specific fix instructions. Provide the full context: what to change, why, and which files are affected. Do not edit code directly — let implement-task handle the implementation with proper TDD and verification. diff --git a/core/opencode/agents/review-plan.md b/core/opencode/agents/review-plan.md index 74b4cee..500d668 100644 --- a/core/opencode/agents/review-plan.md +++ b/core/opencode/agents/review-plan.md @@ -21,31 +21,26 @@ permission: "git add plans/*": allow "git commit *": allow - "bash .agents/skills/github-publish/scripts/push-branch.sh*": allow - "bash .agents/skills/gitlab-publish/scripts/push-branch.sh*": allow + "bash .agents/skills/git-publish/scripts/push-branch.sh*": allow "git worktree remove *": deny - "bash .agents/skills/github-pr-comments/scripts/fetch-pr-comments.sh *": allow - 'bash ".agents/skills/github-pr-comments/scripts/fetch-pr-comments.sh" *': allow - "bash .agents/skills/github-pr-comments/scripts/reply-to-pr-comment.sh *": allow - 'bash ".agents/skills/github-pr-comments/scripts/reply-to-pr-comment.sh" *': allow - - "bash .agents/skills/gitlab-mr-comments/scripts/fetch-mr-comments.sh*": allow - "bash .agents/skills/gitlab-mr-comments/scripts/reply-to-mr-comment.sh*": ask + "bash .agents/skills/change-request-comments/scripts/fetch-comments.sh *": allow + 'bash ".agents/skills/change-request-comments/scripts/fetch-comments.sh" *': allow + "bash .agents/skills/change-request-comments/scripts/reply-to-comment.sh *": ask + 'bash ".agents/skills/change-request-comments/scripts/reply-to-comment.sh" *': ask task: "*": deny "explore": allow skill: "*": deny - "github-pr-comments": allow - "gitlab-mr-comments": allow + "change-request-comments": allow --- You are the spec and plan review agent. Load `docs/agents/review-plan.md` before every review and follow its document list exactly. -Use `github-pr-comments` for GitHub remotes and `gitlab-mr-comments` for non-GitHub (commonly self-hosted GitLab) remotes when reading and drafting replies to PR/MR comments. +Use `change-request-comments` when reading and drafting replies to change request comments. Review goals: @@ -66,17 +61,14 @@ Review goals: Use this standard review-plan workflow unless the user explicitly requests a different scope: -1. Read open PR comments first by using the `github-pr-comments` skill. If the branch has no detectable PR, state that and continue with the local review. +1. Read open change request comments first by using the `change-request-comments` skill. If the branch has no detectable change request, state that and continue with the local review. 2. Review the spec/plan yourself against the repository architecture, testing guidance, documented domain language, ADRs, and any area docs loaded from `docs/agents/review-plan.md`. 3. Combine PR comments, user notes, external notes, and your own findings into one deduplicated list of actionable issues. 4. Present suggested fixes as blocking issues and advisory suggestions. Do not edit `plans/**` yet. 5. Wait for explicit user approval before editing the spec or plan. 6. After approved edits, self-review every tracked remark and finding. Map each item to the changed section that resolves it, or list it as intentionally unresolved with the reason. -7. Draft exact GitHub replies for resolved PR comments and ask for explicit approval before posting. Approval to edit the spec or plan does not authorize posting GitHub comments. +7. Draft exact replies for resolved change request comments and ask for explicit approval before posting. Approval to edit the spec or plan does not authorize posting comments. -When reviewing external or GitHub comments, use `github-pr-comments`. Always check open PR comments by default unless the user explicitly says not to. Verify each technical claim before recommending changes. Suggest changes only. Before posting any GitHub issue comment, PR conversation comment, or inline review reply, present the exact draft reply and wait for explicit user approval. Approval to edit `plans/**` does not authorize posting GitHub comments. +When reviewing external comments, use `change-request-comments`. Always check open change request comments by default unless the user explicitly says not to. Verify each technical claim before recommending changes. Suggest changes only. Before posting any comment reply, present the exact draft reply and wait for explicit user approval. Approval to edit `plans/**` does not authorize posting comments. -Publish through the host-appropriate publish skill. Detect host from `git remote get-url origin`: -- GitHub (contains `github.com` or starts with `git@github.com:`) → `bash .agents/skills/github-publish/scripts/push-branch.sh` -- Otherwise → `bash .agents/skills/gitlab-publish/scripts/push-branch.sh` — GitLab is commonly self-hosted -Never hand-roll `git push`. +Push the branch with `bash .agents/skills/git-publish/scripts/push-branch.sh`. Never hand-roll `git push`. From 5020d3fddf3609cad9a811b8cb347a7beb18ae7f Mon Sep 17 00:00:00 2001 From: Simon Flandergan Date: Sun, 28 Jun 2026 12:31:51 +0200 Subject: [PATCH 28/65] Use neutral repository interfaces in Claude workflow skills --- core/claude/skills/brainstorm/SKILL.md | 6 ++--- core/claude/skills/finish/SKILL.md | 6 ++--- core/claude/skills/implement/SKILL.md | 8 +++--- core/claude/skills/planner/SKILL.md | 10 +++---- core/claude/skills/review-code/SKILL.md | 33 +++++++++++------------ core/claude/skills/review-plan/SKILL.md | 36 ++++++++++++------------- 6 files changed, 47 insertions(+), 52 deletions(-) diff --git a/core/claude/skills/brainstorm/SKILL.md b/core/claude/skills/brainstorm/SKILL.md index 956fed5..59dc64c 100644 --- a/core/claude/skills/brainstorm/SKILL.md +++ b/core/claude/skills/brainstorm/SKILL.md @@ -31,9 +31,9 @@ Use `grill-with-docs` when the brainstorm needs domain grilling. - Prefer relative workspace paths in commands and examples (e.g. `mkdir -p plans/2026-05-30-feature-name`). Avoid absolute workspace paths unless a tool requires them. -- Publish through the host-appropriate publish skill. Detect host from `git remote get-url origin`: - - GitHub (contains `github.com` or starts with `git@github.com:`) → `bash .claude/skills/github-publish/scripts/push-branch.sh` - - Otherwise → `bash .claude/skills/gitlab-publish/scripts/push-branch.sh` — GitLab is commonly self-hosted +- Publish through the neutral git-publish skill: + - Push the current branch with `bash .claude/skills/git-publish/scripts/push-branch.sh`. + - Open a change request with `bash .claude/skills/change-request-publish/scripts/open-change-request.sh` when needed. Never hand-roll `git push`. ## Stop conditions diff --git a/core/claude/skills/finish/SKILL.md b/core/claude/skills/finish/SKILL.md index 9af210e..fe124aa 100644 --- a/core/claude/skills/finish/SKILL.md +++ b/core/claude/skills/finish/SKILL.md @@ -47,10 +47,8 @@ explore subagent with a focused question. feature doc is written and the user approves cleanup. Use `git rm` for tracked files; use plain `rm` only for untracked paths. 5. **Commit and push.** Commit the feature doc and cleanup when the user requests it, - then push using the host-appropriate publish skill. Detect host from - `git remote get-url origin`: - - GitHub (contains `github.com` or starts with `git@github.com:`) → `bash .claude/skills/github-publish/scripts/push-branch.sh` - - Otherwise → `bash .claude/skills/gitlab-publish/scripts/push-branch.sh` — GitLab is commonly self-hosted + then push using the neutral git-publish skill: + - Push the current branch with `bash .claude/skills/git-publish/scripts/push-branch.sh`. ## Push boundaries diff --git a/core/claude/skills/implement/SKILL.md b/core/claude/skills/implement/SKILL.md index f98d44d..e616936 100644 --- a/core/claude/skills/implement/SKILL.md +++ b/core/claude/skills/implement/SKILL.md @@ -6,7 +6,7 @@ disable-model-invocation: true --- You are the implementation controller for this repository. -This is the Claude Code half of implementation; OpenCode (`@implement`) is the equivalent controller on that harness. +This is the Claude Code implementation controller. OpenCode has an equivalent controller agent. Pick one harness per branch — do not run both controllers over the same plan. Approved plan (if provided): $ARGUMENTS @@ -46,9 +46,7 @@ Run targeted verification while iterating and the required final verification be ## Finishing -After final verification, commit all changes and push the branch using the host-appropriate publish skill. -Detect host from `git remote get-url origin`: -- GitHub (contains `github.com` or starts with `git@github.com:`) → `bash .claude/skills/github-publish/scripts/push-branch.sh` then `bash .claude/skills/github-publish/scripts/open-pr.sh` -- Otherwise → `bash .claude/skills/gitlab-publish/scripts/push-branch.sh` then `bash .claude/skills/gitlab-publish/scripts/open-mr.sh` — GitLab is commonly self-hosted +After final verification, commit all changes and push the branch using the neutral git-publish skill. +Open a change request with `bash .claude/skills/change-request-publish/scripts/open-change-request.sh` when needed. The publish scripts refuse `main`/`master` and skip creation when a PR/MR already exists for the branch. diff --git a/core/claude/skills/planner/SKILL.md b/core/claude/skills/planner/SKILL.md index 3398221..2798cba 100644 --- a/core/claude/skills/planner/SKILL.md +++ b/core/claude/skills/planner/SKILL.md @@ -1,6 +1,6 @@ --- name: planner -description: Turns an approved spec or clear requirements into a reviewable, task-by-task plan.md with TDD steps, ready for OpenCode handoff. +description: Turns an approved spec or clear requirements into a reviewable, task-by-task plan.md with TDD steps, ready for implementation handoff. argument-hint: [path to spec or requirements] disable-model-invocation: true --- @@ -66,9 +66,9 @@ inlining them here. - Prefer relative workspace paths in commands and examples (e.g. `mkdir -p plans/2026-05-30-feature-name`). Avoid absolute workspace paths unless a tool requires them. -- Publish through the host-appropriate publish skill. Detect host from `git remote get-url origin`: - - GitHub (contains `github.com` or starts with `git@github.com:`) → `bash .claude/skills/github-publish/scripts/push-branch.sh` - - Otherwise → `bash .claude/skills/gitlab-publish/scripts/push-branch.sh` — GitLab is commonly self-hosted +- Publish through the neutral git-publish skill: + - Push the current branch with `bash .claude/skills/git-publish/scripts/push-branch.sh`. + - Open a change request with `bash .claude/skills/change-request-publish/scripts/open-change-request.sh` when needed. Never hand-roll `git push`. ## Stop conditions @@ -77,4 +77,4 @@ inlining them here. spec/plan markdown only when the user asks for committed workflow artifacts. - After the plan is written, **stop**. Optionally suggest `/review-plan` before handoff. - Implementation can run in either harness: Claude Code (`/implement`) or OpenCode - (`@implement`). Pick one per branch. Suggest the user's preferred harness. + (the implement agent). Pick one per branch. Suggest the user's preferred harness. diff --git a/core/claude/skills/review-code/SKILL.md b/core/claude/skills/review-code/SKILL.md index 9c69be3..fa67ec8 100644 --- a/core/claude/skills/review-code/SKILL.md +++ b/core/claude/skills/review-code/SKILL.md @@ -15,7 +15,7 @@ Scope (if provided): $ARGUMENTS Read `docs/agents/review-code.md` before reviewing and follow its document list exactly. -Use `github-pr-comments` for GitHub remotes and `gitlab-mr-comments` for non-GitHub (commonly self-hosted GitLab) remotes when reading and drafting replies to PR/MR comments. +Use `change-request-comments` for reading and drafting replies to change-request comments. ## Review priorities @@ -53,8 +53,8 @@ whether it is a finding. Use this standard review-code workflow unless the user explicitly requests a different scope: -1. Read open PR comments first by using the `github-pr-comments` skill. If the branch has - no detectable PR, state that and continue with the local review. +1. Read open change-request comments first by using the `change-request-comments` skill. If the branch has + no detectable change request, state that and continue with the local review. 2. Identify the plan/spec under review. If multiple candidate plans exist and the user did not state which one to use, ask before continuing the plan-conformance part of the review. @@ -70,16 +70,16 @@ Use this standard review-code workflow unless the user explicitly requests a dif implementation plan for new review findings. Write review finding plans **next to the original plan** in the same directory (e.g. `plans//review-findings.md`). Do not create new date-prefixed folders for review findings. -7. If the user approves dispatching `@implement-task` for trivial review-scoped fixes, +7. If the user approves dispatching implementation tasks for trivial review-scoped fixes, dispatch focused tasks only after presenting the exact fix instructions. In Claude - Code, prefer writing the fix-plan handoff document and handing it to OpenCode - (`@implement` / `@implement-task`) for TDD implementation. + Code, prefer writing the fix-plan handoff document and handing it to the + OpenCode implement agent for TDD implementation. 8. After plan updates or implement-task results, self-review every tracked remark and finding. Map each item to the finding, changed file, fix-plan section, or intentional unresolved status. -9. Draft exact GitHub replies for resolved PR comments and ask for explicit approval +9. Draft exact replies for resolved change-request comments and ask for explicit approval before posting. Approval to dispatch fixes, write a fix plan, or edit files does not - authorize posting GitHub comments. + authorize posting change-request comments. Output findings first, ordered by severity, with file and line references. If there are no findings, say so and note any areas you could not verify from the diff alone. @@ -87,8 +87,8 @@ no findings, say so and note any areas you could not verify from the diff alone. ## Verification Your job is to review and report findings. Verification (lint, typecheck, test, build) is -the implement agent's responsibility — `@implement-task` runs targeted verification per -task, and `@implement` runs final verification after all tasks complete. Report +the implement agent's responsibility — the implement agent runs targeted verification per +task, and the implement controller runs final verification after all tasks complete. Report unverified areas as residual risks in your findings; do not run verification commands yourself. @@ -115,12 +115,11 @@ Before recommending fixes, evaluate scope: When escalating, state: (1) the number and severity of findings, (2) why they exceed review-fix scope, (3) which command should handle it and why. -## External / GitHub comments +## External / change-request comments -When reviewing external or GitHub PR feedback, use the `github-pr-comments` skill. Always -check open PR comments by default unless the user explicitly says not to. Verify each +When reviewing external change-request feedback, use the `change-request-comments` skill. Always +check open change-request comments by default unless the user explicitly says not to. Verify each technical claim against current code before recommending a change. Suggest changes only. -Before posting any GitHub issue comment, PR conversation comment, or inline review -reply, present the exact draft reply and wait for explicit user approval. Approval to -dispatch fixes, write a fix plan, or edit files does not authorize posting GitHub -comments. +Before posting any change-request comment, present the exact draft reply and wait for explicit +user approval. Approval to dispatch fixes, write a fix plan, or edit files does not authorize +posting change-request comments. diff --git a/core/claude/skills/review-plan/SKILL.md b/core/claude/skills/review-plan/SKILL.md index 671d81f..4a1888f 100644 --- a/core/claude/skills/review-plan/SKILL.md +++ b/core/claude/skills/review-plan/SKILL.md @@ -1,12 +1,12 @@ --- name: review-plan -description: Reviews a spec or plan against architecture, testing rules, and user notes, then finalizes it into the OpenCode handoff document. +description: Reviews a spec or plan against architecture, testing rules, and user notes, then finalizes it into the implementation handoff document. argument-hint: [path to spec or plan] disable-model-invocation: true --- You are the spec and plan review agent for this repository. You review the spec/plan, then -**finalize it into the hand-off document** that OpenCode's implementer (`@implement`) will +**finalize it into the hand-off document** that the implementer will execute. Spec or plan to review (if provided): $ARGUMENTS @@ -16,7 +16,7 @@ Spec or plan to review (if provided): $ARGUMENTS Read `docs/agents/review-plan.md` before every review and follow its document list exactly. -Use `github-pr-comments` for GitHub remotes and `gitlab-mr-comments` for non-GitHub (commonly self-hosted GitLab) remotes when reading and drafting replies to PR/MR comments. +Use `change-request-comments` for reading and drafting replies to change-request comments. ## Review goals @@ -47,8 +47,8 @@ executable. Use this standard review-plan workflow unless the user explicitly requests a different scope: -1. Read open PR comments first by using the `github-pr-comments` skill. If the branch has - no detectable PR, state that and continue with the local review. +1. Read open change-request comments first by using the `change-request-comments` skill. If the branch has + no detectable change request, state that and continue with the local review. 2. Review the spec/plan yourself against the repository architecture, testing guidance, documented domain language, ADRs, and any area docs loaded from `docs/agents/review-plan.md`. @@ -60,9 +60,9 @@ Use this standard review-plan workflow unless the user explicitly requests a dif 6. After approved edits, self-review every tracked remark and finding. Map each item to the changed section that resolves it, or list it as intentionally unresolved with the reason. -7. Draft exact GitHub replies for resolved PR comments and ask for explicit approval - before posting. Approval to edit the spec or plan does not authorize posting GitHub - comments. +7. Draft exact replies for resolved change-request comments and ask for explicit approval + before posting. Approval to edit the spec or plan does not authorize posting + change-request comments. ## Finalizing the handoff document @@ -75,18 +75,18 @@ document. The gate is approval, not capability: 3. Apply the approved changes to `plans//plan.md` (and `spec.md` if needed) so the plan is unambiguous and executable. Do not touch application code, tests, or config — only the `plans/**` artifacts. -4. Report the finalized plan path and confirm it is ready for OpenCode handoff. +4. Report the finalized plan path and confirm it is ready for implementation handoff. -Publish through the host-appropriate publish skill. Detect host from `git remote get-url origin`: -- GitHub (contains `github.com` or starts with `git@github.com:`) → `bash .claude/skills/github-publish/scripts/push-branch.sh` -- Otherwise → `bash .claude/skills/gitlab-publish/scripts/push-branch.sh` — GitLab is commonly self-hosted +Publish through the neutral git-publish skill: +- Push the current branch with `bash .claude/skills/git-publish/scripts/push-branch.sh`. +- Open a change request with `bash .claude/skills/change-request-publish/scripts/open-change-request.sh` when needed. Never hand-roll `git push`. -## External / GitHub comments +## External / change-request comments -When reviewing external or GitHub PR feedback, use the `github-pr-comments` skill. Always -check open PR comments by default unless the user explicitly says not to. Verify each +When reviewing external change-request feedback, use the `change-request-comments` skill. Always +check open change-request comments by default unless the user explicitly says not to. Verify each technical claim against the current code before recommending a change. Suggest changes -only. Before posting any GitHub issue comment, PR conversation comment, or inline review -reply, present the exact draft reply and wait for explicit user approval. Approval to -edit `plans/**` does not authorize posting GitHub comments. +only. Before posting any change-request comment, present the exact draft reply and wait +for explicit user approval. Approval to edit `plans/**` does not authorize posting +change-request comments. From 3c9a1d05f22ec2a9aced83555046727ba1c81374 Mon Sep 17 00:00:00 2001 From: Simon Flandergan Date: Sun, 28 Jun 2026 12:33:38 +0200 Subject: [PATCH 29/65] Update permissions for neutral repository skills --- core/claude/settings.json | 28 ++++++++-------------------- 1 file changed, 8 insertions(+), 20 deletions(-) diff --git a/core/claude/settings.json b/core/claude/settings.json index a724baa..36d3f1d 100644 --- a/core/claude/settings.json +++ b/core/claude/settings.json @@ -42,38 +42,26 @@ "Bash(which:*)", "Bash(mkdir:*)", - "Bash(bash .claude/skills/github-pr-comments/scripts/fetch-pr-comments.sh:*)", + "Bash(bash .claude/skills/git-publish/scripts/push-branch.sh:*)", + "Bash(bash .claude/skills/change-request-comments/scripts/fetch-comments.sh:*)", "Bash(bash .claude/skills/issue-tracker/scripts/create-issue.sh:*)", + "Bash(bash .claude/skills/issue-tracker/scripts/update-issue.sh:*)", "Bash(bash .claude/skills/issue-tracker/scripts/find-duplicate-issues.sh:*)", "Bash(gh issue list:*)", "Bash(gh issue view:*)", "Bash(gh search issues:*)", - - "Bash(bash .claude/skills/github-publish/scripts/push-branch.sh:*)", - "Bash(bash .claude/skills/gitlab-publish/scripts/push-branch.sh:*)", - "Bash(bash .claude/skills/gitlab-mr-comments/scripts/fetch-mr-comments.sh:*)", - "Bash(glab mr view:*)", - "Bash(glab mr diff:*)", - "Bash(glab mr list:*)", - "Bash(glab issue view:*)", - "Bash(glab issue list:*)" + "Bash(glab issue list:*)", + "Bash(glab issue view:*)" ], "ask": [ "Bash(git push:*)", "Bash(git push --force:*)", "Bash(git push -f:*)", - "Bash(gh pr create:*)", "Bash(rm:*)", "Bash(rm -rf:*)", - "Bash(bash .claude/skills/github-pr-comments/scripts/reply-to-pr-comment.sh:*)", - "Bash(bash .claude/skills/issue-tracker/scripts/update-issue.sh:*)", - "Bash(bash .claude/skills/github-publish/scripts/open-pr.sh:*)", - "Bash(bash .claude/skills/gitlab-publish/scripts/open-mr.sh:*)", - "Bash(bash .claude/skills/gitlab-mr-comments/scripts/reply-to-mr-comment.sh:*)", - "Bash(glab mr create:*)", - "Bash(glab mr note create:*)", - "Bash(glab issue create:*)", - "Bash(glab issue update:*)" + "Bash(bash .claude/skills/change-request-publish/scripts/open-change-request.sh:*)", + "Bash(bash .claude/skills/change-request-comments/scripts/reply-to-comment.sh:*)", + "Bash(bash .claude/skills/issue-tracker/scripts/update-issue.sh:*)" ], "deny": [ "Bash(git branch -d:*)", From d7570dba9f1186cac7c53551718a217c9173c6db Mon Sep 17 00:00:00 2001 From: Simon Flandergan Date: Sun, 28 Jun 2026 12:33:39 +0200 Subject: [PATCH 30/65] Document neutral repository skills in README and role docs --- README.md | 10 ++++++---- core/docs/agents/agent-workflow-extension.md | 5 +++-- core/docs/agents/review-code.md | 5 ++--- core/docs/agents/review-plan.md | 3 +-- 4 files changed, 12 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 8185833..528a11b 100644 --- a/README.md +++ b/README.md @@ -101,7 +101,7 @@ Under `.claude/skills/` (all marked `disable-model-invocation: true`): Under `.agents/skills/`: -`grill-with-docs`, `workflow-bug-analysis`, `workflow-brainstorming`, `workflow-planning`, `workflow-implementation`, `workflow-verification`, `feature-documentation`, `github-publish`, `github-pr-comments`, `gitlab-publish`, `gitlab-mr-comments` +`grill-with-docs`, `workflow-bug-analysis`, `workflow-brainstorming`, `workflow-planning`, `workflow-implementation`, `workflow-verification`, `feature-documentation`, `git-publish`, `change-request-publish`, `change-request-comments`, `issue-tracker`, `github-pr-comments`, `gitlab-mr-comments` ### DDD Docs @@ -136,9 +136,11 @@ The workflow entry skills are real directories. The authored skills are symlinke | `workflow-planning` | `../../.agents/skills/workflow-planning` | | `workflow-verification` | `../../.agents/skills/workflow-verification` | | `feature-documentation` | `../../.agents/skills/feature-documentation` | +| `git-publish` | `../../.agents/skills/git-publish` | +| `change-request-publish` | `../../.agents/skills/change-request-publish` | +| `change-request-comments` | `../../.agents/skills/change-request-comments` | +| `issue-tracker` | `../../.agents/skills/issue-tracker` | | `github-pr-comments` | `../../.agents/skills/github-pr-comments` | -| `github-publish` | `../../.agents/skills/github-publish` | -| `gitlab-publish` | `../../.agents/skills/gitlab-publish` | | `gitlab-mr-comments` | `../../.agents/skills/gitlab-mr-comments` | Each symlinked skill has `user-invocable: false` in its `SKILL.md` frontmatter so it stays hidden from Claude Code's user-facing skill list. @@ -165,7 +167,7 @@ The diagram above maps the full cycle from brainstorming a feature through to sh | # | Step | Invocation | |---|---|---| | 7 | **Implement task-by-task** — dispatch one worker per plan task, verify, and commit. | Claude `/implement` or OpenCode `@implement` (controller) which spawns implement-task workers. Pick one harness per branch. | -| 8 | **Human comments code** — review the diff and leave inline comments or GitHub review notes. | Human checkpoint (no agent invocation). | +| 8 | **Human comments code** — review the diff and leave inline comments or change-request review notes. | Human checkpoint (no agent invocation). | | 9 | **Review code** — analyze review feedback and determine required changes. | OpenCode `@review-code` or Claude `/review-code`. | | 10 | **Review / Remark plan** — if code review surfaces scope changes, update the plan and loop back to step 7. Repeat until the plan is sound and complete. | OpenCode `@planner` or Claude `/planner` to revise; then re-enter implementation at step 7. | | 11 | **Finish** — write summary and feature documentation, reconcile durable docs (ADRs, context maps, etc.). | OpenCode `@finish` or Claude `/finish`. | diff --git a/core/docs/agents/agent-workflow-extension.md b/core/docs/agents/agent-workflow-extension.md index 405ea77..f0c1ffe 100644 --- a/core/docs/agents/agent-workflow-extension.md +++ b/core/docs/agents/agent-workflow-extension.md @@ -9,9 +9,10 @@ Use this guide when changing coding assistant workflows, agents, or reusable ski - `.claude/skills/*/SKILL.md` files define Claude skill behavior for the matching workflow. - `.agents/skills/*` files provide reusable mechanics shared by workflows. They may describe how to use bundled scripts or helpers, but they should not own role-level orchestration for review-plan, review-code, planner, implement, or finish workflows. -## GitHub PR comment workflow boundary +## Change-request comment workflow boundary -- The `github-pr-comments` skill owns reading PR comments, classifying comment target types, obtaining exact IDs, and posting approved replies through project scripts. +- The `change-request-comments` skill owns reading change-request comments, classifying comment target types, obtaining exact IDs, and posting approved replies through project scripts. +- Provider-specific mechanics (`github-pr-comments`, `gitlab-mr-comments`, `gh`, `glab`) belong only in provider skills or neutral integration skills, never in generic workflow skills or agent instructions. - Review agents own deciding what the comments mean, validating technical claims, combining them with independent review findings, suggesting fixes, and requesting approval before edits or replies. ## Default placement rules diff --git a/core/docs/agents/review-code.md b/core/docs/agents/review-code.md index e242316..fe0ecb7 100644 --- a/core/docs/agents/review-code.md +++ b/core/docs/agents/review-code.md @@ -4,15 +4,14 @@ - Approved plan - Approved spec, if present -- Git diff or PR diff under review +- Git diff or change-request diff under review - `docs/CODING_GUIDELINES.md` - `docs/LOGGING.md` - `docs/TESTING.md` - `CONTEXT-MAP.md` and relevant `docs/contexts//CONTEXT.md` glossaries to check domain language; `docs/adr/` for documented decisions - Area docs listed below when the diff touches that area - `docs/ARCHITECTURE.md` when the change crosses package or ownership boundaries -- `github-pr-comments` skill for reading and drafting replies to GitHub PR feedback -- `gitlab-mr-comments` skill for reading and drafting replies to GitLab MR feedback +- `change-request-comments` skill for reading and drafting replies to change-request feedback ## Area Docs diff --git a/core/docs/agents/review-plan.md b/core/docs/agents/review-plan.md index 363c522..5fa5f54 100644 --- a/core/docs/agents/review-plan.md +++ b/core/docs/agents/review-plan.md @@ -8,8 +8,7 @@ - `docs/TESTING.md` - `CONTEXT-MAP.md` and relevant `docs/contexts//CONTEXT.md` glossaries to check domain language; `docs/adr/` for documented decisions - Area docs listed below when the reviewed work touches that area -- `github-pr-comments` skill for reading and drafting replies to GitHub PR feedback -- `gitlab-mr-comments` skill for reading and drafting replies to GitLab MR feedback +- `change-request-comments` skill for reading and drafting replies to change-request feedback ## Area Docs From 44a9dbe117c6bafeb29af274f524c750aec8ccfb Mon Sep 17 00:00:00 2001 From: Simon Flandergan Date: Sun, 28 Jun 2026 12:38:53 +0200 Subject: [PATCH 31/65] Register neutral repository skills in installers --- scripts/copy.sh | 6 ++++-- scripts/init.sh | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/scripts/copy.sh b/scripts/copy.sh index 9f07bd0..1926b09 100755 --- a/scripts/copy.sh +++ b/scripts/copy.sh @@ -468,9 +468,11 @@ AUTHORED_SKILLS=( workflow-planning workflow-verification feature-documentation + git-publish + change-request-publish + change-request-comments + issue-tracker github-pr-comments - github-publish - gitlab-publish gitlab-mr-comments ) for skill_name in "${AUTHORED_SKILLS[@]}"; do diff --git a/scripts/init.sh b/scripts/init.sh index eda6b18..37ba827 100755 --- a/scripts/init.sh +++ b/scripts/init.sh @@ -237,9 +237,11 @@ AUTHORED_SKILLS=( "workflow-planning" "workflow-verification" "feature-documentation" + "git-publish" + "change-request-publish" + "change-request-comments" + "issue-tracker" "github-pr-comments" - "github-publish" - "gitlab-publish" "gitlab-mr-comments" ) From 209dc7bd7fb8c03aaabb6a10f378d46a5cd49479 Mon Sep 17 00:00:00 2001 From: Simon Flandergan Date: Sun, 28 Jun 2026 12:49:28 +0200 Subject: [PATCH 32/65] Add workflow provider boundary check --- core/opencode/agents/implement.md | 4 -- scripts/check-workflow-boundaries.sh | 58 ++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+), 4 deletions(-) create mode 100755 scripts/check-workflow-boundaries.sh diff --git a/core/opencode/agents/implement.md b/core/opencode/agents/implement.md index d1a7454..374fbe2 100644 --- a/core/opencode/agents/implement.md +++ b/core/opencode/agents/implement.md @@ -7,10 +7,6 @@ permission: bash: "*": ask - "gh pr create *": allow - "gh pr list *": allow - "gh pr view *": allow - "git add *": allow "git branch *": allow "git branch -d *": deny diff --git a/scripts/check-workflow-boundaries.sh b/scripts/check-workflow-boundaries.sh new file mode 100755 index 0000000..c81fa60 --- /dev/null +++ b/scripts/check-workflow-boundaries.sh @@ -0,0 +1,58 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +cd "$ROOT" + +TARGETS=( + core/agents/skills/workflow-* + core/claude/skills + core/opencode/agents +) + +EXCLUDES=( + core/agents/skills/github-* + core/agents/skills/gitlab-* + core/agents/skills/git-publish + core/agents/skills/change-request-publish + core/agents/skills/change-request-comments + core/agents/skills/issue-tracker + scripts/init.sh + scripts/copy.sh + README.md +) + +# Patterns that indicate provider-internal leakage. +# Focus on provider-specific skill names and write operations. +# Read-only CLI commands (gh issue view, glab issue list, etc.) are allowed +# as implementation support for the neutral wrapper scripts. +PATTERNS=( + 'github-publish' + 'gitlab-publish' + 'github-pr-comments' + 'gitlab-mr-comments' + 'open-pr\.sh' + 'open-mr\.sh' + 'fetch-pr-comments\.sh' + 'fetch-mr-comments\.sh' +) + +# Build rg exclude globs +EXCLUDE_ARGS=() +for e in "${EXCLUDES[@]}"; do + EXCLUDE_ARGS+=(--glob="!$e") +done + +FAILED=0 +for pattern in "${PATTERNS[@]}"; do + if rg --line-number --glob='*' "${EXCLUDE_ARGS[@]}" "$pattern" "${TARGETS[@]}"; then + FAILED=1 + fi +done + +if [[ "$FAILED" -ne 0 ]]; then + echo "ERROR: provider-internal references found in generic workflow files." >&2 + exit 1 +fi + +echo "OK: no provider-internal leakage in generic workflow files." From b16140c34929ceda6d33939d5a4b3e79310e1d0a Mon Sep 17 00:00:00 2001 From: Simon Flandergan Date: Sun, 28 Jun 2026 12:52:03 +0200 Subject: [PATCH 33/65] Update publish-branch.sh to use neutral skills --- scripts/publish-branch.sh | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/scripts/publish-branch.sh b/scripts/publish-branch.sh index 0782a51..1ca29a2 100755 --- a/scripts/publish-branch.sh +++ b/scripts/publish-branch.sh @@ -1,7 +1,6 @@ #!/usr/bin/env bash set -euo pipefail -# Compatibility wrapper: this repo's self-maintenance agents still invoke -# scripts/publish-branch.sh. It delegates to the github-publish authored skill. -bash core/agents/skills/github-publish/scripts/push-branch.sh --set-upstream -bash core/agents/skills/github-publish/scripts/open-pr.sh --fill +# Publish the current branch and open a change request if needed. +bash core/agents/skills/git-publish/scripts/push-branch.sh --set-upstream +bash core/agents/skills/change-request-publish/scripts/open-change-request.sh --fill From fc7c9fc2679115b1fbc0dcf7428de02af325760d Mon Sep 17 00:00:00 2001 From: Simon Flandergan Date: Sun, 28 Jun 2026 15:28:13 +0200 Subject: [PATCH 34/65] add plan to fix review remarks --- .../review-findings.md | 344 ++++++++++++++++++ 1 file changed, 344 insertions(+) create mode 100644 plans/2026-06-25-dual-harness-forge/review-findings.md diff --git a/plans/2026-06-25-dual-harness-forge/review-findings.md b/plans/2026-06-25-dual-harness-forge/review-findings.md new file mode 100644 index 0000000..a73fe3d --- /dev/null +++ b/plans/2026-06-25-dual-harness-forge/review-findings.md @@ -0,0 +1,344 @@ +# Review Findings Plan — PR #6 Dual Harness + GitLab Support + +This plan consolidates the current PR comments and local review findings for fixing the remaining issues on `feature/support-claude-implement-and-glab`. + +## Review summary + +### Blocking issues + +1. **Workflow-facing files leak skill internals.** OpenCode agents, Claude skills, and `workflow-bug-analysis` still instruct agents to run `.../skills//scripts/*.sh` directly. These files should name the skill to use, not its internal scripts. +2. **Provider-specific comment skills remain in the downstream install surface.** `github-pr-comments` and `gitlab-mr-comments` are still installed and documented even though PR feedback asks to move that logic behind `change-request-comments`. +3. **`change-request-comments` delegates to provider skill folders.** Its scripts still call `.agents/skills/github-pr-comments/...` and `.agents/skills/gitlab-mr-comments/...`, so removing those folders would break comment workflows unless the implementations move into the neutral skill. +4. **Permission/skill allowlists are inconsistent.** Several agents have script permissions without corresponding skill permissions, and review-code is missing publish capability for review-fix implementation plans. +5. **`AGENTS.md` does not yet encode the “no skill internals in workflow instructions” rule.** This is the root cause called out by the top-level PR comment. + +### Advisory issues + +1. **`core/claude/settings.json` has readability and policy drift.** Permissions should be grouped and `update-issue.sh` should appear in only one permission tier. +2. **`scripts/publish-branch.sh` conflicts with the new neutral skill model.** Decide whether to preserve the repo-local compatibility wrapper required by `AGENTS.md` or update `AGENTS.md` and self-maintenance symlinks. +3. **`scripts/check-workflow-boundaries.sh` catches provider names but not generic skill-internal script paths.** It should prevent both provider leakage and direct internal script leakage. + +## Implementation tasks + +### Task 1 — Add a hard workflow boundary rule to `AGENTS.md` + +**Files** + +- `AGENTS.md` + +**Changes** + +1. Add a section such as `## Skill Boundary Rule` after the symlink model. +2. State that workflow-facing files must instruct agents to use skills by name, for example `git-publish`, `change-request-publish`, `change-request-comments`, and `issue-tracker`. +3. State that workflow-facing files must not expose internal script paths like `.agents/skills//scripts/*.sh` or `.claude/skills//scripts/*.sh` except inside the skill's own `SKILL.md` or scripts. +4. Clarify that agent frontmatter and Claude settings may grant script permissions, but body instructions should stay skill-level. +5. Add provider-boundary language: provider-specific CLI details (`gh`, `glab`, provider comment scripts) belong only in provider/boundary skills, not generic workflow files. + +**Verification** + +```bash +codespell AGENTS.md +``` + +**Commit boundary** + +```text +Document skill boundary rules for workflow instructions +``` + +### Task 2 — Move provider comment implementations into `change-request-comments` + +**Files** + +- `core/agents/skills/change-request-comments/SKILL.md` +- `core/agents/skills/change-request-comments/scripts/fetch-comments.sh` +- `core/agents/skills/change-request-comments/scripts/reply-to-comment.sh` +- `core/agents/skills/github-pr-comments/` (delete from downstream template) +- `core/agents/skills/gitlab-mr-comments/` (delete from downstream template) + +**Changes** + +1. Inline or move the current GitHub PR comment fetch/reply logic into `change-request-comments/scripts/`. +2. Inline or move the current GitLab MR comment fetch/reply logic into `change-request-comments/scripts/`. +3. Keep host detection inside `change-request-comments`; it may call `gh`/`glab` because this skill is the boundary layer. +4. Remove references from `change-request-comments/SKILL.md` that say it delegates to `github-pr-comments` or `gitlab-mr-comments` skill folders. +5. Delete `core/agents/skills/github-pr-comments/` and `core/agents/skills/gitlab-mr-comments/` with `git rm -r` after their logic is represented inside `change-request-comments`. +6. Keep this repo's self-maintenance `.agents/skills/github-pr-comments` only if still needed for this PR review workflow; do not confuse self-maintenance skills with `core/` templates. + +**Verification** + +```bash +bash -n core/agents/skills/change-request-comments/scripts/*.sh +shellcheck core/agents/skills/change-request-comments/scripts/*.sh +rg -n "github-pr-comments|gitlab-mr-comments" core/agents/skills/change-request-comments +``` + +Expected result: no delegation to provider skill folders remains in `change-request-comments`. + +**Commit boundary** + +```text +Move comment provider logic into change-request-comments +``` + +### Task 3 — Remove skill-internal script instructions from workflow-facing files + +**Files** + +- `core/opencode/agents/brainstorm.md` +- `core/opencode/agents/bugfix.md` +- `core/opencode/agents/planner.md` +- `core/opencode/agents/finish.md` +- `core/opencode/agents/implement.md` +- `core/opencode/agents/review-plan.md` +- `core/opencode/agents/review-code.md` +- `core/claude/skills/brainstorm/SKILL.md` +- `core/claude/skills/bugfix/SKILL.md` +- `core/claude/skills/finish/SKILL.md` +- `core/claude/skills/implement/SKILL.md` +- `core/claude/skills/planner/SKILL.md` +- `core/claude/skills/review-plan/SKILL.md` +- `core/claude/skills/review-code/SKILL.md` +- `core/agents/skills/workflow-bug-analysis/SKILL.md` +- `core/agents/skills/workflow-implementation/SKILL.md` + +**Changes** + +1. Replace body text such as ``bash .agents/skills/git-publish/scripts/push-branch.sh`` with skill-level language such as `use git-publish`. +2. Replace body text such as ``bash .claude/skills/change-request-publish/scripts/open-change-request.sh`` with `use change-request-publish`. +3. Replace `issue-tracker/scripts/create-issue.sh`, `update-issue.sh`, and `find-duplicate-issues.sh` instructions with `use issue-tracker to check duplicates, create tracker issues, and update tracker issues`. +4. In `workflow-implementation/SKILL.md`, keep the boundary concise: after verification, commit, then use `git-publish` and `change-request-publish`; do not explain script behavior. +5. Keep script paths only in permission blocks/frontmatter where the harness needs executable allow/ask patterns. + +**Verification** + +```bash +rg -n "\\.agents/skills/.*/scripts|\\.claude/skills/.*/scripts|issue-tracker/scripts" \ + core/opencode/agents \ + core/claude/skills \ + core/agents/skills/workflow-* + +codespell \ + core/opencode/agents \ + core/claude/skills \ + core/agents/skills/workflow-* +``` + +Expected result: remaining script-path hits are only in permission/frontmatter blocks or in boundary skill docs, not workflow body instructions. + +**Commit boundary** + +```text +Use skill-level instructions in workflow files +``` + +### Task 4 — Align OpenCode agent permissions and skill allowlists + +**Files** + +- `core/opencode/agents/brainstorm.md` +- `core/opencode/agents/bugfix.md` +- `core/opencode/agents/planner.md` +- `core/opencode/agents/finish.md` +- `core/opencode/agents/implement.md` +- `core/opencode/agents/review-plan.md` +- `core/opencode/agents/review-code.md` + +**Changes** + +1. For each agent with `git-publish` script permission, add a corresponding `git-publish` skill allow entry. +2. For each agent that may open a change request, add both the `change-request-publish` skill allow entry and the script permission at the desired tier. +3. Apply PR feedback that `brainstorm` should allow opening a change request when publishing a brainstorming result. +4. Apply PR feedback that `review-plan` requires `git-publish`. +5. Apply PR feedback that `review-code` should be allowed to publish review-fix implementation plans; add `git-publish` permission and skill if this agent is expected to commit/publish its review-finding plan. +6. Keep direct script paths only in permission maps, not body instructions. + +**Verification** + +```bash +rg -n "git-publish|change-request-publish|change-request-comments|issue-tracker" core/opencode/agents +rg -n "\\.agents/skills/.*/scripts" core/opencode/agents +``` + +Expected result: permissions and skill allowlists line up, with script paths confined to permission maps. + +**Commit boundary** + +```text +Align OpenCode permissions for neutral repository skills +``` + +### Task 5 — Update installer skill inventories and README sync + +**Files** + +- `scripts/init.sh` +- `scripts/copy.sh` +- `README.md` +- `core/docs/agents/review-plan.md` +- `core/docs/agents/review-code.md` +- `core/docs/agents/agent-workflow-extension.md` + +**Changes** + +1. Remove `github-pr-comments` and `gitlab-mr-comments` from the `AUTHORED_SKILLS` arrays if Task 2 moved their implementation into `change-request-comments`. +2. Keep the neutral authored skills in both installer arrays: `git-publish`, `change-request-publish`, `change-request-comments`, and `issue-tracker`. +3. Update `README.md` authored skill list and symlink table to match the actual installed authored skills. +4. Remove README invocation guidance that points users at `/github-pr-comments`; use `/change-request-comments` or workflow-neutral language instead. +5. Update role docs and the workflow extension guide to name `change-request-comments` as the comment boundary. +6. Re-check `stacks/pnpm` and `stacks/maven` for overlays that need equivalent wording changes. + +**Verification** + +```bash +bash -n scripts/init.sh scripts/copy.sh +shellcheck scripts/init.sh scripts/copy.sh +codespell README.md core/docs/agents scripts/init.sh scripts/copy.sh +rg -n "github-pr-comments|gitlab-mr-comments" README.md core/docs/agents scripts/init.sh scripts/copy.sh +rg -n "github-pr-comments|gitlab-mr-comments|github|gitlab|PR|MR|gh |glab" stacks/pnpm stacks/maven +``` + +Expected result: provider comment skill names do not appear in downstream installer or generic docs except in explicitly justified boundary documentation. + +**Commit boundary** + +```text +Sync installers and docs with neutral comment skill +``` + +### Task 6 — Clean up Claude settings and OpenCode base config + +**Files** + +- `core/claude/settings.json` +- `core/opencode.json` + +**Changes** + +1. Group Claude permissions by neutral wrapper scripts, GitHub read-only support, and GitLab read-only support. +2. Put mutating neutral wrapper commands in `ask` unless the workflow intentionally allows them. +3. Ensure `issue-tracker/scripts/update-issue.sh` appears in only one permission tier. +4. Remove direct provider mutation permissions that are now handled through neutral wrapper scripts. +5. Keep `core/opencode.json` as a small permissive base config and avoid reintroducing `glab` base permissions. + +**Verification** + +```bash +jq . core/claude/settings.json > /dev/null +jq . core/opencode.json > /dev/null +rg -n "github-publish|gitlab-publish|github-pr-comments|gitlab-mr-comments|create-bug-issue|update-bug-issue" \ + core/claude/settings.json core/opencode.json +jq '.permission.bash | keys' core/opencode.json +``` + +**Commit boundary** + +```text +Normalize permissions for neutral repository workflows +``` + +### Task 7 — Replace the repo-local publish wrapper with self-maintenance skill symlinks + +**Files** + +- `AGENTS.md` +- `scripts/publish-branch.sh` +- `.agents/skills/git-publish` +- `.agents/skills/change-request-publish` + +**Changes** + +1. Delete `scripts/publish-branch.sh` with `git rm`. +2. Add self-maintenance symlinks so this repo can load the same neutral skills it installs downstream: + - `.agents/skills/git-publish` → `../../core/agents/skills/git-publish` + - `.agents/skills/change-request-publish` → `../../core/agents/skills/change-request-publish` +3. Update `AGENTS.md` Git Conventions to replace `Use scripts/publish-branch.sh` with `Use git-publish for branch pushes and change-request-publish for PR/MR creation`. +4. Confirm the symlink model remains clear: `.agents/skills/*` may contain repo-self-maintenance skills and symlinks to authored template skills; `core/agents/skills/*` remains the downstream template source. + +**Verification** + +```bash +test ! -e scripts/publish-branch.sh +ls -la .agents/skills/git-publish .agents/skills/change-request-publish +test "$(readlink .agents/skills/git-publish)" = "../../core/agents/skills/git-publish" +test "$(readlink .agents/skills/change-request-publish)" = "../../core/agents/skills/change-request-publish" +codespell AGENTS.md +``` + +**Commit boundary** + +```text +Use neutral publish skills for repo maintenance +``` + +### Task 8 — Strengthen workflow boundary regression checks + +**Files** + +- `scripts/check-workflow-boundaries.sh` + +**Changes** + +1. Keep the existing provider-specific pattern checks. +2. Add checks for direct internal script references in workflow-facing body text, including `.agents/skills/.*/scripts/`, `.claude/skills/.*/scripts/`, and `/scripts/*.sh` forms. +3. Exclude boundary skill directories where script usage is the documented interface for that skill itself. +4. Filter frontmatter permission blocks so valid OpenCode permission entries do not fail the body-instruction leakage check. +5. Run the check after Tasks 2–6 so the expected result is a clean pass. + +**Verification** + +```bash +bash -n scripts/check-workflow-boundaries.sh +shellcheck scripts/check-workflow-boundaries.sh +bash scripts/check-workflow-boundaries.sh +``` + +**Commit boundary** + +```text +Check workflow files for skill-internal leakage +``` + +## Final verification + +Run from the repository root after all tasks: + +```bash +bash -n scripts/init.sh scripts/copy.sh scripts/check-workflow-boundaries.sh +shellcheck scripts/init.sh scripts/copy.sh scripts/check-workflow-boundaries.sh +jq . core/claude/settings.json > /dev/null +jq . core/opencode.json > /dev/null +codespell AGENTS.md README.md core/agents/skills core/claude/skills core/opencode/agents core/docs/agents scripts +bash scripts/check-workflow-boundaries.sh +``` + +Smoke install under `.temp/`: + +```bash +mkdir -p .temp/smoke-init +printf "1\n1\n.temp/smoke-init/target\n" | bash scripts/init.sh +ls -la .temp/smoke-init/target/.claude/skills + +mkdir -p .temp/smoke-copy/target +git -C .temp/smoke-copy/target init +git -C .temp/smoke-copy/target config user.email "test@example.com" +git -C .temp/smoke-copy/target config user.name "Test" +touch .temp/smoke-copy/target/README.md +git -C .temp/smoke-copy/target add README.md +git -C .temp/smoke-copy/target commit -m "init" +printf "1\n1\n" | bash scripts/copy.sh .temp/smoke-copy/target +ls -la .temp/smoke-copy/target/.claude/skills + +rm -rf .temp/smoke-init .temp/smoke-copy +``` + +## Acceptance criteria + +- `AGENTS.md` explicitly prevents workflow-facing instructions from exposing skill internals. +- Generic workflow files name skills, not internal script paths. +- `change-request-comments` is the only downstream comment skill surface. +- Installer arrays, README inventories, and symlink table match actual installed authored skills. +- OpenCode and Claude permissions allow neutral wrapper usage without documenting internal scripts in workflow bodies. +- Provider-specific CLI details live only inside boundary skills or provider-specific implementation code. +- Boundary checks prevent future provider-skill and internal-script leakage. +- Bash and smoke verification pass under `.temp/`. From 8b06d11ed4753137c3c3b4a5a159bb1b0f1601ae Mon Sep 17 00:00:00 2001 From: Simon Flandergan Date: Sun, 28 Jun 2026 16:08:25 +0200 Subject: [PATCH 35/65] Expand review findings plan details --- .../review-findings.md | 108 +++++++++++++++--- 1 file changed, 89 insertions(+), 19 deletions(-) diff --git a/plans/2026-06-25-dual-harness-forge/review-findings.md b/plans/2026-06-25-dual-harness-forge/review-findings.md index a73fe3d..4e0b8c0 100644 --- a/plans/2026-06-25-dual-harness-forge/review-findings.md +++ b/plans/2026-06-25-dual-harness-forge/review-findings.md @@ -11,6 +11,7 @@ This plan consolidates the current PR comments and local review findings for fix 3. **`change-request-comments` delegates to provider skill folders.** Its scripts still call `.agents/skills/github-pr-comments/...` and `.agents/skills/gitlab-mr-comments/...`, so removing those folders would break comment workflows unless the implementations move into the neutral skill. 4. **Permission/skill allowlists are inconsistent.** Several agents have script permissions without corresponding skill permissions, and review-code is missing publish capability for review-fix implementation plans. 5. **`AGENTS.md` does not yet encode the “no skill internals in workflow instructions” rule.** This is the root cause called out by the top-level PR comment. +6. **Neutral skill docs mix runtime instructions with design rationale.** Some `SKILL.md` files explain why the wrapper exists or expose implementation detail. Keep `SKILL.md` focused on invocation contract and move rationale into sibling `README.md` files. ### Advisory issues @@ -30,7 +31,7 @@ This plan consolidates the current PR comments and local review findings for fix 1. Add a section such as `## Skill Boundary Rule` after the symlink model. 2. State that workflow-facing files must instruct agents to use skills by name, for example `git-publish`, `change-request-publish`, `change-request-comments`, and `issue-tracker`. -3. State that workflow-facing files must not expose internal script paths like `.agents/skills//scripts/*.sh` or `.claude/skills//scripts/*.sh` except inside the skill's own `SKILL.md` or scripts. +3. State that workflow-facing files must not expose internal script paths like `.agents/skills//scripts/*.sh` or `.claude/skills//scripts/*.sh`. Boundary-skill implementation details may live in that skill's own scripts or sibling `README.md`; keep `SKILL.md` focused on the invocation contract. 4. Clarify that agent frontmatter and Claude settings may grant script permissions, but body instructions should stay skill-level. 5. Add provider-boundary language: provider-specific CLI details (`gh`, `glab`, provider comment scripts) belong only in provider/boundary skills, not generic workflow files. @@ -55,22 +56,31 @@ Document skill boundary rules for workflow instructions - `core/agents/skills/change-request-comments/scripts/reply-to-comment.sh` - `core/agents/skills/github-pr-comments/` (delete from downstream template) - `core/agents/skills/gitlab-mr-comments/` (delete from downstream template) +- `.agents/skills/github-pr-comments/` (convert from symlink to self-maintenance copy if this repo still needs PR comment review) +- `.claude/skills/github-pr-comments` (keep symlink to `.agents/skills/github-pr-comments`) **Changes** -1. Inline or move the current GitHub PR comment fetch/reply logic into `change-request-comments/scripts/`. -2. Inline or move the current GitLab MR comment fetch/reply logic into `change-request-comments/scripts/`. -3. Keep host detection inside `change-request-comments`; it may call `gh`/`glab` because this skill is the boundary layer. -4. Remove references from `change-request-comments/SKILL.md` that say it delegates to `github-pr-comments` or `gitlab-mr-comments` skill folders. -5. Delete `core/agents/skills/github-pr-comments/` and `core/agents/skills/gitlab-mr-comments/` with `git rm -r` after their logic is represented inside `change-request-comments`. -6. Keep this repo's self-maintenance `.agents/skills/github-pr-comments` only if still needed for this PR review workflow; do not confuse self-maintenance skills with `core/` templates. +1. Before deleting `core/agents/skills/github-pr-comments/`, preserve this repo's self-maintenance review workflow by converting `.agents/skills/github-pr-comments` from a symlink into a real self-maintenance skill directory copied from the current GitHub implementation. Keep `.claude/skills/github-pr-comments` symlinked to `.agents/skills/github-pr-comments`. +2. Replace the GitHub branch of `change-request-comments/scripts/fetch-comments.sh` with the implementation currently in `core/agents/skills/github-pr-comments/scripts/fetch-pr-comments.sh`; keep the public wrapper name `fetch-comments.sh`. +3. Replace the GitHub branch of `change-request-comments/scripts/reply-to-comment.sh` with the implementation currently in `core/agents/skills/github-pr-comments/scripts/reply-to-pr-comment.sh`; keep the public wrapper name `reply-to-comment.sh`. +4. Replace the GitLab branch of `fetch-comments.sh` with the implementation currently in `core/agents/skills/gitlab-mr-comments/scripts/fetch-mr-comments.sh`. +5. Replace the GitLab branch of `reply-to-comment.sh` with the implementation currently in `core/agents/skills/gitlab-mr-comments/scripts/reply-to-mr-comment.sh`. +6. Keep host detection inside `change-request-comments`; it may call `gh`/`glab` because this skill is the provider boundary layer. +7. Preserve behavior and flags from both provider implementations, including `--comments-only`, `--diff-only`, `--json`, comment reply payload handling, and exit-code behavior. +8. Remove references from `change-request-comments/SKILL.md` and scripts that say it delegates to `github-pr-comments` or `gitlab-mr-comments` skill folders. +9. Delete `core/agents/skills/github-pr-comments/` and `core/agents/skills/gitlab-mr-comments/` with `git rm -r` after their logic is represented inside `change-request-comments` and the self-maintenance GitHub skill no longer points at `core/`. **Verification** ```bash bash -n core/agents/skills/change-request-comments/scripts/*.sh shellcheck core/agents/skills/change-request-comments/scripts/*.sh -rg -n "github-pr-comments|gitlab-mr-comments" core/agents/skills/change-request-comments +! rg -n "github-pr-comments|gitlab-mr-comments" core/agents/skills/change-request-comments +test ! -e core/agents/skills/github-pr-comments +test ! -e core/agents/skills/gitlab-mr-comments +test -d .agents/skills/github-pr-comments +test "$(readlink .claude/skills/github-pr-comments)" = "../../.agents/skills/github-pr-comments" ``` Expected result: no delegation to provider skill folders remains in `change-request-comments`. @@ -81,6 +91,54 @@ Expected result: no delegation to provider skill folders remains in `change-requ Move comment provider logic into change-request-comments ``` +### Task 2A — Split neutral skill rationale into sibling READMEs + +**Files** + +- `core/agents/skills/git-publish/SKILL.md` +- `core/agents/skills/git-publish/README.md` (add) +- `core/agents/skills/change-request-publish/SKILL.md` +- `core/agents/skills/change-request-publish/README.md` (add) +- `core/agents/skills/change-request-comments/SKILL.md` +- `core/agents/skills/change-request-comments/README.md` (add) +- `core/agents/skills/issue-tracker/SKILL.md` +- `core/agents/skills/issue-tracker/README.md` (add) + +**Changes** + +1. Keep each `SKILL.md` focused on the agent-facing contract: when to use the skill, what high-level capability it provides, required inputs/outputs, and safety rules. +2. Remove design-rationale sections such as `Why a script, not a raw ...` from `SKILL.md` files. +3. Move the rationale into the sibling `README.md`, including why the wrapper exists, host-detection philosophy, branch/default-branch guards, provider differences, and why workflow-facing files should not call provider CLIs directly. +4. Do not expose provider-specific skill names or deleted provider folders in the downstream `SKILL.md` files. Provider CLI details may appear in these boundary-skill `README.md` files because they document the implementation rationale. +5. Keep script paths out of generic workflow docs. In boundary-skill docs, script paths may appear only where they describe the skill's own implementation or operator/debugging interface. + +**Verification** + +```bash +test -f core/agents/skills/git-publish/README.md +test -f core/agents/skills/change-request-publish/README.md +test -f core/agents/skills/change-request-comments/README.md +test -f core/agents/skills/issue-tracker/README.md +! rg -n '^## Why|Why a script|raw `git push`|raw `gh pr create`|raw `glab mr create`' \ + core/agents/skills/git-publish/SKILL.md \ + core/agents/skills/change-request-publish/SKILL.md \ + core/agents/skills/change-request-comments/SKILL.md \ + core/agents/skills/issue-tracker/SKILL.md +codespell \ + core/agents/skills/git-publish \ + core/agents/skills/change-request-publish \ + core/agents/skills/change-request-comments \ + core/agents/skills/issue-tracker +``` + +Expected result: the `rg` command finds no rationale text in the listed `SKILL.md` files; rationale lives in the new sibling `README.md` files. + +**Commit boundary** + +```text +Move neutral skill rationale into READMEs +``` + ### Task 3 — Remove skill-internal script instructions from workflow-facing files **Files** @@ -175,6 +233,7 @@ Align OpenCode permissions for neutral repository skills - `scripts/init.sh` - `scripts/copy.sh` - `README.md` +- `core/claude/README.md` - `core/docs/agents/review-plan.md` - `core/docs/agents/review-code.md` - `core/docs/agents/agent-workflow-extension.md` @@ -184,18 +243,21 @@ Align OpenCode permissions for neutral repository skills 1. Remove `github-pr-comments` and `gitlab-mr-comments` from the `AUTHORED_SKILLS` arrays if Task 2 moved their implementation into `change-request-comments`. 2. Keep the neutral authored skills in both installer arrays: `git-publish`, `change-request-publish`, `change-request-comments`, and `issue-tracker`. 3. Update `README.md` authored skill list and symlink table to match the actual installed authored skills. -4. Remove README invocation guidance that points users at `/github-pr-comments`; use `/change-request-comments` or workflow-neutral language instead. -5. Update role docs and the workflow extension guide to name `change-request-comments` as the comment boundary. -6. Re-check `stacks/pnpm` and `stacks/maven` for overlays that need equivalent wording changes. +4. Update `core/claude/README.md` so it lists the neutral authored skills and removes stale `github-pr-comments`, `gitlab-mr-comments`, `github-publish`, and `gitlab-publish` references from downstream Claude documentation. +5. Remove README invocation guidance that points users at `/github-pr-comments`; use `/change-request-comments` or workflow-neutral language instead. +6. Update role docs and the workflow extension guide to name `change-request-comments` as the comment boundary. +7. Re-check `stacks/pnpm` and `stacks/maven` for overlays that need equivalent wording changes. Current expected result: no `agents/skills/` overlays exist in either stack; only stack docs/config overlays may need wording changes. +8. Lockfile check: confirm no lockfile edit is needed because `github-pr-comments` and `gitlab-mr-comments` are authored skills, not remote skills tracked by `core/skills-lock.json`. If a remote-skill entry is discovered, update only the affected lockfile scope. **Verification** ```bash bash -n scripts/init.sh scripts/copy.sh shellcheck scripts/init.sh scripts/copy.sh -codespell README.md core/docs/agents scripts/init.sh scripts/copy.sh -rg -n "github-pr-comments|gitlab-mr-comments" README.md core/docs/agents scripts/init.sh scripts/copy.sh -rg -n "github-pr-comments|gitlab-mr-comments|github|gitlab|PR|MR|gh |glab" stacks/pnpm stacks/maven +codespell README.md core/claude/README.md core/docs/agents scripts/init.sh scripts/copy.sh +! rg -n "github-pr-comments|gitlab-mr-comments|github-publish|gitlab-publish" \ + README.md core/claude/README.md core/docs/agents scripts/init.sh scripts/copy.sh +! rg -n "github-pr-comments|gitlab-mr-comments|github|gitlab|PR|MR|gh |glab" stacks/pnpm stacks/maven ``` Expected result: provider comment skill names do not appear in downstream installer or generic docs except in explicitly justified boundary documentation. @@ -226,7 +288,7 @@ Sync installers and docs with neutral comment skill ```bash jq . core/claude/settings.json > /dev/null jq . core/opencode.json > /dev/null -rg -n "github-publish|gitlab-publish|github-pr-comments|gitlab-mr-comments|create-bug-issue|update-bug-issue" \ +! rg -n "github-publish|gitlab-publish|github-pr-comments|gitlab-mr-comments|create-bug-issue|update-bug-issue" \ core/claude/settings.json core/opencode.json jq '.permission.bash | keys' core/opencode.json ``` @@ -262,6 +324,8 @@ test ! -e scripts/publish-branch.sh ls -la .agents/skills/git-publish .agents/skills/change-request-publish test "$(readlink .agents/skills/git-publish)" = "../../core/agents/skills/git-publish" test "$(readlink .agents/skills/change-request-publish)" = "../../core/agents/skills/change-request-publish" +test "$(readlink .claude/skills/git-publish)" = "../../.agents/skills/git-publish" +test "$(readlink .claude/skills/change-request-publish)" = "../../.agents/skills/change-request-publish" codespell AGENTS.md ``` @@ -281,9 +345,10 @@ Use neutral publish skills for repo maintenance 1. Keep the existing provider-specific pattern checks. 2. Add checks for direct internal script references in workflow-facing body text, including `.agents/skills/.*/scripts/`, `.claude/skills/.*/scripts/`, and `/scripts/*.sh` forms. -3. Exclude boundary skill directories where script usage is the documented interface for that skill itself. -4. Filter frontmatter permission blocks so valid OpenCode permission entries do not fail the body-instruction leakage check. -5. Run the check after Tasks 2–6 so the expected result is a clean pass. +3. Exclude boundary skill directories where script usage is the documented interface for that skill itself: `git-publish`, `change-request-publish`, `change-request-comments`, and `issue-tracker`. +4. Filter frontmatter permission blocks so valid OpenCode permission entries do not fail the body-instruction leakage check. Implement this explicitly by scanning only the markdown body after the opening YAML frontmatter (`--- ... ---`) for agent files; do not rely on a plain `rg` that cannot distinguish permissions from prose. +5. Keep permission-map script paths legal, but fail on the same paths in body prose, bullets, or examples in generic workflow files. +6. Run the check after Tasks 2–6 so the expected result is a clean pass. During earlier tasks, use the task-local `rg` commands because this regression check is not authoritative until this task updates it. **Verification** @@ -308,7 +373,7 @@ bash -n scripts/init.sh scripts/copy.sh scripts/check-workflow-boundaries.sh shellcheck scripts/init.sh scripts/copy.sh scripts/check-workflow-boundaries.sh jq . core/claude/settings.json > /dev/null jq . core/opencode.json > /dev/null -codespell AGENTS.md README.md core/agents/skills core/claude/skills core/opencode/agents core/docs/agents scripts +codespell AGENTS.md README.md core/claude/README.md core/agents/skills core/claude/skills core/opencode/agents core/docs/agents scripts bash scripts/check-workflow-boundaries.sh ``` @@ -318,6 +383,8 @@ Smoke install under `.temp/`: mkdir -p .temp/smoke-init printf "1\n1\n.temp/smoke-init/target\n" | bash scripts/init.sh ls -la .temp/smoke-init/target/.claude/skills +test ! -e .temp/smoke-init/target/.agents/skills/github-pr-comments +test ! -e .temp/smoke-init/target/.agents/skills/gitlab-mr-comments mkdir -p .temp/smoke-copy/target git -C .temp/smoke-copy/target init @@ -328,6 +395,8 @@ git -C .temp/smoke-copy/target add README.md git -C .temp/smoke-copy/target commit -m "init" printf "1\n1\n" | bash scripts/copy.sh .temp/smoke-copy/target ls -la .temp/smoke-copy/target/.claude/skills +test ! -e .temp/smoke-copy/target/.agents/skills/github-pr-comments +test ! -e .temp/smoke-copy/target/.agents/skills/gitlab-mr-comments rm -rf .temp/smoke-init .temp/smoke-copy ``` @@ -337,6 +406,7 @@ rm -rf .temp/smoke-init .temp/smoke-copy - `AGENTS.md` explicitly prevents workflow-facing instructions from exposing skill internals. - Generic workflow files name skills, not internal script paths. - `change-request-comments` is the only downstream comment skill surface. +- Neutral skill `SKILL.md` files focus on invocation contracts; rationale lives in sibling `README.md` files. - Installer arrays, README inventories, and symlink table match actual installed authored skills. - OpenCode and Claude permissions allow neutral wrapper usage without documenting internal scripts in workflow bodies. - Provider-specific CLI details live only inside boundary skills or provider-specific implementation code. From d089d77005f28b43bce6ac497ad042fdf193a689 Mon Sep 17 00:00:00 2001 From: Simon Flandergan Date: Sun, 28 Jun 2026 16:09:36 +0200 Subject: [PATCH 36/65] Document skill boundary rules for workflow instructions --- AGENTS.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/AGENTS.md b/AGENTS.md index 474766e..28148c0 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -62,6 +62,16 @@ user-invocable: false # for skills only loaded by agents, not users OpenCode is configured to read skills from `.agents/skills//SKILL.md`. Each skill is symlinked into `.claude/skills/` (`ln -s ../../.agents/skills/`) so Claude Code also sees it. This matches the model `copy.sh` uses for authored skills. +## Skill Boundary Rule + +Workflow-facing files (SKILL.md bodies, agent instructions, README workflow sections) must instruct agents to **use skills by name** — for example `git-publish`, `change-request-publish`, `change-request-comments`, or `issue-tracker` — rather than exposing internal implementation paths. + +**Do not** reference internal script paths like `.agents/skills//scripts/*.sh` or `.claude/skills//scripts/*.sh` in workflow-facing content. Boundary-skill implementation details may live in that skill's own scripts or sibling `README.md`; keep the `SKILL.md` focused on the invocation contract. + +Agent frontmatter and Claude settings may grant script permissions, but body instructions should stay at the skill level, not the script level. + +**Provider-boundary language:** Provider-specific CLI details (`gh`, `glab`, provider comment scripts) belong only in provider or boundary skills, not in generic workflow files. Generic workflow files should remain provider-agnostic. + ## .temp/ Scratch Rule All smoke runs and throwaway work goes in `.temp/`, never `/tmp`. Clean up after use. `.temp/` is gitignored. From f66f450d15d70c350ff8014089acd01ffb79e09b Mon Sep 17 00:00:00 2001 From: Simon Flandergan Date: Sun, 28 Jun 2026 16:23:58 +0200 Subject: [PATCH 37/65] Move comment provider logic into change-request-comments --- .agents/skills/github-pr-comments | 1 - .../skills/github-pr-comments/SKILL.md | 0 .../scripts/fetch-pr-comments.sh | 0 .../scripts/reply-to-pr-comment.sh | 0 .../skills/change-request-comments/SKILL.md | 38 +++- .../scripts/fetch-comments.sh | 194 +++++++++++++++++- .../scripts/reply-to-comment.sh | 70 ++++++- .../agents/skills/gitlab-mr-comments/SKILL.md | 86 -------- .../scripts/fetch-mr-comments.sh | 71 ------- .../scripts/reply-to-mr-comment.sh | 33 --- 10 files changed, 288 insertions(+), 205 deletions(-) delete mode 120000 .agents/skills/github-pr-comments rename {core/agents => .agents}/skills/github-pr-comments/SKILL.md (100%) rename {core/agents => .agents}/skills/github-pr-comments/scripts/fetch-pr-comments.sh (100%) rename {core/agents => .agents}/skills/github-pr-comments/scripts/reply-to-pr-comment.sh (100%) delete mode 100644 core/agents/skills/gitlab-mr-comments/SKILL.md delete mode 100755 core/agents/skills/gitlab-mr-comments/scripts/fetch-mr-comments.sh delete mode 100755 core/agents/skills/gitlab-mr-comments/scripts/reply-to-mr-comment.sh diff --git a/.agents/skills/github-pr-comments b/.agents/skills/github-pr-comments deleted file mode 120000 index bc49c89..0000000 --- a/.agents/skills/github-pr-comments +++ /dev/null @@ -1 +0,0 @@ -../../core/agents/skills/github-pr-comments \ No newline at end of file diff --git a/core/agents/skills/github-pr-comments/SKILL.md b/.agents/skills/github-pr-comments/SKILL.md similarity index 100% rename from core/agents/skills/github-pr-comments/SKILL.md rename to .agents/skills/github-pr-comments/SKILL.md diff --git a/core/agents/skills/github-pr-comments/scripts/fetch-pr-comments.sh b/.agents/skills/github-pr-comments/scripts/fetch-pr-comments.sh similarity index 100% rename from core/agents/skills/github-pr-comments/scripts/fetch-pr-comments.sh rename to .agents/skills/github-pr-comments/scripts/fetch-pr-comments.sh diff --git a/core/agents/skills/github-pr-comments/scripts/reply-to-pr-comment.sh b/.agents/skills/github-pr-comments/scripts/reply-to-pr-comment.sh similarity index 100% rename from core/agents/skills/github-pr-comments/scripts/reply-to-pr-comment.sh rename to .agents/skills/github-pr-comments/scripts/reply-to-pr-comment.sh diff --git a/core/agents/skills/change-request-comments/SKILL.md b/core/agents/skills/change-request-comments/SKILL.md index a8a57dc..6f05cb1 100644 --- a/core/agents/skills/change-request-comments/SKILL.md +++ b/core/agents/skills/change-request-comments/SKILL.md @@ -1,12 +1,12 @@ --- name: change-request-comments -description: Use when reading or replying to pull request or merge request comments — detects GitHub vs GitLab and delegates to provider-specific skills +description: Use when reading or replying to pull request or merge request comments — detects GitHub vs GitLab and handles both inline user-invocable: false --- # Change Request Comments -Host-agnostic interface for reading and replying to change-request (PR/MR) comments. The script detects whether the repository is on GitHub or GitLab and delegates to the corresponding provider-specific skill. +Host-agnostic interface for reading and replying to change-request (PR/MR) comments. The scripts detect whether the repository is on GitHub or GitLab and handle both providers directly. ## Fetch comments @@ -15,9 +15,15 @@ bash .agents/skills/change-request-comments/scripts/fetch-comments.sh [] ``` - **Host detection**: reads `git remote get-url origin` to determine the host. - - GitHub → delegates to `.agents/skills/github-pr-comments/scripts/fetch-pr-comments.sh` - - GitLab → delegates to `.agents/skills/gitlab-mr-comments/scripts/fetch-mr-comments.sh` -- Arguments and exit code are preserved. + - GitHub: uses `gh` CLI and GraphQL to fetch issue comments, inline review threads, and PR diff. + - GitLab: uses `glab` CLI to fetch discussions and MR diff. +- When `` is omitted, the script auto-detects the PR/MR number from the current branch. + +Optional modes: + +- `--comments-only` — print comment metadata only, omit the diff. +- `--diff-only` — print the diff only, omit comments. +- `--json` — output a single JSON object with all data (PR/MR metadata, comments, discussions). ## Reply to a comment @@ -26,6 +32,22 @@ bash .agents/skills/change-request-comments/scripts/reply-to-comment.sh [' '[ + { "comment_id": 123456, "body": "Fixed in abc123." }, + { "comment_id": 789012, "body": "Good catch, updated." } +]' + +# GitLab +bash .agents/skills/change-request-comments/scripts/reply-to-comment.sh '' '[ + { "discussion_id": "a1b2c3d4...", "body": "Fixed in abc123." }, + { "discussion_id": "e5f6g7h8...", "body": "Good catch, updated." } +]' +``` diff --git a/core/agents/skills/change-request-comments/scripts/fetch-comments.sh b/core/agents/skills/change-request-comments/scripts/fetch-comments.sh index 23b9f7a..bc519a2 100644 --- a/core/agents/skills/change-request-comments/scripts/fetch-comments.sh +++ b/core/agents/skills/change-request-comments/scripts/fetch-comments.sh @@ -1,14 +1,202 @@ #!/usr/bin/env bash set -euo pipefail -# Detect host from the remote URL. remote_url="$(git remote get-url origin)" case "$remote_url" in *github.com*) - exec bash .agents/skills/github-pr-comments/scripts/fetch-pr-comments.sh "$@" + + if [ "$#" -gt 2 ]; then + printf 'Usage: %s [] [--comments-only|--diff-only|--json]\n' "$0" >&2 + exit 2 + fi + + if [[ "${1:-}" =~ ^[0-9]+$ ]]; then + pr="$1" + mode="${2:-}" + else + pr="$(gh pr view --json number --jq '.number')" + mode="${1:-}" + fi + case "$mode" in + ""|--comments-only|--diff-only|--json) ;; + *) + printf 'Unknown mode: %s\n' "$mode" >&2 + printf 'Usage: %s [] [--comments-only|--diff-only|--json]\n' "$0" >&2 + exit 2 + ;; + esac + + if [ "$mode" = "--diff-only" ]; then + gh pr diff "$pr" + exit 0 + fi + + pr_json="$(gh pr view "$pr" --json number,title,headRefName,baseRefName,url,comments,headRepository)" + repo=$(jq -r '.headRepository.nameWithOwner' <<<"$pr_json") + issue_comments_json="$(gh api "repos/$repo/issues/$pr/comments")" + inline_comments_json="$(gh api graphql \ + -F owner="${repo%%/*}" \ + -F name="${repo#*/}" \ + -F pr="$pr" \ + -f query='query($owner: String!, $name: String!, $pr: Int!) { + repository(owner: $owner, name: $name) { + pullRequest(number: $pr) { + reviewThreads(first: 100) { + nodes { + isResolved + comments(first: 100) { + nodes { + id + databaseId + path + line + originalLine + body + createdAt + updatedAt + url + } + } + } + pageInfo { + hasNextPage + endCursor + } + } + } + } + }' \ + --jq '[.data.repository.pullRequest.reviewThreads.nodes[] | select(.isResolved | not) | .comments.nodes[]]')" + + if [ "$mode" = "--json" ]; then + PR_JSON="$pr_json" ISSUE_COMMENTS_JSON="$issue_comments_json" INLINE_COMMENTS_JSON="$inline_comments_json" node <<'JS' +const payload = { + pr: JSON.parse(process.env.PR_JSON ?? '{}'), + issueComments: JSON.parse(process.env.ISSUE_COMMENTS_JSON ?? '[]'), + inlineComments: JSON.parse(process.env.INLINE_COMMENTS_JSON ?? '[]'), +}; + +console.log(JSON.stringify(payload, null, 2)); +JS + exit 0 + fi + + printf '## Comment Summary\n' + PR_JSON="$pr_json" ISSUE_COMMENTS_JSON="$issue_comments_json" INLINE_COMMENTS_JSON="$inline_comments_json" node <<'JS' +const pr = JSON.parse(process.env.PR_JSON ?? '{}'); +const issueComments = JSON.parse(process.env.ISSUE_COMMENTS_JSON ?? '[]'); +const inlineComments = JSON.parse(process.env.INLINE_COMMENTS_JSON ?? '[]'); + +const summarize = (body) => { + const firstLine = String(body ?? '').replace(/\s+/g, ' ').trim(); + return firstLine.length > 180 ? `${firstLine.slice(0, 177)}...` : firstLine; +}; + +console.log(`PR #${pr.number}: ${pr.title}`); +console.log(`Branch: ${pr.headRefName} -> ${pr.baseRefName}`); +console.log(`URL: ${pr.url}`); +console.log(''); + +console.log(`Issue comments (${issueComments.length})`); +for (const comment of issueComments) { + console.log(`- id=${comment.id} author=${comment.user?.login ?? 'unknown'} updated=${comment.updated_at}: ${summarize(comment.body)}`); +} +console.log(''); + +console.log(`Unresolved inline comments (${inlineComments.length})`); +for (const comment of inlineComments) { + const location = `${comment.path}:${comment.line ?? comment.originalLine ?? '?'}`; + console.log(`- databaseId=${comment.databaseId} ${location} updated=${comment.updatedAt}: ${summarize(comment.body)}`); +} +JS + + printf '\n## PR\n' + printf '%s\n' "$pr_json" + + printf '\n## Issue Comments\n' + printf '%s\n' "$issue_comments_json" + + printf '\n## Inline PR Comments\n' + printf '%s\n' "$inline_comments_json" + + if [ "$mode" = "--comments-only" ]; then + exit 0 + fi + + printf '\n## Diff\n' + gh pr diff "$pr" ;; + *) - exec bash .agents/skills/gitlab-mr-comments/scripts/fetch-mr-comments.sh "$@" + + if [ "$#" -gt 2 ]; then + printf 'Usage: %s [] [--comments-only|--diff-only|--json]\n' "$0" >&2 + exit 2 + fi + + if [[ "${1:-}" =~ ^[0-9]+$ ]]; then + mr="$1" + mode="${2:-}" + else + mr="$(glab mr view -F json | jq -r '.iid')" + mode="${1:-}" + fi + case "$mode" in + ""|--comments-only|--diff-only|--json) ;; + *) + printf 'Unknown mode: %s\n' "$mode" >&2 + printf 'Usage: %s [] [--comments-only|--diff-only|--json]\n' "$0" >&2 + exit 2 + ;; + esac + + if [ "$mode" = "--diff-only" ]; then + glab mr diff "$mr" + exit 0 + fi + + mr_json="$(glab mr view "$mr" -F json)" + discussions_json="$(glab api --paginate "projects/:id/merge_requests/$mr/discussions?per_page=100")" + + if [ "$mode" = "--json" ]; then + jq -n \ + --argjson mr "$mr_json" \ + --argjson discussions "$discussions_json" \ + '{ mr: $mr, discussions: $discussions }' + exit 0 + fi + + printf '## Note Summary\n' + jq -r \ + --argjson mr "$mr_json" ' + def summarize: (. // "" | gsub("\\s+"; " ") | .[0:180]); + "MR !\($mr.iid): \($mr.title)", + "Branch: \($mr.source_branch) -> \($mr.target_branch)", + "URL: \($mr.web_url)", + "", + "Standalone conversation notes (\([.[] | select(.individual_note == true)] | length)):", + ( .[] | select(.individual_note == true) | .notes[] | select(.system == false) + | "- discussion_id=\(.id // "?") note=\(.id) author=\(.author.username) updated=\(.updated_at): \(.body | summarize)" ), + "", + "Unresolved inline diff discussions:", + ( .[] | select(.individual_note != true) | . as $d + | select([.notes[] | select(.resolvable == true and .resolved == false)] | length > 0) + | .notes[0] as $n + | "- discussion_id=\($d.id) \($n.position.new_path // $n.position.old_path // "?"):\($n.position.new_line // $n.position.old_line // "?") author=\($n.author.username) updated=\($n.updated_at): \($n.body | summarize)" ) + ' <<<"$discussions_json" + + printf '\n## MR\n' + printf '%s\n' "$mr_json" + + printf '\n## Discussions\n' + printf '%s\n' "$discussions_json" + + if [ "$mode" = "--comments-only" ]; then + exit 0 + fi + + printf '\n## Diff\n' + glab mr diff "$mr" ;; esac diff --git a/core/agents/skills/change-request-comments/scripts/reply-to-comment.sh b/core/agents/skills/change-request-comments/scripts/reply-to-comment.sh index bb48cee..6e71c79 100644 --- a/core/agents/skills/change-request-comments/scripts/reply-to-comment.sh +++ b/core/agents/skills/change-request-comments/scripts/reply-to-comment.sh @@ -1,14 +1,78 @@ #!/usr/bin/env bash set -euo pipefail -# Detect host from the remote URL. remote_url="$(git remote get-url origin)" case "$remote_url" in *github.com*) - exec bash .agents/skills/github-pr-comments/scripts/reply-to-pr-comment.sh "$@" + + if [ "$#" -eq 1 ]; then + pr_info="$(gh pr view --json number,headRepository)" + replies_json="$1" + elif [ "$#" -eq 2 ] && [[ "$1" =~ ^[0-9]+$ ]]; then + pr_info="$(gh pr view "$1" --json number,headRepository)" + replies_json="$2" + else + printf 'Usage: %s [] \n' "$0" >&2 + exit 2 + fi + + pr=$(jq -r '.number' <<<"$pr_info") + repo=$(jq -r '.headRepository.nameWithOwner' <<<"$pr_info") + + if ! jq -e 'type == "array" and all(.[]; (.comment_id | type == "number") and (.body | type == "string"))' \ + >/dev/null <<<"$replies_json"; then + printf 'Reply JSON must be an array of { "comment_id": number, "body": string } objects.\n' >&2 + exit 2 + fi + + count=$(jq length <<<"$replies_json") + printf 'Posting %d replies to PR #%s...\n' "$count" "$pr" + + while IFS= read -r reply; do + comment_id=$(jq -r '.comment_id' <<<"$reply") + body=$(jq -r '.body' <<<"$reply") + + printf ' Replying to comment %s... ' "$comment_id" + gh api --method POST "repos/$repo/pulls/$pr/comments/$comment_id/replies" \ + -f body="$body" + printf 'done\n' + done < <(jq -c '.[]' <<<"$replies_json") + + printf 'All %d replies posted.\n' "$count" ;; + *) - exec bash .agents/skills/gitlab-mr-comments/scripts/reply-to-mr-comment.sh "$@" + + if [ "$#" -eq 1 ]; then + mr="$(glab mr view -F json | jq -r '.iid')" + replies_json="$1" + elif [ "$#" -eq 2 ] && [[ "$1" =~ ^[0-9]+$ ]]; then + mr="$1" + replies_json="$2" + else + printf 'Usage: %s [] \n' "$0" >&2 + exit 2 + fi + + if ! jq -e 'type == "array" and all(.[]; (.discussion_id | type == "string") and (.body | type == "string"))' \ + >/dev/null <<<"$replies_json"; then + printf 'Reply JSON must be an array of { "discussion_id": string, "body": string } objects.\n' >&2 + exit 2 + fi + + count=$(jq length <<<"$replies_json") + printf 'Posting %d replies to MR !%s...\n' "$count" "$mr" + + while IFS= read -r reply; do + discussion_id=$(jq -r '.discussion_id' <<<"$reply") + body=$(jq -r '.body' <<<"$reply") + + printf ' Replying to discussion %s... ' "$discussion_id" + glab mr note create "$mr" --reply "$discussion_id" -m "$body" + printf 'done\n' + done < <(jq -c '.[]' <<<"$replies_json") + + printf 'All %d replies posted.\n' "$count" ;; esac diff --git a/core/agents/skills/gitlab-mr-comments/SKILL.md b/core/agents/skills/gitlab-mr-comments/SKILL.md deleted file mode 100644 index 2563f85..0000000 --- a/core/agents/skills/gitlab-mr-comments/SKILL.md +++ /dev/null @@ -1,86 +0,0 @@ ---- -name: gitlab-mr-comments -description: Use when GitLab merge request feedback lives in plain notes, inline diff discussions, or discussion threads -user-invocable: false ---- - -# GitLab MR Comments - -Use this for team merge request review workflows where feedback is stored as GitLab notes and discussions. This is the GitLab equivalent of `github-pr-comments`. - -## Baseline Failure To Avoid - -Agents naturally mix the GitLab note surfaces: they may read a standalone conversation note when feedback is actually an unresolved inline diff discussion, post a new top-level note instead of replying inside the existing thread, or edit someone else's note instead of replying to it. - -## Skill Scope - -This skill owns MR note mechanics: fetching notes, discussions, and the diff; distinguishing standalone conversation notes from inline diff discussions; obtaining exact discussion IDs; and posting approved replies through project scripts. - -This skill does not own role-level review orchestration. The calling review agent decides how to interpret notes, validate technical claims, combine them with other findings, suggest fixes, edit files, dispatch implementers, or perform final self-review. - -## Read Notes - -Use the bundled read-only helper before proposing fixes. It fetches standalone conversation notes, unresolved inline diff discussions, and the MR diff: - -```bash -bash .agents/skills/gitlab-mr-comments/scripts/fetch-mr-comments.sh [] -``` - -When `` is omitted, the script auto-detects the MR internal ID (`iid`) from the current branch. - -Run the command exactly as shown, without quoting the script path. The review agents have explicit auto-permissions for this command form. - -The helper prints a compact summary first, then full MR metadata, the discussions JSON, and the MR diff. Use the summary for grouping and the full JSON sections for exact discussion IDs. - -Optional read-only modes: - -```bash -bash .agents/skills/gitlab-mr-comments/scripts/fetch-mr-comments.sh [] --comments-only -bash .agents/skills/gitlab-mr-comments/scripts/fetch-mr-comments.sh [] --diff-only -bash .agents/skills/gitlab-mr-comments/scripts/fetch-mr-comments.sh [] --json -``` - -Do not call `glab` directly for reading MR metadata, notes, discussions, or diffs. The helper is the stable interface for this workflow. - -## Classify Notes - -- Standalone conversation notes: top-level MR discussion entries (`individual_note: true`), the GitLab analog of a plain comment. -- Inline diff discussions: resolvable threads whose notes carry a `diff position` (file path and line). Surface only those that are unresolved. -- Outdated inline discussions may still be valid; verify against the current diff before dismissing. - -## Review Workflow - -1. Fetch MR notes and diff when the caller's workflow involves an MR. -2. Use the summary to group target types, then use the full discussions JSON for exact discussion IDs. -3. Distinguish standalone conversation notes from inline diff discussions before posting replies. -4. Surface outdated inline discussions as context; the calling review agent decides whether they still apply. -5. For posting, require an exact approved reply batch with the discussion ID and body. -6. Post only the exact approved reply batch. - -## Replies - -Replying mutates GitLab state, so it is not hidden behind the read helper. Approval for edits, fixes, planning, or any other non-GitLab action does not authorize posting GitLab notes. - -Before posting, present the exact reply batch to the user. Include the discussion ID and body. Wait for explicit approval for that batch. - -After approval, reply inside the existing thread through the project script. Use the `id` of the discussion from the read helper as `discussion_id`: - -Pass a JSON array as the final argument: - -```bash -bash .agents/skills/gitlab-mr-comments/scripts/reply-to-mr-comment.sh [] '[ - { "discussion_id": "a1b2c3d4...", "body": "Fixed in abc123." }, - { "discussion_id": "e5f6g7h8...", "body": "Good catch, updated." } -]' -``` - -The MR number is optional; when omitted, the script auto-detects it from the current branch. Use a one-element array for a single reply. This script replies inside existing discussion threads; it does not open new standalone notes. - -## Common Mistakes - -- Treating standalone conversation notes as complete enough for inline diff review. -- Posting a new top-level note when the user asked to reply inside an inline thread. -- Resolving, editing, or deleting notes without explicit approval. -- Applying external feedback without checking whether it is technically correct. -- Treating approval for edits, fixes, planning, or other non-GitLab work as approval to post GitLab replies. -- Posting a reply batch that differs from the exact batch the user approved. diff --git a/core/agents/skills/gitlab-mr-comments/scripts/fetch-mr-comments.sh b/core/agents/skills/gitlab-mr-comments/scripts/fetch-mr-comments.sh deleted file mode 100755 index 99d69f6..0000000 --- a/core/agents/skills/gitlab-mr-comments/scripts/fetch-mr-comments.sh +++ /dev/null @@ -1,71 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -if [ "$#" -gt 2 ]; then - printf 'Usage: %s [] [--comments-only|--diff-only|--json]\n' "$0" >&2 - exit 2 -fi - -if [[ "${1:-}" =~ ^[0-9]+$ ]]; then - mr="$1" - mode="${2:-}" -else - mr="$(glab mr view -F json | jq -r '.iid')" - mode="${1:-}" -fi -case "$mode" in - ""|--comments-only|--diff-only|--json) ;; - *) - printf 'Unknown mode: %s\n' "$mode" >&2 - printf 'Usage: %s [] [--comments-only|--diff-only|--json]\n' "$0" >&2 - exit 2 - ;; -esac - -if [ "$mode" = "--diff-only" ]; then - glab mr diff "$mr" - exit 0 -fi - -mr_json="$(glab mr view "$mr" -F json)" -discussions_json="$(glab api --paginate "projects/:id/merge_requests/$mr/discussions?per_page=100")" - -if [ "$mode" = "--json" ]; then - jq -n \ - --argjson mr "$mr_json" \ - --argjson discussions "$discussions_json" \ - '{ mr: $mr, discussions: $discussions }' - exit 0 -fi - -printf '## Note Summary\n' -jq -r \ - --argjson mr "$mr_json" ' - def summarize: (. // "" | gsub("\\s+"; " ") | .[0:180]); - "MR !\($mr.iid): \($mr.title)", - "Branch: \($mr.source_branch) -> \($mr.target_branch)", - "URL: \($mr.web_url)", - "", - "Standalone conversation notes (\([.[] | select(.individual_note == true)] | length)):", - ( .[] | select(.individual_note == true) | .notes[] | select(.system == false) - | "- discussion_id=\(.id // "?") note=\(.id) author=\(.author.username) updated=\(.updated_at): \(.body | summarize)" ), - "", - "Unresolved inline diff discussions:", - ( .[] | select(.individual_note != true) | . as $d - | select([.notes[] | select(.resolvable == true and .resolved == false)] | length > 0) - | .notes[0] as $n - | "- discussion_id=\($d.id) \($n.position.new_path // $n.position.old_path // "?"):\($n.position.new_line // $n.position.old_line // "?") author=\($n.author.username) updated=\($n.updated_at): \($n.body | summarize)" ) - ' <<<"$discussions_json" - -printf '\n## MR\n' -printf '%s\n' "$mr_json" - -printf '\n## Discussions\n' -printf '%s\n' "$discussions_json" - -if [ "$mode" = "--comments-only" ]; then - exit 0 -fi - -printf '\n## Diff\n' -glab mr diff "$mr" diff --git a/core/agents/skills/gitlab-mr-comments/scripts/reply-to-mr-comment.sh b/core/agents/skills/gitlab-mr-comments/scripts/reply-to-mr-comment.sh deleted file mode 100755 index 791e976..0000000 --- a/core/agents/skills/gitlab-mr-comments/scripts/reply-to-mr-comment.sh +++ /dev/null @@ -1,33 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -if [ "$#" -eq 1 ]; then - mr="$(glab mr view -F json | jq -r '.iid')" - replies_json="$1" -elif [ "$#" -eq 2 ] && [[ "$1" =~ ^[0-9]+$ ]]; then - mr="$1" - replies_json="$2" -else - printf 'Usage: %s [] \n' "$0" >&2 - exit 2 -fi - -if ! jq -e 'type == "array" and all(.[]; (.discussion_id | type == "string") and (.body | type == "string"))' \ - >/dev/null <<<"$replies_json"; then - printf 'Reply JSON must be an array of { "discussion_id": string, "body": string } objects.\n' >&2 - exit 2 -fi - -count=$(jq length <<<"$replies_json") -printf 'Posting %d replies to MR !%s...\n' "$count" "$mr" - -while IFS= read -r reply; do - discussion_id=$(jq -r '.discussion_id' <<<"$reply") - body=$(jq -r '.body' <<<"$reply") - - printf ' Replying to discussion %s... ' "$discussion_id" - glab mr note create "$mr" --reply "$discussion_id" -m "$body" - printf 'done\n' -done < <(jq -c '.[]' <<<"$replies_json") - -printf 'All %d replies posted.\n' "$count" From 43628bf0c189249021495b9df01edecdd35f6eb1 Mon Sep 17 00:00:00 2001 From: Simon Flandergan Date: Sun, 28 Jun 2026 16:29:28 +0200 Subject: [PATCH 38/65] Move neutral skill rationale into READMEs --- .../skills/change-request-comments/README.md | 27 +++++++++++++++++ .../skills/change-request-publish/README.md | 30 +++++++++++++++++++ .../skills/change-request-publish/SKILL.md | 4 --- core/agents/skills/git-publish/README.md | 18 +++++++++++ core/agents/skills/git-publish/SKILL.md | 4 --- core/agents/skills/issue-tracker/README.md | 24 +++++++++++++++ 6 files changed, 99 insertions(+), 8 deletions(-) create mode 100644 core/agents/skills/change-request-comments/README.md create mode 100644 core/agents/skills/change-request-publish/README.md create mode 100644 core/agents/skills/git-publish/README.md create mode 100644 core/agents/skills/issue-tracker/README.md diff --git a/core/agents/skills/change-request-comments/README.md b/core/agents/skills/change-request-comments/README.md new file mode 100644 index 0000000..4bd58a7 --- /dev/null +++ b/core/agents/skills/change-request-comments/README.md @@ -0,0 +1,27 @@ +# change-request-comments — Design Rationale + +## Why a host-agnostic comment skill exists + +Pull request and merge request comments have different APIs, data models, and CLI tools on GitHub (`gh`) and GitLab (`glab`). A host-agnostic skill lets agents read and reply to change-request comments without needing to know which provider hosts the repository. + +## Host detection + +The scripts read `git remote get-url origin` to determine the host: + +- GitHub → uses `gh` CLI and GraphQL to fetch issue comments, inline review threads, and PR diff. +- GitLab → uses `glab` CLI to fetch discussions and MR diff. + +The PR/MR number can be auto-detected from the current branch when omitted. + +## Provider-specific reply formats + +The reply payload format differs between providers: + +- GitHub replies target `comment_id` (a numeric ID) and are posted via `gh api`. +- GitLab replies target `discussion_id` (a string ID) and are posted inside existing discussion threads via `glab mr note create`. + +The `reply-to-comment.sh` script abstracts these differences behind a unified JSON interface. + +## Why provider-specific CLIs should not be called directly from workflow files + +Calling `gh` or `glab` directly from workflow files couples those files to a specific provider. The comment skill handles host detection and format translation, so workflow instructions should tell agents to use the `change-request-comments` skill by name. diff --git a/core/agents/skills/change-request-publish/README.md b/core/agents/skills/change-request-publish/README.md new file mode 100644 index 0000000..81455e4 --- /dev/null +++ b/core/agents/skills/change-request-publish/README.md @@ -0,0 +1,30 @@ +# change-request-publish — Design Rationale + +## Why a script, not a raw `gh pr create` or `glab mr create` + +The `open-change-request.sh` script inspects the current branch, checks whether a change request already exists, and then delegates to the correct provider CLI (`gh` for GitHub, `glab` for GitLab). This means workflow-facing files never need to know whether the repository is hosted on GitHub or GitLab. + +## Host detection + +The script reads `git remote get-url origin` to determine the host: + +- `github.com` or `git@github.com:` → opens a pull request with `gh pr create`. +- Otherwise (commonly GitLab, including self-hosted instances) → opens a merge request with `glab mr create`. + +## Branch guard + +Refuses to open a change request when the current branch is `main`, `master`, or a detached `HEAD`. + +## Idempotency + +If a change request already exists for the current branch, the script prints the existing one and exits 0 instead of creating a duplicate. + +## Provider differences + +- GitHub pull requests use `gh pr create` with `--title` and `--body`. +- GitLab merge requests use `glab mr create` with `--title` and `--description`. +- The script abstracts these differences so callers use a single interface. + +## Why workflow files should not call provider CLIs directly + +Any workflow file that calls `gh pr create` or `glab mr create` directly bypasses the host detection, branch guard, and idempotency checks. Workflow instructions should tell agents to use the `change-request-publish` skill by name rather than invoking provider CLIs directly. diff --git a/core/agents/skills/change-request-publish/SKILL.md b/core/agents/skills/change-request-publish/SKILL.md index 1864bd8..25f51c0 100644 --- a/core/agents/skills/change-request-publish/SKILL.md +++ b/core/agents/skills/change-request-publish/SKILL.md @@ -8,10 +8,6 @@ user-invocable: false Safe publishing for any Git-hosted repository. Opening a change request (pull request or merge request) goes through a bundled script that **detects the host** from the remote URL and delegates to the appropriate CLI. -## Why a script, not a raw `gh pr create` or `glab mr create` - -The script inspects the current branch, checks whether a change request already exists, and then delegates to the correct provider CLI. This means workflow-facing files never need to know whether the repository is hosted on GitHub or GitLab. - ## Open a change request ```bash diff --git a/core/agents/skills/git-publish/README.md b/core/agents/skills/git-publish/README.md new file mode 100644 index 0000000..9b7dc18 --- /dev/null +++ b/core/agents/skills/git-publish/README.md @@ -0,0 +1,18 @@ +# git-publish — Design Rationale + +## Why a script, not a raw `git push` + +`git push origin $(git rev-parse --abbrev-ref HEAD)` does **not** protect `main`: while you are on `main` it expands to `git push origin main`, and permission globs cannot see through the command substitution to block it. The guard has to inspect the current branch at run time, which is what the `push-branch.sh` script does. + +## Host detection + +The script reads `git remote get-url origin` to determine the remote, then pushes to that remote. No hardcoded remote name is assumed. + +## Branch and default-branch guards + +- Refuses to push when the current branch is `main`, `master`, or a detached `HEAD`. +- Refuses any `--force`, `-f`, or `--force-with-lease` argument — force-pushing is out of scope for this skill. + +## Why workflow-facing files should not call `git push` directly + +Any workflow file that calls `git push` bypasses the branch guard. The protection only holds if publishing goes through this script. Workflow instructions should tell agents to use the `git-publish` skill by name rather than invoking `git push` directly. diff --git a/core/agents/skills/git-publish/SKILL.md b/core/agents/skills/git-publish/SKILL.md index 3db4f0e..5fb2b3b 100644 --- a/core/agents/skills/git-publish/SKILL.md +++ b/core/agents/skills/git-publish/SKILL.md @@ -8,10 +8,6 @@ user-invocable: false Safe publishing for any Git-hosted repository. Pushing goes through a bundled script that **refuses to act on `main`/`master`** and refuses force-pushes. -## Why a script, not a raw `git push` - -`git push origin $(git rev-parse --abbrev-ref HEAD)` does **not** protect `main`: while you are on `main` it expands to `git push origin main`, and permission globs cannot see through the command substitution to block it. The guard has to inspect the current branch at run time, which is what this script does. - ## Push the current branch ```bash diff --git a/core/agents/skills/issue-tracker/README.md b/core/agents/skills/issue-tracker/README.md new file mode 100644 index 0000000..dd0c9b3 --- /dev/null +++ b/core/agents/skills/issue-tracker/README.md @@ -0,0 +1,24 @@ +# issue-tracker — Design Rationale + +## Why a host-agnostic issue tracker wrapper exists + +GitHub and GitLab have different CLI tools (`gh` and `glab`) and slightly different flags for issue operations. A host-agnostic skill lets agents create, update, and search for issues without needing to know which provider hosts the repository. + +## Host detection + +All scripts read `git remote get-url origin` to determine the host: + +- GitHub → delegates to `gh issue ...` commands. +- GitLab → delegates to `glab issue ...` commands. + +## Provider differences abstracted by the scripts + +| Operation | GitHub (`gh`) | GitLab (`glab`) | +|---|---|---| +| Create issue | `gh issue create --title ... --body-file ... --label ...` | `glab issue create --title ... --description ... --label ...` | +| Update issue | `gh issue edit --body-file ...` | `glab issue update --description ...` | +| Search issues | `gh issue list --search ... --label ... --json ...` | `glab issue list --search ... --label ... --output json` | + +## Why provider CLIs should not be called directly from workflow files + +Calling `gh` or `glab` directly from workflow files couples those files to a specific provider. The issue-tracker skill handles host detection and flag translation, so workflow instructions should tell agents to use the `issue-tracker` skill by name. From db075e2c9e5c860c41225f2dcb99da3389db4b3b Mon Sep 17 00:00:00 2001 From: Simon Flandergan Date: Sun, 28 Jun 2026 16:32:08 +0200 Subject: [PATCH 39/65] Use skill-level instructions in workflow files --- .../skills/workflow-bug-analysis/SKILL.md | 25 +++---------------- core/claude/skills/brainstorm/SKILL.md | 4 +-- core/claude/skills/bugfix/SKILL.md | 4 +-- core/claude/skills/finish/SKILL.md | 2 +- core/claude/skills/implement/SKILL.md | 2 +- core/claude/skills/planner/SKILL.md | 4 +-- core/claude/skills/review-plan/SKILL.md | 4 +-- core/opencode/agents/brainstorm.md | 2 +- core/opencode/agents/bugfix.md | 2 +- core/opencode/agents/finish.md | 2 +- core/opencode/agents/implement.md | 6 ++--- core/opencode/agents/planner.md | 2 +- core/opencode/agents/review-plan.md | 2 +- 13 files changed, 21 insertions(+), 40 deletions(-) diff --git a/core/agents/skills/workflow-bug-analysis/SKILL.md b/core/agents/skills/workflow-bug-analysis/SKILL.md index 9a565fa..d99de10 100644 --- a/core/agents/skills/workflow-bug-analysis/SKILL.md +++ b/core/agents/skills/workflow-bug-analysis/SKILL.md @@ -86,33 +86,14 @@ Structure findings into the issue template and save to `.temp/-issue-body. ### 7. Create the issue -First, check for duplicate issues: +First, use `issue-tracker` to check for duplicate issues. If duplicates exist, link to them in the issue body. Then use `issue-tracker` to create the issue with the title, body file, and labels. -```bash -bash .agents/skills/issue-tracker/scripts/find-duplicate-issues.sh \ - --title "Concise bug summary" -``` - -If duplicates exist, link to them in the issue body. Then create the issue: - -```bash -bash .agents/skills/issue-tracker/scripts/create-issue.sh \ - --title "Concise bug summary" \ - --body-file .temp/-issue-body.md \ - --labels "bug" -``` - -The script prints the created issue URL. Report this URL to the user. +The skill prints the created issue URL. Report this URL to the user. ## Follow-up Evidence If the user provides additional evidence after the issue is created: 1. Update the issue body file in `.temp/` -2. Use `issue-tracker/scripts/update-issue.sh` to push the update: - ```bash - bash .agents/skills/issue-tracker/scripts/update-issue.sh \ - --issue \ - --body-file .temp/-issue-body-updated.md - ``` +2. Use `issue-tracker` to update the issue with the updated body file 3. Report the updated issue URL diff --git a/core/claude/skills/brainstorm/SKILL.md b/core/claude/skills/brainstorm/SKILL.md index 59dc64c..d22f661 100644 --- a/core/claude/skills/brainstorm/SKILL.md +++ b/core/claude/skills/brainstorm/SKILL.md @@ -32,8 +32,8 @@ Use `grill-with-docs` when the brainstorm needs domain grilling. `mkdir -p plans/2026-05-30-feature-name`). Avoid absolute workspace paths unless a tool requires them. - Publish through the neutral git-publish skill: - - Push the current branch with `bash .claude/skills/git-publish/scripts/push-branch.sh`. - - Open a change request with `bash .claude/skills/change-request-publish/scripts/open-change-request.sh` when needed. + - Push the current branch with `git-publish`. + - Open a change request with `change-request-publish` when needed. Never hand-roll `git push`. ## Stop conditions diff --git a/core/claude/skills/bugfix/SKILL.md b/core/claude/skills/bugfix/SKILL.md index d25ed29..7b56fb4 100644 --- a/core/claude/skills/bugfix/SKILL.md +++ b/core/claude/skills/bugfix/SKILL.md @@ -32,7 +32,7 @@ when their questions are independent. 3. **Hypothesize** — Form a root-cause hypothesis based on gathered evidence. -4. **Create the issue** — Use `issue-tracker/scripts/find-duplicate-issues.sh` for duplicate checks and `issue-tracker/scripts/create-issue.sh` to file the tracker issue using the +4. **Create the issue** — Use `issue-tracker` to check for duplicates and create the tracker issue using the `workflow-bug-analysis` skill for content. 5. **Report and stop** — Report the issue URL. The job is done. @@ -47,7 +47,7 @@ using the `workflow-bug-analysis` skill and report the updated issue URL. - Never commit, push, or create PRs. Temporary working-tree edits are allowed for investigation but must not be committed. - Never call `gh` or `glab` directly — use the `issue-tracker` scripts for issue mutations. -- Use `issue-tracker/scripts/find-duplicate-issues.sh` for duplicate checking. +- Use `issue-tracker` for duplicate checking. - Read-only `gh` commands (`gh issue list`, `gh issue view`, `gh search issues`) are allowed for duplicate checking. - If the bug cannot be investigated with the available evidence, say so and list what diff --git a/core/claude/skills/finish/SKILL.md b/core/claude/skills/finish/SKILL.md index fe124aa..ba45960 100644 --- a/core/claude/skills/finish/SKILL.md +++ b/core/claude/skills/finish/SKILL.md @@ -48,7 +48,7 @@ explore subagent with a focused question. files; use plain `rm` only for untracked paths. 5. **Commit and push.** Commit the feature doc and cleanup when the user requests it, then push using the neutral git-publish skill: - - Push the current branch with `bash .claude/skills/git-publish/scripts/push-branch.sh`. + - Push the current branch with `git-publish`. ## Push boundaries diff --git a/core/claude/skills/implement/SKILL.md b/core/claude/skills/implement/SKILL.md index e616936..f5d8219 100644 --- a/core/claude/skills/implement/SKILL.md +++ b/core/claude/skills/implement/SKILL.md @@ -47,6 +47,6 @@ Run targeted verification while iterating and the required final verification be ## Finishing After final verification, commit all changes and push the branch using the neutral git-publish skill. -Open a change request with `bash .claude/skills/change-request-publish/scripts/open-change-request.sh` when needed. +Open a change request with `change-request-publish` when needed. The publish scripts refuse `main`/`master` and skip creation when a PR/MR already exists for the branch. diff --git a/core/claude/skills/planner/SKILL.md b/core/claude/skills/planner/SKILL.md index 2798cba..bb0509a 100644 --- a/core/claude/skills/planner/SKILL.md +++ b/core/claude/skills/planner/SKILL.md @@ -67,8 +67,8 @@ inlining them here. `mkdir -p plans/2026-05-30-feature-name`). Avoid absolute workspace paths unless a tool requires them. - Publish through the neutral git-publish skill: - - Push the current branch with `bash .claude/skills/git-publish/scripts/push-branch.sh`. - - Open a change request with `bash .claude/skills/change-request-publish/scripts/open-change-request.sh` when needed. + - Push the current branch with `git-publish`. + - Open a change request with `change-request-publish` when needed. Never hand-roll `git push`. ## Stop conditions diff --git a/core/claude/skills/review-plan/SKILL.md b/core/claude/skills/review-plan/SKILL.md index 4a1888f..f0b0745 100644 --- a/core/claude/skills/review-plan/SKILL.md +++ b/core/claude/skills/review-plan/SKILL.md @@ -78,8 +78,8 @@ document. The gate is approval, not capability: 4. Report the finalized plan path and confirm it is ready for implementation handoff. Publish through the neutral git-publish skill: -- Push the current branch with `bash .claude/skills/git-publish/scripts/push-branch.sh`. -- Open a change request with `bash .claude/skills/change-request-publish/scripts/open-change-request.sh` when needed. +- Push the current branch with `git-publish`. +- Open a change request with `change-request-publish` when needed. Never hand-roll `git push`. ## External / change-request comments diff --git a/core/opencode/agents/brainstorm.md b/core/opencode/agents/brainstorm.md index 7f89811..844ade3 100644 --- a/core/opencode/agents/brainstorm.md +++ b/core/opencode/agents/brainstorm.md @@ -83,6 +83,6 @@ Shell guidance: - Prefer relative workspace paths in shell commands and examples (e.g., `mkdir -p plans/2026-05-25-feature-name`). - Avoid absolute workspace paths in shell commands unless a tool explicitly requires them. -- Push the branch with `bash .agents/skills/git-publish/scripts/push-branch.sh`. Never hand-roll `git push`. +- Push the branch with `git-publish`. Never hand-roll `git push`. When writing specs, include goal, non-goals, architecture, data flow, testing expectations, rollout or migration notes, and open questions if any remain. diff --git a/core/opencode/agents/bugfix.md b/core/opencode/agents/bugfix.md index 6104b81..856e1ae 100644 --- a/core/opencode/agents/bugfix.md +++ b/core/opencode/agents/bugfix.md @@ -65,7 +65,7 @@ Your job is to investigate bugs and produce a well-structured tracker issue. You 1. **Intake** — Read the user's input (error log, stack trace, or behavior description). Classify the input type and extract key signals. 2. **Investigate** — Use the `workflow-bug-analysis` skill methodology. Launch `@explore` subagents when you need focused repository investigation. 3. **Hypothesize** — Form a root-cause hypothesis based on gathered evidence. -4. **Create the issue** — Use `issue-tracker/scripts/find-duplicate-issues.sh` for duplicate checks and `issue-tracker/scripts/create-issue.sh` to file the tracker issue. +4. **Create the issue** — Use `issue-tracker` to check for duplicates and create the tracker issue. 5. **Report and stop** — Report the issue URL. ## Subagent usage diff --git a/core/opencode/agents/finish.md b/core/opencode/agents/finish.md index 3663814..192f7ad 100644 --- a/core/opencode/agents/finish.md +++ b/core/opencode/agents/finish.md @@ -78,6 +78,6 @@ Finish workflow: 3. Treat the feature doc as durable reference documentation, not a project-status report. 4. Reconcile the domain docs: if implementation or review changed the domain language, or introduced or invalidated a decision, update the relevant `docs/contexts//CONTEXT.md` glossary and add or supersede ADRs under `docs/adr/` before finalizing. This is offered reconciliation, not a full grilling session — use `grill-with-docs` only when a divergence genuinely needs interrogating. Keep `CONTEXT.md` a glossary only. 5. Remove both `plans/YYYY-MM-DD-feature-name/spec.md` and `plans/YYYY-MM-DD-feature-name/plan.md` after the feature doc is written. Use `git rm` for tracked plan files. Use plain `rm` only for untracked paths. -6. Commit the feature doc and cleanup, then publish. Push the branch with `bash .agents/skills/git-publish/scripts/push-branch.sh`. To open a change request, use `bash .agents/skills/change-request-publish/scripts/open-change-request.sh` if needed. +6. Commit the feature doc and cleanup, then publish. Push the branch with `git-publish`. To open a change request, use `change-request-publish` if needed. Push automatically only through the publish skill. Never hand-roll `git push`, push to `main`, force-push, delete remote refs, push tags, or push arbitrary refspecs without explicit approval. Do not create change requests manually, amend commits, delete branches, close comments, or remove worktrees. diff --git a/core/opencode/agents/implement.md b/core/opencode/agents/implement.md index 374fbe2..70e1e69 100644 --- a/core/opencode/agents/implement.md +++ b/core/opencode/agents/implement.md @@ -97,8 +97,8 @@ Execution rules: - Never implement on `main`; create or ask for a scoped branch if needed. - Prefer `git mv` for moves and renames of tracked paths. Use plain `mv` only for untracked paths or operations git cannot express cleanly. - Prefer `git rm` for removals of tracked paths. Use plain `rm` only for untracked paths. -- Push the branch with `bash .agents/skills/git-publish/scripts/push-branch.sh`, which refuses `main`. Never hand-roll `git push`: `git push origin $(...)` silently pushes `main` when the current branch is `main`. -- To open a change request, use `bash .agents/skills/change-request-publish/scripts/open-change-request.sh` — it skips creation when one already exists for the current branch. +- Push the branch with `git-publish` (refuses `main`). Never hand-roll `git push`: `git push origin $(...)` silently pushes `main` when the current branch is `main`. +- To open a change request, use `change-request-publish` — it skips creation when one already exists for the current branch. - **Default behavior:** Execute the plan task-by-task by dispatching a fresh `@implement-task` worker for each task. This is the standard workflow — do not deviate unless the user explicitly requests inline implementation. - **Inline implementation:** Acceptable only when the user explicitly asks you to implement directly rather than delegating. When executing inline, apply the same task/review gates as delegated workers. - **Controller duties:** Your primary role is orchestration — dispatch tasks, package context for workers, review worker reports and diffs, enforce spec compliance and code quality review gates, and run verification before any completion claim. @@ -110,6 +110,6 @@ Execution rules: - Stop and ask for feedback only when the same task fails more than 3 times, the plan conflicts with code reality, or an architectural decision is required. - If a task is too complex or requires an architectural decision, report the blocker and recommend human escalation. - Run targeted verification while iterating and the required final verification before claiming completion. -- After final verification, commit all changes and publish. Push the branch with `bash .agents/skills/git-publish/scripts/push-branch.sh`, then open a change request with `bash .agents/skills/change-request-publish/scripts/open-change-request.sh` (no-ops when one already exists for the current branch). The push script refuses `main`. +- After final verification, commit all changes and publish. Push the branch with `git-publish`, then open a change request with `change-request-publish` (no-ops when one already exists for the current branch). The push script refuses `main`. Use `workflow-verification` before any completion claim. Do not say work is complete, fixed, or passing unless the relevant commands have just run successfully. diff --git a/core/opencode/agents/planner.md b/core/opencode/agents/planner.md index 71c8ee4..f429530 100644 --- a/core/opencode/agents/planner.md +++ b/core/opencode/agents/planner.md @@ -77,7 +77,7 @@ Shell guidance: - Prefer relative workspace paths in shell commands and examples (e.g., `mkdir -p plans/2026-05-25-feature-name`). - Avoid absolute workspace paths in shell commands unless a tool explicitly requires them. -- Push the branch with `bash .agents/skills/git-publish/scripts/push-branch.sh`. Never hand-roll `git push`. +- Push the branch with `git-publish`. Never hand-roll `git push`. Do not invoke brainstorming automatically. If requirements are unclear enough that planning would be speculative, ask the user whether to switch to `@brainstorm`. diff --git a/core/opencode/agents/review-plan.md b/core/opencode/agents/review-plan.md index 500d668..4ed94ac 100644 --- a/core/opencode/agents/review-plan.md +++ b/core/opencode/agents/review-plan.md @@ -71,4 +71,4 @@ Use this standard review-plan workflow unless the user explicitly requests a dif When reviewing external comments, use `change-request-comments`. Always check open change request comments by default unless the user explicitly says not to. Verify each technical claim before recommending changes. Suggest changes only. Before posting any comment reply, present the exact draft reply and wait for explicit user approval. Approval to edit `plans/**` does not authorize posting comments. -Push the branch with `bash .agents/skills/git-publish/scripts/push-branch.sh`. Never hand-roll `git push`. +Push the branch with `git-publish`. Never hand-roll `git push`. From 1b79d0dd061e3a9535823d296cea51d9bb60245b Mon Sep 17 00:00:00 2001 From: Simon Flandergan Date: Sun, 28 Jun 2026 16:34:41 +0200 Subject: [PATCH 40/65] Align OpenCode permissions for neutral repository skills --- core/opencode/agents/brainstorm.md | 2 ++ core/opencode/agents/bugfix.md | 1 + core/opencode/agents/planner.md | 1 + core/opencode/agents/review-code.md | 6 ++++++ core/opencode/agents/review-plan.md | 1 + 5 files changed, 11 insertions(+) diff --git a/core/opencode/agents/brainstorm.md b/core/opencode/agents/brainstorm.md index 844ade3..4105256 100644 --- a/core/opencode/agents/brainstorm.md +++ b/core/opencode/agents/brainstorm.md @@ -48,6 +48,8 @@ permission: "*": deny "workflow-brainstorming": allow "grill-with-docs": allow + "git-publish": allow + "change-request-publish": allow --- You are the explicit brainstorming agent. diff --git a/core/opencode/agents/bugfix.md b/core/opencode/agents/bugfix.md index 856e1ae..fd62c24 100644 --- a/core/opencode/agents/bugfix.md +++ b/core/opencode/agents/bugfix.md @@ -52,6 +52,7 @@ permission: skill: "*": deny "workflow-bug-analysis": allow + "issue-tracker": allow --- You are the bugfix analysis agent. diff --git a/core/opencode/agents/planner.md b/core/opencode/agents/planner.md index f429530..a944e47 100644 --- a/core/opencode/agents/planner.md +++ b/core/opencode/agents/planner.md @@ -48,6 +48,7 @@ permission: "*": deny "workflow-planning": allow "grill-with-docs": allow + "git-publish": allow --- You are the planning agent. diff --git a/core/opencode/agents/review-code.md b/core/opencode/agents/review-code.md index dc53eed..c3dfd96 100644 --- a/core/opencode/agents/review-code.md +++ b/core/opencode/agents/review-code.md @@ -26,6 +26,10 @@ permission: "git push *": ask + "bash .agents/skills/git-publish/scripts/push-branch.sh*": allow + + "bash .agents/skills/change-request-publish/scripts/open-change-request.sh*": ask + "bash .agents/skills/change-request-comments/scripts/fetch-comments.sh *": allow 'bash ".agents/skills/change-request-comments/scripts/fetch-comments.sh" *': allow "bash .agents/skills/change-request-comments/scripts/reply-to-comment.sh *": ask @@ -37,6 +41,8 @@ permission: skill: "*": deny "change-request-comments": allow + "git-publish": allow + "change-request-publish": allow --- You are the code review agent. diff --git a/core/opencode/agents/review-plan.md b/core/opencode/agents/review-plan.md index 4ed94ac..c2ff5e2 100644 --- a/core/opencode/agents/review-plan.md +++ b/core/opencode/agents/review-plan.md @@ -34,6 +34,7 @@ permission: skill: "*": deny "change-request-comments": allow + "git-publish": allow --- You are the spec and plan review agent. From 92d505189d51a7c03c47d53f68b731b497f64faf Mon Sep 17 00:00:00 2001 From: Simon Flandergan Date: Sun, 28 Jun 2026 16:37:42 +0200 Subject: [PATCH 41/65] Sync installers and docs with neutral comment skill --- README.md | 9 ++++----- core/claude/README.md | 17 ++++++++--------- core/docs/agents/agent-workflow-extension.md | 2 +- scripts/copy.sh | 2 -- scripts/init.sh | 2 -- 5 files changed, 13 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index 528a11b..c1e0492 100644 --- a/README.md +++ b/README.md @@ -101,7 +101,7 @@ Under `.claude/skills/` (all marked `disable-model-invocation: true`): Under `.agents/skills/`: -`grill-with-docs`, `workflow-bug-analysis`, `workflow-brainstorming`, `workflow-planning`, `workflow-implementation`, `workflow-verification`, `feature-documentation`, `git-publish`, `change-request-publish`, `change-request-comments`, `issue-tracker`, `github-pr-comments`, `gitlab-mr-comments` +`grill-with-docs`, `workflow-bug-analysis`, `workflow-brainstorming`, `workflow-planning`, `workflow-implementation`, `workflow-verification`, `feature-documentation`, `git-publish`, `change-request-publish`, `change-request-comments`, `issue-tracker` ### DDD Docs @@ -140,8 +140,7 @@ The workflow entry skills are real directories. The authored skills are symlinke | `change-request-publish` | `../../.agents/skills/change-request-publish` | | `change-request-comments` | `../../.agents/skills/change-request-comments` | | `issue-tracker` | `../../.agents/skills/issue-tracker` | -| `github-pr-comments` | `../../.agents/skills/github-pr-comments` | -| `gitlab-mr-comments` | `../../.agents/skills/gitlab-mr-comments` | +| `workflow-implementation` | `../../.agents/skills/workflow-implementation` | Each symlinked skill has `user-invocable: false` in its `SKILL.md` frontmatter so it stays hidden from Claude Code's user-facing skill list. @@ -221,10 +220,10 @@ Under `.agents/skills/` (symlinked into `.claude/skills/` for Claude Code compat | `agent-implementation` | Controller orchestration, worker status handling, completion | | `agent-verification` | Evidence-before-claims gate, verification commands, smoke runs | | `agent-review` | Plan + diff review checklist aligned to `AGENTS.md` | -| `github-pr-comments` | PR comment fetching, classification, and reply workflow | +| `change-request-comments` | Comment fetching, classification, and reply workflow | | `writing-skills` | Remote skill from `obra/superpowers` for authoring skills | -Invoke in Claude Code with `/agent-planning`, `/agent-implementation`, `/agent-verification`, `/agent-review`, or `/github-pr-comments`. The `writing-skills` skill is also exposed as `/writing-skills`. +Invoke in Claude Code with `/agent-planning`, `/agent-implementation`, `/agent-verification`, `/agent-review`, or `/change-request-comments`. The `writing-skills` skill is also exposed as `/writing-skills`. ### Lockfiles diff --git a/core/claude/README.md b/core/claude/README.md index f687cbc..54e931b 100644 --- a/core/claude/README.md +++ b/core/claude/README.md @@ -35,10 +35,9 @@ These shared skills are symlinked into `.claude/skills/` from `.agents/skills/`: - `workflow-planning` — used by `/planner` - `workflow-verification` — used by `/finish` - `feature-documentation` — used by `/finish` -- `github-pr-comments` — used by `/review-plan`, `/review-code` (+ OpenCode) -- `github-publish` — used by `/implement`, `/finish` (+ OpenCode) -- `gitlab-publish` — used by `/implement`, `/finish` (+ OpenCode; GitLab equivalent) -- `gitlab-mr-comments` — used by `/review-plan`, `/review-code` (+ OpenCode; GitLab equivalent of `github-pr-comments`) +- `change-request-comments` — used by `/review-plan`, `/review-code` (+ OpenCode) +- `git-publish` — used by `/implement`, `/finish` (+ OpenCode) +- `change-request-publish` — used by `/implement`, `/finish` (+ OpenCode) Remote skills (e.g. `context7-cli`, `next-best-practices`, `shadcn`, `zoom-out`, `write-a-skill`) are declared in `skills-lock.json` and installed via the @@ -71,8 +70,8 @@ All three skills load the shared `grill-with-docs` skill on demand. `review-plan`, `review-code`, `finish`. - **Symlinked shared skills (auto-invocable):** `grill-with-docs`, `workflow-bug-analysis`, `workflow-brainstorming`, `workflow-planning`, - `workflow-verification`, `feature-documentation`, `github-pr-comments`, - `github-publish`, `gitlab-publish`, `gitlab-mr-comments`. + `workflow-verification`, `feature-documentation`, `change-request-comments`, + `git-publish`, `change-request-publish`. To add a newly-installed shared skill: `ln -s ../../.agents/skills/ .claude/skills/`. `.claude/skills/` is hand-managed. @@ -81,9 +80,9 @@ To add a newly-installed shared skill: `settings.json` encodes the project-wide permission union the skills need: edit allowed; read-only git and common Unix commands allowed; `git push` / `gh pr create` / -`glab mr create` / `rm` ask first; branch-delete, worktree-remove denied. Both GitHub -and GitLab publish/comment skill scripts (`github-publish`, `gitlab-publish`, -`github-pr-comments`, `gitlab-mr-comments`) are available. +`glab mr create` / `rm` ask first; branch-delete, worktree-remove denied. The +`git-publish`, `change-request-publish`, and `change-request-comments` skill scripts +are available. ## Usage diff --git a/core/docs/agents/agent-workflow-extension.md b/core/docs/agents/agent-workflow-extension.md index f0c1ffe..314c055 100644 --- a/core/docs/agents/agent-workflow-extension.md +++ b/core/docs/agents/agent-workflow-extension.md @@ -12,7 +12,7 @@ Use this guide when changing coding assistant workflows, agents, or reusable ski ## Change-request comment workflow boundary - The `change-request-comments` skill owns reading change-request comments, classifying comment target types, obtaining exact IDs, and posting approved replies through project scripts. -- Provider-specific mechanics (`github-pr-comments`, `gitlab-mr-comments`, `gh`, `glab`) belong only in provider skills or neutral integration skills, never in generic workflow skills or agent instructions. +- Provider-specific mechanics (`gh`, `glab`, provider comment scripts) belong only in provider or boundary skills such as `change-request-comments`, never in generic workflow skills or agent instructions. - Review agents own deciding what the comments mean, validating technical claims, combining them with independent review findings, suggesting fixes, and requesting approval before edits or replies. ## Default placement rules diff --git a/scripts/copy.sh b/scripts/copy.sh index 1926b09..5551b58 100755 --- a/scripts/copy.sh +++ b/scripts/copy.sh @@ -472,8 +472,6 @@ AUTHORED_SKILLS=( change-request-publish change-request-comments issue-tracker - github-pr-comments - gitlab-mr-comments ) for skill_name in "${AUTHORED_SKILLS[@]}"; do src="$STAGE/.agents/skills/$skill_name" diff --git a/scripts/init.sh b/scripts/init.sh index 37ba827..d3c4a58 100755 --- a/scripts/init.sh +++ b/scripts/init.sh @@ -241,8 +241,6 @@ AUTHORED_SKILLS=( "change-request-publish" "change-request-comments" "issue-tracker" - "github-pr-comments" - "gitlab-mr-comments" ) mkdir -p "$TARGET/.claude/skills" From 071070edeabf597b760c2752b30119ce6d309268 Mon Sep 17 00:00:00 2001 From: Simon Flandergan Date: Sun, 28 Jun 2026 16:39:03 +0200 Subject: [PATCH 42/65] Normalize permissions for neutral repository workflows --- core/claude/settings.json | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/core/claude/settings.json b/core/claude/settings.json index 36d3f1d..cb46e01 100644 --- a/core/claude/settings.json +++ b/core/claude/settings.json @@ -5,7 +5,6 @@ "Grep(./**)", "Glob(./**)", "Read(./**)", - "Edit(./**)", "Write(./**)", @@ -19,6 +18,7 @@ "Bash(git ls-files:*)", "Bash(git branch:*)", "Bash(git checkout:*)", + "Bash(git add:*)", "Bash(git commit:*)", "Bash(git rm:*)", @@ -45,11 +45,12 @@ "Bash(bash .claude/skills/git-publish/scripts/push-branch.sh:*)", "Bash(bash .claude/skills/change-request-comments/scripts/fetch-comments.sh:*)", "Bash(bash .claude/skills/issue-tracker/scripts/create-issue.sh:*)", - "Bash(bash .claude/skills/issue-tracker/scripts/update-issue.sh:*)", "Bash(bash .claude/skills/issue-tracker/scripts/find-duplicate-issues.sh:*)", + "Bash(gh issue list:*)", "Bash(gh issue view:*)", "Bash(gh search issues:*)", + "Bash(glab issue list:*)", "Bash(glab issue view:*)" ], @@ -57,8 +58,10 @@ "Bash(git push:*)", "Bash(git push --force:*)", "Bash(git push -f:*)", + "Bash(rm:*)", "Bash(rm -rf:*)", + "Bash(bash .claude/skills/change-request-publish/scripts/open-change-request.sh:*)", "Bash(bash .claude/skills/change-request-comments/scripts/reply-to-comment.sh:*)", "Bash(bash .claude/skills/issue-tracker/scripts/update-issue.sh:*)" From 0cf9348fa626715a0af87e28c0d3f566766333f2 Mon Sep 17 00:00:00 2001 From: Simon Flandergan Date: Sun, 28 Jun 2026 16:40:00 +0200 Subject: [PATCH 43/65] Use neutral publish skills for repo maintenance --- AGENTS.md | 2 +- scripts/publish-branch.sh | 6 ------ 2 files changed, 1 insertion(+), 7 deletions(-) delete mode 100755 scripts/publish-branch.sh diff --git a/AGENTS.md b/AGENTS.md index 28148c0..1e2ed54 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -82,7 +82,7 @@ All smoke runs and throwaway work goes in `.temp/`, never `/tmp`. Clean up after - Branches use `feature/`, `fix/`, or `chore/` prefixes with short kebab-case descriptions. - Commits are concise, imperative, and focused on why. - Prefer `git mv` for moves/renames of tracked paths. Use `git rm` for removals of tracked paths. -- Use `scripts/publish-branch.sh` for branch publishing and PR creation so branch-safety checks are centralized. +- Use `git-publish` for branch pushes and `change-request-publish` for PR/MR creation so branch-safety checks are centralized. - Keep branch deletion, worktree removal, and force-push operations under explicit human control. - Write commits without `Co-Authored-By` trailers. diff --git a/scripts/publish-branch.sh b/scripts/publish-branch.sh deleted file mode 100755 index 1ca29a2..0000000 --- a/scripts/publish-branch.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -# Publish the current branch and open a change request if needed. -bash core/agents/skills/git-publish/scripts/push-branch.sh --set-upstream -bash core/agents/skills/change-request-publish/scripts/open-change-request.sh --fill From adf3b509fbdb8d2368cdc93ae0fed7284c578d69 Mon Sep 17 00:00:00 2001 From: Simon Flandergan Date: Sun, 28 Jun 2026 16:44:20 +0200 Subject: [PATCH 44/65] Check workflow files for skill-internal leakage --- scripts/check-workflow-boundaries.sh | 62 ++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/scripts/check-workflow-boundaries.sh b/scripts/check-workflow-boundaries.sh index c81fa60..b6995d8 100755 --- a/scripts/check-workflow-boundaries.sh +++ b/scripts/check-workflow-boundaries.sh @@ -55,4 +55,66 @@ if [[ "$FAILED" -ne 0 ]]; then exit 1 fi +# --- Skill-internal script path check --- +# Per the Skill Boundary Rule, body text should use skill names, not internal +# script paths like .agents/skills//scripts/*.sh. Only check body text +# (after YAML frontmatter) for OpenCode agent files. + +SCRIPT_PATH_PATTERNS=( + '\.agents/skills/.*/scripts/' + '\.claude/skills/.*/scripts/' +) + +# Boundary skill directories where script usage is the documented interface +BOUNDARY_SKILLS=( + core/agents/skills/git-publish + core/agents/skills/change-request-publish + core/agents/skills/change-request-comments + core/agents/skills/issue-tracker +) + +# Expand target globs to actual files +TARGET_FILES=() +for target in "${TARGETS[@]}"; do + while IFS= read -r file; do + [[ -f "$file" ]] && TARGET_FILES+=("$file") + done < <(find "$target" -name '*.md' -type f 2>/dev/null) +done + +if [[ ${#TARGET_FILES[@]} -eq 0 ]]; then + echo "OK: no workflow files found to check." >&2 + exit 0 +fi + +for file in "${TARGET_FILES[@]}"; do + # Skip boundary skill docs + skip=false + for boundary in "${BOUNDARY_SKILLS[@]}"; do + if [[ "$file" == "$boundary"/* ]]; then + skip=true + break + fi + done + [[ "$skip" == true ]] && continue + + # For OpenCode agent files, only check body text (after second ---) + if [[ "$file" == core/opencode/agents/*.md ]]; then + body=$(awk 'BEGIN{n=0} /^---$/{n++; next} n>=2{print}' "$file") + else + body=$(cat "$file") + fi + + for pattern in "${SCRIPT_PATH_PATTERNS[@]}"; do + if echo "$body" | rg -n "$pattern" 2>/dev/null; then + echo " ^ in $file" >&2 + FAILED=1 + fi + done +done + +if [[ "$FAILED" -ne 0 ]]; then + echo "ERROR: skill-internal script references found in workflow body text." >&2 + exit 1 +fi + echo "OK: no provider-internal leakage in generic workflow files." From 1083a75d224e63e234c9e8b7433cd9852055539f Mon Sep 17 00:00:00 2001 From: Simon Flandergan Date: Sun, 28 Jun 2026 17:06:49 +0200 Subject: [PATCH 45/65] Add self-maintenance symlinks for neutral publish skills --- .agents/skills/change-request-publish | 1 + .agents/skills/git-publish | 1 + .claude/skills/change-request-publish | 1 + .claude/skills/git-publish | 1 + 4 files changed, 4 insertions(+) create mode 120000 .agents/skills/change-request-publish create mode 120000 .agents/skills/git-publish create mode 120000 .claude/skills/change-request-publish create mode 120000 .claude/skills/git-publish diff --git a/.agents/skills/change-request-publish b/.agents/skills/change-request-publish new file mode 120000 index 0000000..38848a9 --- /dev/null +++ b/.agents/skills/change-request-publish @@ -0,0 +1 @@ +../../core/agents/skills/change-request-publish \ No newline at end of file diff --git a/.agents/skills/git-publish b/.agents/skills/git-publish new file mode 120000 index 0000000..a982c29 --- /dev/null +++ b/.agents/skills/git-publish @@ -0,0 +1 @@ +../../core/agents/skills/git-publish \ No newline at end of file diff --git a/.claude/skills/change-request-publish b/.claude/skills/change-request-publish new file mode 120000 index 0000000..d7afb8d --- /dev/null +++ b/.claude/skills/change-request-publish @@ -0,0 +1 @@ +../../.agents/skills/change-request-publish \ No newline at end of file diff --git a/.claude/skills/git-publish b/.claude/skills/git-publish new file mode 120000 index 0000000..8b6fd6a --- /dev/null +++ b/.claude/skills/git-publish @@ -0,0 +1 @@ +../../.agents/skills/git-publish \ No newline at end of file From 63fa67ea8a71b6693ee0590c5cf7db2737967844 Mon Sep 17 00:00:00 2001 From: Simon Flandergan Date: Sun, 28 Jun 2026 17:45:36 +0200 Subject: [PATCH 46/65] use all git skills internally --- .agents/skills/change-request-comments | 1 + .agents/skills/github-pr-comments/SKILL.md | 86 ------------ .../scripts/fetch-pr-comments.sh | 123 ------------------ .../scripts/reply-to-pr-comment.sh | 37 ------ .claude/skills/change-request-comments | 1 + .claude/skills/github-pr-comments | 1 - .../scripts/fetch-comments.sh | 0 .../scripts/reply-to-comment.sh | 0 .../scripts/open-change-request.sh | 0 .../skills/git-publish/scripts/push-branch.sh | 0 10 files changed, 2 insertions(+), 247 deletions(-) create mode 120000 .agents/skills/change-request-comments delete mode 100644 .agents/skills/github-pr-comments/SKILL.md delete mode 100644 .agents/skills/github-pr-comments/scripts/fetch-pr-comments.sh delete mode 100755 .agents/skills/github-pr-comments/scripts/reply-to-pr-comment.sh create mode 120000 .claude/skills/change-request-comments delete mode 120000 .claude/skills/github-pr-comments mode change 100644 => 100755 core/agents/skills/change-request-comments/scripts/fetch-comments.sh mode change 100644 => 100755 core/agents/skills/change-request-comments/scripts/reply-to-comment.sh mode change 100644 => 100755 core/agents/skills/change-request-publish/scripts/open-change-request.sh mode change 100644 => 100755 core/agents/skills/git-publish/scripts/push-branch.sh diff --git a/.agents/skills/change-request-comments b/.agents/skills/change-request-comments new file mode 120000 index 0000000..b23a4b8 --- /dev/null +++ b/.agents/skills/change-request-comments @@ -0,0 +1 @@ +../../core/agents/skills/change-request-comments \ No newline at end of file diff --git a/.agents/skills/github-pr-comments/SKILL.md b/.agents/skills/github-pr-comments/SKILL.md deleted file mode 100644 index 590741c..0000000 --- a/.agents/skills/github-pr-comments/SKILL.md +++ /dev/null @@ -1,86 +0,0 @@ ---- -name: github-pr-comments -description: Use when GitHub PR feedback lives in plain comments, inline comments, issue comments, or review threads -user-invocable: false ---- - -# GitHub PR Comments - -Use this for solo-maintainer PR review workflows where feedback is stored as plain GitHub comments rather than formal review submissions. - -## Baseline Failure To Avoid - -Agents naturally mix comment APIs: they may read reviews when feedback is actually an issue comment, post a top-level reply instead of an inline thread reply, or patch someone else's comment instead of posting a reply. - -## Skill Scope - -This skill owns PR comment mechanics: fetching comments and diffs, distinguishing issue comments from inline review comments, obtaining exact target IDs, and posting approved replies through project scripts. - -This skill does not own role-level review orchestration. The calling review agent decides how to interpret comments, validate technical claims, combine them with other findings, suggest fixes, edit files, dispatch implementers, or perform final self-review. - -## Read Comments - -Use the bundled read-only helper before proposing fixes. It fetches top-level issue comments, unresolved inline review threads, and the PR diff: - -```bash -bash .agents/skills/github-pr-comments/scripts/fetch-pr-comments.sh [] -``` - -When `` is omitted, the script auto-detects the PR number from the current branch. - -Run the command exactly as shown, without quoting the script path. The review-code agent has explicit auto-permissions for this command form. - -The helper prints a compact comment summary first, then full PR metadata, issue comments, inline comments, and the PR diff. Use the summary for grouping and the full JSON sections for exact `databaseId` values. - -Optional read-only modes: - -```bash -bash .agents/skills/github-pr-comments/scripts/fetch-pr-comments.sh [] --comments-only -bash .agents/skills/github-pr-comments/scripts/fetch-pr-comments.sh [] --diff-only -bash .agents/skills/github-pr-comments/scripts/fetch-pr-comments.sh [] --json -``` - -Do not call the GitHub CLI directly for reading PR metadata, issue comments, inline comments, or diffs. The helper is the stable interface for this workflow. - -## Classify Comments - -- Issue comments: top-level PR conversation, fetched from `issues//comments`. -- Inline PR comments: unresolved diff review-thread comments, fetched through GitHub GraphQL `reviewThreads`. -- Outdated inline comments may still be valid; verify against current diff before dismissing. - -## Review Workflow - -1. Fetch PR comments and diff when the caller's workflow involves a PR. -2. Use the summary to group target types, then use the full JSON sections for exact `databaseId` values. -3. Distinguish top-level issue comments from inline review comments before posting replies. -4. Surface outdated inline comments as comment metadata/context; the calling review agent decides whether they still apply. -5. For posting, require an exact approved reply batch with target type, target ID when available, and body. -6. Post only the exact approved reply batch. - -## Replies - -Replying mutates GitHub state, so it is not hidden behind the read helper. Approval for edits, fixes, planning, or any other non-GitHub action does not authorize posting GitHub comments. - -Before posting, present the exact reply batch to the user. Include the target type (`issue comment` or `inline review comment`), target ID when available, and body. Wait for explicit approval for that batch. - -After approval, post inline review replies through the project script. Use the numeric `databaseId` from the read helper as `comment_id`: - -Pass a JSON array as the final argument: - -```bash -bash .agents/skills/github-pr-comments/scripts/reply-to-pr-comment.sh [] '[ - { "comment_id": 123456, "body": "Fixed in abc123." }, - { "comment_id": 789012, "body": "Good catch, updated." } -]' -``` - -The PR number is optional; when omitted, the script auto-detects it from the current branch. Use a one-element array for a single reply. This script replies to inline PR review comments only; it does not reply to top-level issue comments. - -## Common Mistakes - -- Treating top-level PR comments as complete enough for inline review. -- Posting a top-level PR comment when the user asked to reply to an inline thread. -- Resolving, editing, or deleting comments without explicit approval. -- Applying external feedback without checking whether it is technically correct. -- Treating approval for edits, fixes, planning, or other non-GitHub work as approval to post GitHub replies. -- Posting a reply batch that differs from the exact batch the user approved. diff --git a/.agents/skills/github-pr-comments/scripts/fetch-pr-comments.sh b/.agents/skills/github-pr-comments/scripts/fetch-pr-comments.sh deleted file mode 100644 index b063f40..0000000 --- a/.agents/skills/github-pr-comments/scripts/fetch-pr-comments.sh +++ /dev/null @@ -1,123 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -if [ "$#" -gt 2 ]; then - printf 'Usage: %s [] [--comments-only|--diff-only|--json]\n' "$0" >&2 - exit 2 -fi - -if [[ "${1:-}" =~ ^[0-9]+$ ]]; then - pr="$1" - mode="${2:-}" -else - pr="$(gh pr view --json number --jq '.number')" - mode="${1:-}" -fi -case "$mode" in - ""|--comments-only|--diff-only|--json) ;; - *) - printf 'Unknown mode: %s\n' "$mode" >&2 - printf 'Usage: %s [] [--comments-only|--diff-only|--json]\n' "$0" >&2 - exit 2 - ;; -esac - -if [ "$mode" = "--diff-only" ]; then - gh pr diff "$pr" - exit 0 -fi - -pr_json="$(gh pr view "$pr" --json number,title,headRefName,baseRefName,url,comments,headRepository)" -repo=$(jq -r '.headRepository.nameWithOwner' <<<"$pr_json") -issue_comments_json="$(gh api "repos/$repo/issues/$pr/comments")" -inline_comments_json="$(gh api graphql \ - -F owner="${repo%%/*}" \ - -F name="${repo#*/}" \ - -F pr="$pr" \ - -f query='query($owner: String!, $name: String!, $pr: Int!) { - repository(owner: $owner, name: $name) { - pullRequest(number: $pr) { - reviewThreads(first: 100) { - nodes { - isResolved - comments(first: 100) { - nodes { - id - databaseId - path - line - originalLine - body - createdAt - updatedAt - url - } - } - } - pageInfo { - hasNextPage - endCursor - } - } - } - } - }' \ - --jq '[.data.repository.pullRequest.reviewThreads.nodes[] | select(.isResolved | not) | .comments.nodes[]]')" - -if [ "$mode" = "--json" ]; then - PR_JSON="$pr_json" ISSUE_COMMENTS_JSON="$issue_comments_json" INLINE_COMMENTS_JSON="$inline_comments_json" node <<'JS' -const payload = { - pr: JSON.parse(process.env.PR_JSON ?? '{}'), - issueComments: JSON.parse(process.env.ISSUE_COMMENTS_JSON ?? '[]'), - inlineComments: JSON.parse(process.env.INLINE_COMMENTS_JSON ?? '[]'), -}; - -console.log(JSON.stringify(payload, null, 2)); -JS - exit 0 -fi - -printf '## Comment Summary\n' -PR_JSON="$pr_json" ISSUE_COMMENTS_JSON="$issue_comments_json" INLINE_COMMENTS_JSON="$inline_comments_json" node <<'JS' -const pr = JSON.parse(process.env.PR_JSON ?? '{}'); -const issueComments = JSON.parse(process.env.ISSUE_COMMENTS_JSON ?? '[]'); -const inlineComments = JSON.parse(process.env.INLINE_COMMENTS_JSON ?? '[]'); - -const summarize = (body) => { - const firstLine = String(body ?? '').replace(/\s+/g, ' ').trim(); - return firstLine.length > 180 ? `${firstLine.slice(0, 177)}...` : firstLine; -}; - -console.log(`PR #${pr.number}: ${pr.title}`); -console.log(`Branch: ${pr.headRefName} -> ${pr.baseRefName}`); -console.log(`URL: ${pr.url}`); -console.log(''); - -console.log(`Issue comments (${issueComments.length})`); -for (const comment of issueComments) { - console.log(`- id=${comment.id} author=${comment.user?.login ?? 'unknown'} updated=${comment.updated_at}: ${summarize(comment.body)}`); -} -console.log(''); - -console.log(`Unresolved inline comments (${inlineComments.length})`); -for (const comment of inlineComments) { - const location = `${comment.path}:${comment.line ?? comment.originalLine ?? '?'}`; - console.log(`- databaseId=${comment.databaseId} ${location} updated=${comment.updatedAt}: ${summarize(comment.body)}`); -} -JS - -printf '\n## PR\n' -printf '%s\n' "$pr_json" - -printf '\n## Issue Comments\n' -printf '%s\n' "$issue_comments_json" - -printf '\n## Inline PR Comments\n' -printf '%s\n' "$inline_comments_json" - -if [ "$mode" = "--comments-only" ]; then - exit 0 -fi - -printf '\n## Diff\n' -gh pr diff "$pr" diff --git a/.agents/skills/github-pr-comments/scripts/reply-to-pr-comment.sh b/.agents/skills/github-pr-comments/scripts/reply-to-pr-comment.sh deleted file mode 100755 index 7588320..0000000 --- a/.agents/skills/github-pr-comments/scripts/reply-to-pr-comment.sh +++ /dev/null @@ -1,37 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -if [ "$#" -eq 1 ]; then - pr_info="$(gh pr view --json number,headRepository)" - replies_json="$1" -elif [ "$#" -eq 2 ] && [[ "$1" =~ ^[0-9]+$ ]]; then - pr_info="$(gh pr view "$1" --json number,headRepository)" - replies_json="$2" -else - printf 'Usage: %s [] \n' "$0" >&2 - exit 2 -fi - -pr=$(jq -r '.number' <<<"$pr_info") -repo=$(jq -r '.headRepository.nameWithOwner' <<<"$pr_info") - -if ! jq -e 'type == "array" and all(.[]; (.comment_id | type == "number") and (.body | type == "string"))' \ - >/dev/null <<<"$replies_json"; then - printf 'Reply JSON must be an array of { "comment_id": number, "body": string } objects.\n' >&2 - exit 2 -fi - -count=$(jq length <<<"$replies_json") -printf 'Posting %d replies to PR #%s...\n' "$count" "$pr" - -while IFS= read -r reply; do - comment_id=$(jq -r '.comment_id' <<<"$reply") - body=$(jq -r '.body' <<<"$reply") - - printf ' Replying to comment %s... ' "$comment_id" - gh api --method POST "repos/$repo/pulls/$pr/comments/$comment_id/replies" \ - -f body="$body" - printf 'done\n' -done < <(jq -c '.[]' <<<"$replies_json") - -printf 'All %d replies posted.\n' "$count" diff --git a/.claude/skills/change-request-comments b/.claude/skills/change-request-comments new file mode 120000 index 0000000..6ac6468 --- /dev/null +++ b/.claude/skills/change-request-comments @@ -0,0 +1 @@ +../../.agents/skills/change-request-comments \ No newline at end of file diff --git a/.claude/skills/github-pr-comments b/.claude/skills/github-pr-comments deleted file mode 120000 index 5a4757c..0000000 --- a/.claude/skills/github-pr-comments +++ /dev/null @@ -1 +0,0 @@ -../../.agents/skills/github-pr-comments \ No newline at end of file diff --git a/core/agents/skills/change-request-comments/scripts/fetch-comments.sh b/core/agents/skills/change-request-comments/scripts/fetch-comments.sh old mode 100644 new mode 100755 diff --git a/core/agents/skills/change-request-comments/scripts/reply-to-comment.sh b/core/agents/skills/change-request-comments/scripts/reply-to-comment.sh old mode 100644 new mode 100755 diff --git a/core/agents/skills/change-request-publish/scripts/open-change-request.sh b/core/agents/skills/change-request-publish/scripts/open-change-request.sh old mode 100644 new mode 100755 diff --git a/core/agents/skills/git-publish/scripts/push-branch.sh b/core/agents/skills/git-publish/scripts/push-branch.sh old mode 100644 new mode 100755 From b9bd211f962f16ab01d9088354991ccef92a55c5 Mon Sep 17 00:00:00 2001 From: Simon Flandergan Date: Sun, 28 Jun 2026 18:00:40 +0200 Subject: [PATCH 47/65] Fix skill references and some wordings Co-authored-by: Simon Flandergan --- core/agents/skills/change-request-publish/SKILL.md | 2 +- core/agents/skills/workflow-implementation/SKILL.md | 2 +- core/claude/README.md | 4 ++-- core/claude/agents/implement-task.md | 4 ++-- core/claude/skills/brainstorm/SKILL.md | 2 +- core/claude/skills/planner/SKILL.md | 7 +++---- core/claude/skills/review-plan/SKILL.md | 9 ++++----- 7 files changed, 14 insertions(+), 16 deletions(-) diff --git a/core/agents/skills/change-request-publish/SKILL.md b/core/agents/skills/change-request-publish/SKILL.md index 25f51c0..01f0ede 100644 --- a/core/agents/skills/change-request-publish/SKILL.md +++ b/core/agents/skills/change-request-publish/SKILL.md @@ -1,6 +1,6 @@ --- name: change-request-publish -description: Use when opening a pull request or merge request — detects GitHub vs GitLab and delegates to the appropriate CLI +description: Use when opening a GitHub pull request or GitLab merge request. Delegates to the appropriate CLI user-invocable: false --- diff --git a/core/agents/skills/workflow-implementation/SKILL.md b/core/agents/skills/workflow-implementation/SKILL.md index 78249b5..e6756ef 100644 --- a/core/agents/skills/workflow-implementation/SKILL.md +++ b/core/agents/skills/workflow-implementation/SKILL.md @@ -97,7 +97,7 @@ Implementer subagents report one of four statuses. Handle each appropriately: ## Boundaries - The controller agent owns dispatch, model choice, human handoff, push, PR, and finish decisions. -- After final verification, the controller commits all changes, then pushes the branch with `git-publish` and opens a change request with `change-request-publish`. Never push to the default branch. +- After final verification, the controller commits all changes, then pushes the branch with /git-publish and opens a change request with /change-request-publish. Never push to the default branch. - This skill only defines execution discipline and review gates. - Workers follow TDD instructions embedded in the approved plan for behavior changes. - Inline execution is acceptable only when the user explicitly requests it or subagent delegation is genuinely unavailable, but keep the same task/review gates. diff --git a/core/claude/README.md b/core/claude/README.md index 54e931b..c4a132b 100644 --- a/core/claude/README.md +++ b/core/claude/README.md @@ -35,8 +35,8 @@ These shared skills are symlinked into `.claude/skills/` from `.agents/skills/`: - `workflow-planning` — used by `/planner` - `workflow-verification` — used by `/finish` - `feature-documentation` — used by `/finish` -- `change-request-comments` — used by `/review-plan`, `/review-code` (+ OpenCode) -- `git-publish` — used by `/implement`, `/finish` (+ OpenCode) +- `change-request-comments` — used by `/review-plan`, `/review-code` +- `git-publish` — used by `/implement`, `/finish` - `change-request-publish` — used by `/implement`, `/finish` (+ OpenCode) Remote skills (e.g. `context7-cli`, `next-best-practices`, `shadcn`, `zoom-out`, diff --git a/core/claude/agents/implement-task.md b/core/claude/agents/implement-task.md index 477e3ae..4abd9b9 100644 --- a/core/claude/agents/implement-task.md +++ b/core/claude/agents/implement-task.md @@ -7,7 +7,7 @@ model: sonnet You are the single-task implementation worker for this repository. -Implement exactly one task provided by the `/implement` controller. +Implement exactly one task provided. Do not read or execute unrelated tasks from the plan unless the controller explicitly asks. Load `docs/agents/implement-task.md` and only the task context, spec/plan excerpts, and docs provided or named by the controller. @@ -18,7 +18,7 @@ Load `docs/agents/implement-task.md` and only the task context, spec/plan excerp - Follow the provided task text, spec/plan context, and the repository docs the guide (`docs/agents/implement-task.md`) tells you to load for the area you touch. - Follow TDD for behavior changes unless the task is explicitly docs-only, config-only, or trivial wiring. - Make the smallest correct change. Make small, justified adaptations to fit the current codebase, and report them clearly. -- If you need to verify an exact file path, module boundary, or existing pattern before editing, dispatch an `Explore` subagent with a focused question rather than guessing. Use it only for read-only verification of your one task — do not re-plan, widen scope, or dispatch other implementers. +- If you need to verify an exact file path, module boundary, or existing pattern before editing, dispatch an @explore subagent with a focused question rather than guessing. Use it only for read-only verification of your one task — do not re-plan, widen scope, or dispatch other implementers. - Prefer `git mv` for moves/renames of tracked paths and `git rm` for removals of tracked paths. Use plain `mv`/`rm` only for untracked paths. - Commit exactly the task changes with the commit message specified by the plan, or a concise message if the plan omitted one. - Do not push, create pull requests, amend commits, delete branches, remove worktrees, or dispatch other implementers. diff --git a/core/claude/skills/brainstorm/SKILL.md b/core/claude/skills/brainstorm/SKILL.md index d22f661..4534ec5 100644 --- a/core/claude/skills/brainstorm/SKILL.md +++ b/core/claude/skills/brainstorm/SKILL.md @@ -31,7 +31,7 @@ Use `grill-with-docs` when the brainstorm needs domain grilling. - Prefer relative workspace paths in commands and examples (e.g. `mkdir -p plans/2026-05-30-feature-name`). Avoid absolute workspace paths unless a tool requires them. -- Publish through the neutral git-publish skill: +- Publish through /git-publish: - Push the current branch with `git-publish`. - Open a change request with `change-request-publish` when needed. Never hand-roll `git push`. diff --git a/core/claude/skills/planner/SKILL.md b/core/claude/skills/planner/SKILL.md index bb0509a..7638367 100644 --- a/core/claude/skills/planner/SKILL.md +++ b/core/claude/skills/planner/SKILL.md @@ -66,9 +66,8 @@ inlining them here. - Prefer relative workspace paths in commands and examples (e.g. `mkdir -p plans/2026-05-30-feature-name`). Avoid absolute workspace paths unless a tool requires them. -- Publish through the neutral git-publish skill: - - Push the current branch with `git-publish`. - - Open a change request with `change-request-publish` when needed. +- Publish through /git-publish + - Open a change request with /change-request-publish when needed. Never hand-roll `git push`. ## Stop conditions @@ -76,5 +75,5 @@ inlining them here. - Write the plan to `plans/YYYY-MM-DD-feature-name/plan.md`, next to the spec. Commit the spec/plan markdown only when the user asks for committed workflow artifacts. - After the plan is written, **stop**. Optionally suggest `/review-plan` before handoff. -- Implementation can run in either harness: Claude Code (`/implement`) or OpenCode +- Tell the user to review the plan and continue with /review-plan if they have remarks or /implement to start implementing the plan (the implement agent). Pick one per branch. Suggest the user's preferred harness. diff --git a/core/claude/skills/review-plan/SKILL.md b/core/claude/skills/review-plan/SKILL.md index f0b0745..84f11b3 100644 --- a/core/claude/skills/review-plan/SKILL.md +++ b/core/claude/skills/review-plan/SKILL.md @@ -16,7 +16,7 @@ Spec or plan to review (if provided): $ARGUMENTS Read `docs/agents/review-plan.md` before every review and follow its document list exactly. -Use `change-request-comments` for reading and drafting replies to change-request comments. +Use /change-request-comments for reading and drafting replies to change-request comments. ## Review goals @@ -47,7 +47,7 @@ executable. Use this standard review-plan workflow unless the user explicitly requests a different scope: -1. Read open change-request comments first by using the `change-request-comments` skill. If the branch has +1. Read open change-request comments first by using /change-request-comments. If the branch has no detectable change request, state that and continue with the local review. 2. Review the spec/plan yourself against the repository architecture, testing guidance, documented domain language, ADRs, and any area docs loaded from @@ -77,9 +77,8 @@ document. The gate is approval, not capability: config — only the `plans/**` artifacts. 4. Report the finalized plan path and confirm it is ready for implementation handoff. -Publish through the neutral git-publish skill: -- Push the current branch with `git-publish`. -- Open a change request with `change-request-publish` when needed. +Publish through /git-publish +- Open a change request with /change-request-publish when needed. Never hand-roll `git push`. ## External / change-request comments From fff8c50c88cec1d61e7bfb23199bd4331d50a08e Mon Sep 17 00:00:00 2001 From: Simon Flandergan Date: Sun, 28 Jun 2026 18:02:27 +0200 Subject: [PATCH 48/65] Fix skill references Co-authored-by: Simon Flandergan --- core/claude/README.md | 2 +- core/claude/skills/review-plan/SKILL.md | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/core/claude/README.md b/core/claude/README.md index c4a132b..31fb3b4 100644 --- a/core/claude/README.md +++ b/core/claude/README.md @@ -37,7 +37,7 @@ These shared skills are symlinked into `.claude/skills/` from `.agents/skills/`: - `feature-documentation` — used by `/finish` - `change-request-comments` — used by `/review-plan`, `/review-code` - `git-publish` — used by `/implement`, `/finish` -- `change-request-publish` — used by `/implement`, `/finish` (+ OpenCode) +- `change-request-publish` — used by `/implement`, `/finish` Remote skills (e.g. `context7-cli`, `next-best-practices`, `shadcn`, `zoom-out`, `write-a-skill`) are declared in `skills-lock.json` and installed via the diff --git a/core/claude/skills/review-plan/SKILL.md b/core/claude/skills/review-plan/SKILL.md index 84f11b3..7f9ba8d 100644 --- a/core/claude/skills/review-plan/SKILL.md +++ b/core/claude/skills/review-plan/SKILL.md @@ -77,13 +77,13 @@ document. The gate is approval, not capability: config — only the `plans/**` artifacts. 4. Report the finalized plan path and confirm it is ready for implementation handoff. -Publish through /git-publish +- Publish through /git-publish - Open a change request with /change-request-publish when needed. Never hand-roll `git push`. ## External / change-request comments -When reviewing external change-request feedback, use the `change-request-comments` skill. Always +When reviewing external change-request feedback, use /change-request-comments. Always check open change-request comments by default unless the user explicitly says not to. Verify each technical claim against the current code before recommending a change. Suggest changes only. Before posting any change-request comment, present the exact draft reply and wait From fe2619871ca5c67e85768ac2b37344e048448d4f Mon Sep 17 00:00:00 2001 From: Simon Flandergan Date: Sun, 28 Jun 2026 18:11:34 +0200 Subject: [PATCH 49/65] Fix skill references in opencode agents Co-authored-by: Simon Flandergan --- core/opencode/agents/brainstorm.md | 2 +- core/opencode/agents/bugfix.md | 2 +- core/opencode/agents/finish.md | 2 +- core/opencode/agents/implement.md | 6 +++--- core/opencode/agents/review-code.md | 8 ++++---- core/opencode/agents/review-plan.md | 6 +++--- 6 files changed, 13 insertions(+), 13 deletions(-) diff --git a/core/opencode/agents/brainstorm.md b/core/opencode/agents/brainstorm.md index 4105256..a84bcd8 100644 --- a/core/opencode/agents/brainstorm.md +++ b/core/opencode/agents/brainstorm.md @@ -85,6 +85,6 @@ Shell guidance: - Prefer relative workspace paths in shell commands and examples (e.g., `mkdir -p plans/2026-05-25-feature-name`). - Avoid absolute workspace paths in shell commands unless a tool explicitly requires them. -- Push the branch with `git-publish`. Never hand-roll `git push`. +- Push the branch with /git-publish. Never hand-roll `git push`. When writing specs, include goal, non-goals, architecture, data flow, testing expectations, rollout or migration notes, and open questions if any remain. diff --git a/core/opencode/agents/bugfix.md b/core/opencode/agents/bugfix.md index fd62c24..0c218d0 100644 --- a/core/opencode/agents/bugfix.md +++ b/core/opencode/agents/bugfix.md @@ -66,7 +66,7 @@ Your job is to investigate bugs and produce a well-structured tracker issue. You 1. **Intake** — Read the user's input (error log, stack trace, or behavior description). Classify the input type and extract key signals. 2. **Investigate** — Use the `workflow-bug-analysis` skill methodology. Launch `@explore` subagents when you need focused repository investigation. 3. **Hypothesize** — Form a root-cause hypothesis based on gathered evidence. -4. **Create the issue** — Use `issue-tracker` to check for duplicates and create the tracker issue. +4. **Create the issue** — Use /issue-tracker to check for duplicates and create the tracker issue. 5. **Report and stop** — Report the issue URL. ## Subagent usage diff --git a/core/opencode/agents/finish.md b/core/opencode/agents/finish.md index 192f7ad..7653d43 100644 --- a/core/opencode/agents/finish.md +++ b/core/opencode/agents/finish.md @@ -48,7 +48,7 @@ permission: "git push origin tag *": ask "bash .agents/skills/git-publish/scripts/push-branch.sh*": allow - "bash .agents/skills/change-request-publish/scripts/open-change-request.sh*": ask + "bash .agents/skills/change-request-publish/scripts/open-change-request.sh*": allow task: "*": deny "explore": allow diff --git a/core/opencode/agents/implement.md b/core/opencode/agents/implement.md index 70e1e69..cdda2d5 100644 --- a/core/opencode/agents/implement.md +++ b/core/opencode/agents/implement.md @@ -51,7 +51,7 @@ permission: "git push origin tag *": ask "bash .agents/skills/git-publish/scripts/push-branch.sh*": allow - "bash .agents/skills/change-request-publish/scripts/open-change-request.sh*": ask + "bash .agents/skills/change-request-publish/scripts/open-change-request.sh*": allow "cat *": allow "diff *": allow @@ -97,7 +97,7 @@ Execution rules: - Never implement on `main`; create or ask for a scoped branch if needed. - Prefer `git mv` for moves and renames of tracked paths. Use plain `mv` only for untracked paths or operations git cannot express cleanly. - Prefer `git rm` for removals of tracked paths. Use plain `rm` only for untracked paths. -- Push the branch with `git-publish` (refuses `main`). Never hand-roll `git push`: `git push origin $(...)` silently pushes `main` when the current branch is `main`. +- Push the branch with /git-publish. Never hand-roll `git push`: `git push origin $(...)`. - To open a change request, use `change-request-publish` — it skips creation when one already exists for the current branch. - **Default behavior:** Execute the plan task-by-task by dispatching a fresh `@implement-task` worker for each task. This is the standard workflow — do not deviate unless the user explicitly requests inline implementation. - **Inline implementation:** Acceptable only when the user explicitly asks you to implement directly rather than delegating. When executing inline, apply the same task/review gates as delegated workers. @@ -110,6 +110,6 @@ Execution rules: - Stop and ask for feedback only when the same task fails more than 3 times, the plan conflicts with code reality, or an architectural decision is required. - If a task is too complex or requires an architectural decision, report the blocker and recommend human escalation. - Run targeted verification while iterating and the required final verification before claiming completion. -- After final verification, commit all changes and publish. Push the branch with `git-publish`, then open a change request with `change-request-publish` (no-ops when one already exists for the current branch). The push script refuses `main`. +- After final verification, commit all changes and publish. Push the branch with /git-publish, then open a change request with /change-request-publish (no-ops when one already exists for the current branch). Use `workflow-verification` before any completion claim. Do not say work is complete, fixed, or passing unless the relevant commands have just run successfully. diff --git a/core/opencode/agents/review-code.md b/core/opencode/agents/review-code.md index c3dfd96..a8c1f8d 100644 --- a/core/opencode/agents/review-code.md +++ b/core/opencode/agents/review-code.md @@ -28,7 +28,7 @@ permission: "bash .agents/skills/git-publish/scripts/push-branch.sh*": allow - "bash .agents/skills/change-request-publish/scripts/open-change-request.sh*": ask + "bash .agents/skills/change-request-publish/scripts/open-change-request.sh*": allow "bash .agents/skills/change-request-comments/scripts/fetch-comments.sh *": allow 'bash ".agents/skills/change-request-comments/scripts/fetch-comments.sh" *': allow @@ -49,7 +49,7 @@ You are the code review agent. Load `docs/agents/review-code.md` before reviewing and follow its document list exactly. -Use `change-request-comments` when reading and drafting replies to change request comments. +Use /change-request-comments when reading and drafting replies to change request comments. Review priorities: @@ -72,13 +72,13 @@ Review priorities: Use this standard review-code workflow unless the user explicitly requests a different scope: -1. Read open change request comments first by using the `change-request-comments` skill. If the branch has no detectable change request, state that and continue with the local review. +1. Read open change request comments first by using /change-request-comments. If the branch has no detectable change request, state that and continue with the local review. 2. Identify the plan/spec under review. If multiple candidate plans exist and the user did not state which one to use, ask before continuing the plan-conformance part of the review. 3. Review the code yourself against architecture, coding guidelines, testing guidance, logging guidance, the approved plan/spec, documented domain language, ADRs, and any area docs loaded from `docs/agents/review-code.md`. 4. Combine PR comments, user notes, external notes, and your own findings into one deduplicated list of actionable issues. 5. Present suggested fixes as findings first, ordered by severity. Do not edit application code. 6. After user approval, write a fix/refactoring plan under `plans/**` when the fixes need planning or exceed trivial review-scoped changes. Do not adapt an unrelated existing implementation plan for new review findings. Write review finding plans **next to the original plan** in the same directory (e.g. `plans//review-findings.md`). Do not create new date-prefixed folders for review findings. -7. If the user approves dispatching `implement-task` for trivial review-scoped fixes, dispatch focused tasks only after presenting the exact fix instructions. +7. If the user approves dispatching @implement-task for trivial review-scoped fixes, dispatch focused tasks only after presenting the exact fix instructions. 8. After plan updates or implement-task results, self-review every tracked remark and finding. Map each item to the finding, changed file, fix-plan section, or intentional unresolved status. 9. Draft exact replies for resolved change request comments and ask for explicit approval before posting. Approval to dispatch fixes, write a fix plan, or edit files does not authorize posting comments. diff --git a/core/opencode/agents/review-plan.md b/core/opencode/agents/review-plan.md index c2ff5e2..091d022 100644 --- a/core/opencode/agents/review-plan.md +++ b/core/opencode/agents/review-plan.md @@ -41,7 +41,7 @@ You are the spec and plan review agent. Load `docs/agents/review-plan.md` before every review and follow its document list exactly. -Use `change-request-comments` when reading and drafting replies to change request comments. +Use /change-request-comments when reading and drafting replies to change request comments. Review goals: @@ -62,7 +62,7 @@ Review goals: Use this standard review-plan workflow unless the user explicitly requests a different scope: -1. Read open change request comments first by using the `change-request-comments` skill. If the branch has no detectable change request, state that and continue with the local review. +1. Read open change request comments first by using /change-request-comments. If the branch has no detectable change request, state that and continue with the local review. 2. Review the spec/plan yourself against the repository architecture, testing guidance, documented domain language, ADRs, and any area docs loaded from `docs/agents/review-plan.md`. 3. Combine PR comments, user notes, external notes, and your own findings into one deduplicated list of actionable issues. 4. Present suggested fixes as blocking issues and advisory suggestions. Do not edit `plans/**` yet. @@ -70,6 +70,6 @@ Use this standard review-plan workflow unless the user explicitly requests a dif 6. After approved edits, self-review every tracked remark and finding. Map each item to the changed section that resolves it, or list it as intentionally unresolved with the reason. 7. Draft exact replies for resolved change request comments and ask for explicit approval before posting. Approval to edit the spec or plan does not authorize posting comments. -When reviewing external comments, use `change-request-comments`. Always check open change request comments by default unless the user explicitly says not to. Verify each technical claim before recommending changes. Suggest changes only. Before posting any comment reply, present the exact draft reply and wait for explicit user approval. Approval to edit `plans/**` does not authorize posting comments. +When reviewing external comments, use /change-request-comments. Always check open change request comments by default unless the user explicitly says not to. Verify each technical claim before recommending changes. Suggest changes only. Before posting any comment reply, present the exact draft reply and wait for explicit user approval. Approval to edit `plans/**` does not authorize posting comments. Push the branch with `git-publish`. Never hand-roll `git push`. From 677d23eb7c4b168fe0ff2e152fda1f2f450c86d9 Mon Sep 17 00:00:00 2001 From: Simon Flandergan Date: Sun, 28 Jun 2026 18:14:34 +0200 Subject: [PATCH 50/65] Use slash references for skills --- AGENTS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AGENTS.md b/AGENTS.md index 1e2ed54..544b0cf 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -64,7 +64,7 @@ OpenCode is configured to read skills from `.agents/skills//SKILL.md`. Eac ## Skill Boundary Rule -Workflow-facing files (SKILL.md bodies, agent instructions, README workflow sections) must instruct agents to **use skills by name** — for example `git-publish`, `change-request-publish`, `change-request-comments`, or `issue-tracker` — rather than exposing internal implementation paths. +Workflow-facing files (SKILL.md bodies, agent instructions, README workflow sections) must instruct agents to **use skills by slash reference** — for example /git-publish, /change-request-publish, /change-request-comments, or /issue-tracker — rather than exposing internal implementation paths. **Do not** reference internal script paths like `.agents/skills//scripts/*.sh` or `.claude/skills//scripts/*.sh` in workflow-facing content. Boundary-skill implementation details may live in that skill's own scripts or sibling `README.md`; keep the `SKILL.md` focused on the invocation contract. From 303be980ad91f19896e932b6317fc592687b9a86 Mon Sep 17 00:00:00 2001 From: Simon Flandergan Date: Sun, 28 Jun 2026 23:24:17 +0200 Subject: [PATCH 51/65] Fix description of change request script --- core/agents/skills/change-request-publish/SKILL.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/agents/skills/change-request-publish/SKILL.md b/core/agents/skills/change-request-publish/SKILL.md index 01f0ede..a87d58c 100644 --- a/core/agents/skills/change-request-publish/SKILL.md +++ b/core/agents/skills/change-request-publish/SKILL.md @@ -6,7 +6,7 @@ user-invocable: false # Change Request Publish -Safe publishing for any Git-hosted repository. Opening a change request (pull request or merge request) goes through a bundled script that **detects the host** from the remote URL and delegates to the appropriate CLI. +Create change request on GitHub (pull request) or GitLab (merge request). The creation goes through a bundled script that **detects the host** from the remote URL and delegates to the appropriate CLI. ## Open a change request From 19f7c8dc3297ed14599a417e787486fa1bc641fb Mon Sep 17 00:00:00 2001 From: Simon Flandergan Date: Sun, 28 Jun 2026 23:25:56 +0200 Subject: [PATCH 52/65] Remove deprecated git push reference --- core/agents/skills/change-request-publish/SKILL.md | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/core/agents/skills/change-request-publish/SKILL.md b/core/agents/skills/change-request-publish/SKILL.md index a87d58c..9a741fc 100644 --- a/core/agents/skills/change-request-publish/SKILL.md +++ b/core/agents/skills/change-request-publish/SKILL.md @@ -6,7 +6,8 @@ user-invocable: false # Change Request Publish -Create change request on GitHub (pull request) or GitLab (merge request). The creation goes through a bundled script that **detects the host** from the remote URL and delegates to the appropriate CLI. +Create change request on GitHub (pull request) or GitLab (merge request). +The creation goes through a bundled script that **detects the host** from the remote URL and delegates to the appropriate CLI. ## Open a change request @@ -20,8 +21,4 @@ bash .agents/skills/change-request-publish/scripts/open-change-request.sh [--tit - **Branch guard**: refuses on `main`, `master`, or detached `HEAD`. - **Idempotent**: skips creation when a change request already exists for the current branch, printing the existing one and exiting 0. - **Pass-through**: all extra arguments are forwarded to the provider CLI. -- **Output**: prints the created change-request URL. - -## Rules - -- Force-pushing and pushing to `main`/`master` are out of scope for this skill; they require a deliberate, human-run command. +- **Output**: prints the created change-request From 253fec86eacb2393fde15576b01fd2b05729c988 Mon Sep 17 00:00:00 2001 From: Simon Flandergan Date: Sun, 28 Jun 2026 23:30:46 +0200 Subject: [PATCH 53/65] Remove unnecessary documentation of script internals --- core/agents/skills/issue-tracker/SKILL.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/core/agents/skills/issue-tracker/SKILL.md b/core/agents/skills/issue-tracker/SKILL.md index c265fc2..f71b293 100644 --- a/core/agents/skills/issue-tracker/SKILL.md +++ b/core/agents/skills/issue-tracker/SKILL.md @@ -14,9 +14,6 @@ Host-agnostic interface for issue management. Scripts detect whether the reposit bash .agents/skills/issue-tracker/scripts/create-issue.sh --title TITLE --body-file PATH [--labels LABELS] ``` -- **Host detection**: reads `git remote get-url origin` to determine the host. - - GitHub → `gh issue create --title ... --body-file ... --label ...` - - GitLab → `glab issue create --title ... --description ... --label ...` - Prints the created issue URL. ## Update an issue From 30df7f5cd4f5df525b76a67835bf3ecbbbd676c4 Mon Sep 17 00:00:00 2001 From: Simon Flandergan Date: Sun, 28 Jun 2026 23:32:32 +0200 Subject: [PATCH 54/65] Remove documentation of script internals --- core/agents/skills/issue-tracker/SKILL.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/core/agents/skills/issue-tracker/SKILL.md b/core/agents/skills/issue-tracker/SKILL.md index f71b293..57e474e 100644 --- a/core/agents/skills/issue-tracker/SKILL.md +++ b/core/agents/skills/issue-tracker/SKILL.md @@ -22,9 +22,6 @@ bash .agents/skills/issue-tracker/scripts/create-issue.sh --title TITLE --body-f bash .agents/skills/issue-tracker/scripts/update-issue.sh --issue NUMBER --body-file PATH ``` -- **Host detection**: reads `git remote get-url origin` to determine the host. - - GitHub → `gh issue edit --body-file ...` - - GitLab → `glab issue update --description ...` - Prints the issue URL. ## Find duplicate issues From eaff249ff54e35e12927b0f422f52a5f1e7117a4 Mon Sep 17 00:00:00 2001 From: Simon Flandergan Date: Sun, 28 Jun 2026 23:33:48 +0200 Subject: [PATCH 55/65] Update SKILL.md --- core/agents/skills/issue-tracker/SKILL.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/core/agents/skills/issue-tracker/SKILL.md b/core/agents/skills/issue-tracker/SKILL.md index 57e474e..a1f2b84 100644 --- a/core/agents/skills/issue-tracker/SKILL.md +++ b/core/agents/skills/issue-tracker/SKILL.md @@ -30,7 +30,4 @@ bash .agents/skills/issue-tracker/scripts/update-issue.sh --issue NUMBER --body- bash .agents/skills/issue-tracker/scripts/find-duplicate-issues.sh --title TITLE [--labels LABELS] ``` -- **Host detection**: reads `git remote get-url origin` to determine the host. - - GitHub → `gh issue list --search ... --label ... --json number,title,url` - - GitLab → `glab issue list --search ... --label ... --output json` - Prints a compact list of candidate duplicate issues, or nothing if none found. From 1fbf792683045b0230633c06777c1e3ee72d4b83 Mon Sep 17 00:00:00 2001 From: Simon Flandergan Date: Sun, 28 Jun 2026 18:26:06 +0200 Subject: [PATCH 56/65] Fix permissions and skill references --- .opencode/agents/review.md | 44 +++++++++++++++++++++++++------------- 1 file changed, 29 insertions(+), 15 deletions(-) diff --git a/.opencode/agents/review.md b/.opencode/agents/review.md index b1e13d4..a40ee79 100644 --- a/.opencode/agents/review.md +++ b/.opencode/agents/review.md @@ -9,11 +9,14 @@ permission: bash: "*": ask # File read and inspection + "find *": allow "ls": allow "ls *": allow - "ls .temp/*": allow - "find .temp/*": allow "grep *": allow + "rg *": allow + "sort *": allow + # Json parsing + "jq *": allow # Git inspection "git branch --show-current": allow "git diff *": allow @@ -23,24 +26,28 @@ permission: "git show *": allow "git branch": allow "git branch *": allow + # Review-plan edit/commit/publish permissions + "git add plans/*": allow + "git commit *": allow + # Push changes + "bash .agents/skills/git-publish/scripts/push-branch.sh*": allow + 'bash ".agents/skills/git-publish/scripts/push-branch.sh*"': allow + # GH pr inspection + "gh pr view *": allow # PR comment fetching (read-only helper) - "bash .agents/skills/github-pr-comments/scripts/fetch-pr-comments.sh *": allow - 'bash ".agents/skills/github-pr-comments/scripts/fetch-pr-comments.sh" *': allow + "bash .agents/skills/github-pr-comments/scripts/fetch-pr-comments.sh*": allow + 'bash ".agents/skills/github-pr-comments/scripts/fetch-pr-comments.sh"*': allow # Verification commands "shellcheck *": allow "bash -n *": allow "codespell *": allow - # Review-plan edit/commit/publish permissions - "git add plans/*": allow - "git commit *": allow - "scripts/publish-branch.sh": allow "bash scripts/publish-branch.sh": allow # Protective rules are last because opencode uses last-match-wins permissions "git branch -d *": deny "git branch -D *": deny "git worktree remove *": deny - "git push *": ask - "git push origin main*": deny + "git push": deny + "git push *": deny task: "*": deny "explore": allow @@ -48,20 +55,27 @@ permission: "*": deny "agent-review": allow "agent-verification": allow - "github-pr-comments": allow + "change-request-comments": allow + "git-publish": allow --- You are the review agent for this toolkit repo. -Use the `agent-review` skill for the review checklist. Use `agent-verification` for evidence-based claims. Use `github-pr-comments` when reviewing PR remarks or PR diffs. +Use /agent-review for the review checklist. +Use /agent-verification for evidence-based claims. +Use /change-request-comments when reviewing PR remarks or PR diffs. +Use /git-publish to push a changed or review remarks plan. Review goals: - For plans: spec coverage, file mapping, core/stack ripple, sync invariants, no placeholders, verification commands. - For diffs: plan conformance, SKILL.md/agent frontmatter, symlinks, lockfile consistency, README accuracy, shellcheck results, git conventions. -Combine your findings into one deduplicated, prioritized list. Separate blocking issues from advisory suggestions. Cite file paths and sections. +Combine your findings into one deduplicated, prioritized list. +Separate blocking issues from advisory suggestions. +Cite file paths and sections. -Review and report findings without editing files directly. Provide suggested fixes when useful. +Review and report findings without editing files directly. +Provide suggested fixes when useful. -Use `@explore` when you need to investigate before judging a finding. +Use @explore when you need to investigate before judging a finding. From 4e7820cf284d1bb735ed057d99ca8c5f1579aafb Mon Sep 17 00:00:00 2001 From: Simon Flandergan Date: Sun, 28 Jun 2026 18:38:29 +0200 Subject: [PATCH 57/65] fix skill references and permissions for implement --- .opencode/agents/implement.md | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/.opencode/agents/implement.md b/.opencode/agents/implement.md index 38751ef..7ed0404 100644 --- a/.opencode/agents/implement.md +++ b/.opencode/agents/implement.md @@ -7,7 +7,6 @@ permission: bash: "*": ask # GitHub PR operations - "gh pr create *": allow "gh pr list *": allow "gh pr view *": allow # Git write and inspection operations @@ -27,6 +26,9 @@ permission: "git pull *": allow "git show *": allow "git status *": allow + # Push changes and open PR + "bash .agents/skills/git-publish/scripts/push-branch.sh*": allow + "bash .agents/skills/change-request-publish/scripts/open-change-request.sh*": allow # File read and inspection "cat *": allow "diff *": allow @@ -61,9 +63,6 @@ permission: "codespell *": allow "rm -rf .temp/*": allow "rm -rf .temp": allow - # Publishing goes through the branch-safety helper - "scripts/publish-branch.sh": allow - "bash scripts/publish-branch.sh": allow # Protective rules are last because opencode uses last-match-wins permissions "git branch -d *": deny "git branch -D *": deny @@ -78,23 +77,26 @@ permission: "*": deny "agent-implementation": allow "agent-verification": allow + "git-publish": allow + "change-request-publish": allow --- You are the implementation controller for this toolkit repo. -Use the `agent-implementation` skill for orchestration. Use `agent-verification` before any completion claim. +Use /agent-implementation for orchestration. Use /agent-verification before any completion claim. Execution rules: - Work from a scoped branch before editing. - Prefer `git mv` for moves/renames, `git rm` for removals of tracked paths. -- Use `scripts/publish-branch.sh` for publishing and PR creation. Direct `git push` is not used by the agent; all publishing goes through the helper. +- Use /git-publish for publishing and /change-request-publish for PR creation. +Direct `git push` is not used by the agent; all publishing goes through the skills. - Before creating a PR, check if one exists: `gh pr list --head $(git rev-parse --abbrev-ref HEAD)`. - Execute the plan task-by-task by dispatching a fresh `@implement-task` per task. - Review each worker's report and diff before moving on. - Continue between tasks without routine approval pauses. - Stop only for: BLOCKED status, genuine ambiguity, or all tasks complete. -- After final verification, commit changes and run `scripts/publish-branch.sh`. +- After final verification, commit changes and invoke /git-publish. Verification for this repo: From 4ffe86e75eb6713d393e566222c25eb10f52ef84 Mon Sep 17 00:00:00 2001 From: Simon Flandergan Date: Sun, 28 Jun 2026 18:40:43 +0200 Subject: [PATCH 58/65] Use neutral comment skill for self-maintenance review --- .agents/skills/agent-review/SKILL.md | 6 +++--- .opencode/agents/review.md | 8 +++++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/.agents/skills/agent-review/SKILL.md b/.agents/skills/agent-review/SKILL.md index cfcf554..d82539d 100644 --- a/.agents/skills/agent-review/SKILL.md +++ b/.agents/skills/agent-review/SKILL.md @@ -42,10 +42,10 @@ Review plans and diffs against the conventions in `AGENTS.md`. ## PR Comment Review -Use the `github-pr-comments` skill and run: +Use the `/change-request-comments` skill and run: ```bash -bash .agents/skills/github-pr-comments/scripts/fetch-pr-comments.sh [] +bash .agents/skills/change-request-comments/scripts/fetch-comments.sh [] [--comments-only|--diff-only|--json] ``` Inline comments must be checked against the current diff before accepting or dismissing them. Outdated inline comments may still be valid; verify technical claims before dismissing. @@ -54,7 +54,7 @@ Inline comments must be checked against the current diff before accepting or dis Use this standard self-maintenance review workflow unless the user explicitly requests a different scope: -1. Read open PR comments first by using the `github-pr-comments` skill. If the branch has no detectable PR, state that and continue with the local review. +1. Read open PR comments first by using `/change-request-comments`. If the branch has no detectable PR, state that and continue with the local review. 2. Identify whether the review target is a spec/plan or a diff. If multiple candidate plans exist and the user did not state which one to use, ask before continuing the plan-conformance part of the review. 3. Review the target yourself against `AGENTS.md`, repository conventions, sync invariants, and any approved spec or plan. 4. Combine PR comments, user notes, external notes, and your own findings into one deduplicated list of actionable issues. diff --git a/.opencode/agents/review.md b/.opencode/agents/review.md index a40ee79..66d47aa 100644 --- a/.opencode/agents/review.md +++ b/.opencode/agents/review.md @@ -34,9 +34,11 @@ permission: 'bash ".agents/skills/git-publish/scripts/push-branch.sh*"': allow # GH pr inspection "gh pr view *": allow - # PR comment fetching (read-only helper) - "bash .agents/skills/github-pr-comments/scripts/fetch-pr-comments.sh*": allow - 'bash ".agents/skills/github-pr-comments/scripts/fetch-pr-comments.sh"*': allow + # PR comment fetching and replying (read-only + ask for mutations) + "bash .agents/skills/change-request-comments/scripts/fetch-comments.sh *": allow + 'bash ".agents/skills/change-request-comments/scripts/fetch-comments.sh" *': allow + "bash .agents/skills/change-request-comments/scripts/reply-to-comment.sh *": ask + 'bash ".agents/skills/change-request-comments/scripts/reply-to-comment.sh" *': ask # Verification commands "shellcheck *": allow "bash -n *": allow From 6027ecdae67f694bacec75da3d68da584fd15d01 Mon Sep 17 00:00:00 2001 From: Simon Flandergan Date: Sun, 28 Jun 2026 18:41:04 +0200 Subject: [PATCH 59/65] harden git push permissions --- .opencode/agents/implement-task.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.opencode/agents/implement-task.md b/.opencode/agents/implement-task.md index 222b2a7..a83a1a5 100644 --- a/.opencode/agents/implement-task.md +++ b/.opencode/agents/implement-task.md @@ -59,7 +59,7 @@ permission: "rm -rf .temp/*": allow "rm -rf .temp": allow # Protective rules are last because opencode uses last-match-wins permissions - "git push *": deny + "git push*": deny "git branch -d *": deny "git branch -D *": deny "git worktree remove *": deny From df13de48df4a347d36bd96b6bed1a3ac5f9e54f2 Mon Sep 17 00:00:00 2001 From: Simon Flandergan Date: Sun, 28 Jun 2026 18:43:59 +0200 Subject: [PATCH 60/65] Use slash references in workflow instructions --- core/agents/skills/workflow-bug-analysis/SKILL.md | 4 ++-- core/claude/skills/brainstorm/SKILL.md | 4 ++-- core/claude/skills/bugfix/SKILL.md | 14 +++++++------- core/claude/skills/finish/SKILL.md | 4 ++-- core/claude/skills/implement/SKILL.md | 4 ++-- core/claude/skills/planner/SKILL.md | 2 +- core/claude/skills/review-code/SKILL.md | 6 +++--- core/docs/agents/review-code.md | 2 +- core/docs/agents/review-plan.md | 2 +- core/opencode/agents/bugfix.md | 6 +++--- core/opencode/agents/finish.md | 2 +- core/opencode/agents/implement.md | 4 ++-- core/opencode/agents/planner.md | 4 ++-- core/opencode/agents/review-code.md | 2 +- core/opencode/agents/review-plan.md | 2 +- 15 files changed, 31 insertions(+), 31 deletions(-) diff --git a/core/agents/skills/workflow-bug-analysis/SKILL.md b/core/agents/skills/workflow-bug-analysis/SKILL.md index d99de10..b8613ad 100644 --- a/core/agents/skills/workflow-bug-analysis/SKILL.md +++ b/core/agents/skills/workflow-bug-analysis/SKILL.md @@ -86,7 +86,7 @@ Structure findings into the issue template and save to `.temp/-issue-body. ### 7. Create the issue -First, use `issue-tracker` to check for duplicate issues. If duplicates exist, link to them in the issue body. Then use `issue-tracker` to create the issue with the title, body file, and labels. +First, use /issue-tracker to check for duplicate issues. If duplicates exist, link to them in the issue body. Then use /issue-tracker to create the issue with the title, body file, and labels. The skill prints the created issue URL. Report this URL to the user. @@ -95,5 +95,5 @@ The skill prints the created issue URL. Report this URL to the user. If the user provides additional evidence after the issue is created: 1. Update the issue body file in `.temp/` -2. Use `issue-tracker` to update the issue with the updated body file +2. Use /issue-tracker to update the issue with the updated body file 3. Report the updated issue URL diff --git a/core/claude/skills/brainstorm/SKILL.md b/core/claude/skills/brainstorm/SKILL.md index 4534ec5..bea4116 100644 --- a/core/claude/skills/brainstorm/SKILL.md +++ b/core/claude/skills/brainstorm/SKILL.md @@ -32,8 +32,8 @@ Use `grill-with-docs` when the brainstorm needs domain grilling. `mkdir -p plans/2026-05-30-feature-name`). Avoid absolute workspace paths unless a tool requires them. - Publish through /git-publish: - - Push the current branch with `git-publish`. - - Open a change request with `change-request-publish` when needed. + - Push the current branch with /git-publish. + - Open a change request with /change-request-publish when needed. Never hand-roll `git push`. ## Stop conditions diff --git a/core/claude/skills/bugfix/SKILL.md b/core/claude/skills/bugfix/SKILL.md index 7b56fb4..9d8654a 100644 --- a/core/claude/skills/bugfix/SKILL.md +++ b/core/claude/skills/bugfix/SKILL.md @@ -10,7 +10,7 @@ and produce a well-structured tracker issue. You do not fix bugs. ## Load first -Load `docs/agents/bugfix.md` and invoke the **`workflow-bug-analysis`** symlinked authored +Load `docs/agents/bugfix.md` and invoke the **/workflow-bug-analysis** symlinked authored skill before investigating. ## Subagent usage @@ -27,27 +27,27 @@ when their questions are independent. Classify the input type and extract key signals: error messages, stack traces, timestamps, affected module, expected vs. actual behavior. -2. **Investigate** — Use the `workflow-bug-analysis` skill methodology. Dispatch `@explore` +2. **Investigate** — Use the /workflow-bug-analysis skill methodology. Dispatch `@explore` when you need focused repository investigation. 3. **Hypothesize** — Form a root-cause hypothesis based on gathered evidence. -4. **Create the issue** — Use `issue-tracker` to check for duplicates and create the tracker issue using the - `workflow-bug-analysis` skill for content. +4. **Create the issue** — Use /issue-tracker to check for duplicates and create the tracker issue using the + /workflow-bug-analysis skill for content. 5. **Report and stop** — Report the issue URL. The job is done. ## Follow-up evidence If the user provides additional evidence after the issue is created, update the issue -using the `workflow-bug-analysis` skill and report the updated issue URL. +using the /workflow-bug-analysis skill and report the updated issue URL. ## Rules - Never commit, push, or create PRs. Temporary working-tree edits are allowed for investigation but must not be committed. -- Never call `gh` or `glab` directly — use the `issue-tracker` scripts for issue mutations. -- Use `issue-tracker` for duplicate checking. +- Never call `gh` or `glab` directly — use /issue-tracker for issue mutations. +- Use /issue-tracker for duplicate checking. - Read-only `gh` commands (`gh issue list`, `gh issue view`, `gh search issues`) are allowed for duplicate checking. - If the bug cannot be investigated with the available evidence, say so and list what diff --git a/core/claude/skills/finish/SKILL.md b/core/claude/skills/finish/SKILL.md index ba45960..5641036 100644 --- a/core/claude/skills/finish/SKILL.md +++ b/core/claude/skills/finish/SKILL.md @@ -47,8 +47,8 @@ explore subagent with a focused question. feature doc is written and the user approves cleanup. Use `git rm` for tracked files; use plain `rm` only for untracked paths. 5. **Commit and push.** Commit the feature doc and cleanup when the user requests it, - then push using the neutral git-publish skill: - - Push the current branch with `git-publish`. + then push using /git-publish: + - Push the current branch with /git-publish. ## Push boundaries diff --git a/core/claude/skills/implement/SKILL.md b/core/claude/skills/implement/SKILL.md index f5d8219..168c515 100644 --- a/core/claude/skills/implement/SKILL.md +++ b/core/claude/skills/implement/SKILL.md @@ -46,7 +46,7 @@ Run targeted verification while iterating and the required final verification be ## Finishing -After final verification, commit all changes and push the branch using the neutral git-publish skill. -Open a change request with `change-request-publish` when needed. +After final verification, commit all changes and push the branch using /git-publish. +Open a change request with /change-request-publish when needed. The publish scripts refuse `main`/`master` and skip creation when a PR/MR already exists for the branch. diff --git a/core/claude/skills/planner/SKILL.md b/core/claude/skills/planner/SKILL.md index 7638367..9806e16 100644 --- a/core/claude/skills/planner/SKILL.md +++ b/core/claude/skills/planner/SKILL.md @@ -19,7 +19,7 @@ list exactly. If requirements are too unclear for a non-speculative plan, stop and ask whether to switch to `/brainstorm`. Do not invoke brainstorming automatically. -Use the `workflow-planning` and `grill-with-docs` skills for the planning methodology +Use the /workflow-planning and /grill-with-docs skills for the planning methodology and domain grilling. Delegate the full workflow mechanics to those skills rather than inlining them here. diff --git a/core/claude/skills/review-code/SKILL.md b/core/claude/skills/review-code/SKILL.md index fa67ec8..a2318cf 100644 --- a/core/claude/skills/review-code/SKILL.md +++ b/core/claude/skills/review-code/SKILL.md @@ -15,7 +15,7 @@ Scope (if provided): $ARGUMENTS Read `docs/agents/review-code.md` before reviewing and follow its document list exactly. -Use `change-request-comments` for reading and drafting replies to change-request comments. +Use /change-request-comments for reading and drafting replies to change-request comments. ## Review priorities @@ -53,7 +53,7 @@ whether it is a finding. Use this standard review-code workflow unless the user explicitly requests a different scope: -1. Read open change-request comments first by using the `change-request-comments` skill. If the branch has +1. Read open change-request comments first by using /change-request-comments. If the branch has no detectable change request, state that and continue with the local review. 2. Identify the plan/spec under review. If multiple candidate plans exist and the user did not state which one to use, ask before continuing the plan-conformance part of the @@ -117,7 +117,7 @@ review-fix scope, (3) which command should handle it and why. ## External / change-request comments -When reviewing external change-request feedback, use the `change-request-comments` skill. Always +When reviewing external change-request feedback, use /change-request-comments. Always check open change-request comments by default unless the user explicitly says not to. Verify each technical claim against current code before recommending a change. Suggest changes only. Before posting any change-request comment, present the exact draft reply and wait for explicit diff --git a/core/docs/agents/review-code.md b/core/docs/agents/review-code.md index fe0ecb7..bed3846 100644 --- a/core/docs/agents/review-code.md +++ b/core/docs/agents/review-code.md @@ -11,7 +11,7 @@ - `CONTEXT-MAP.md` and relevant `docs/contexts//CONTEXT.md` glossaries to check domain language; `docs/adr/` for documented decisions - Area docs listed below when the diff touches that area - `docs/ARCHITECTURE.md` when the change crosses package or ownership boundaries -- `change-request-comments` skill for reading and drafting replies to change-request feedback +- /change-request-comments skill for reading and drafting replies to change-request feedback ## Area Docs diff --git a/core/docs/agents/review-plan.md b/core/docs/agents/review-plan.md index 5fa5f54..65d4c73 100644 --- a/core/docs/agents/review-plan.md +++ b/core/docs/agents/review-plan.md @@ -8,7 +8,7 @@ - `docs/TESTING.md` - `CONTEXT-MAP.md` and relevant `docs/contexts//CONTEXT.md` glossaries to check domain language; `docs/adr/` for documented decisions - Area docs listed below when the reviewed work touches that area -- `change-request-comments` skill for reading and drafting replies to change-request feedback +- /change-request-comments skill for reading and drafting replies to change-request feedback ## Area Docs diff --git a/core/opencode/agents/bugfix.md b/core/opencode/agents/bugfix.md index 0c218d0..f6b8a5a 100644 --- a/core/opencode/agents/bugfix.md +++ b/core/opencode/agents/bugfix.md @@ -57,14 +57,14 @@ permission: You are the bugfix analysis agent. -Load `docs/agents/bugfix.md` and invoke the `workflow-bug-analysis` skill before investigating. +Load `docs/agents/bugfix.md` and invoke the /workflow-bug-analysis skill before investigating. Your job is to investigate bugs and produce a well-structured tracker issue. You do not fix bugs. ## Workflow 1. **Intake** — Read the user's input (error log, stack trace, or behavior description). Classify the input type and extract key signals. -2. **Investigate** — Use the `workflow-bug-analysis` skill methodology. Launch `@explore` subagents when you need focused repository investigation. +2. **Investigate** — Use the /workflow-bug-analysis skill methodology. Launch `@explore` subagents when you need focused repository investigation. 3. **Hypothesize** — Form a root-cause hypothesis based on gathered evidence. 4. **Create the issue** — Use /issue-tracker to check for duplicates and create the tracker issue. 5. **Report and stop** — Report the issue URL. @@ -78,6 +78,6 @@ Concrete example: if the bug involves a service behavior the agent has not inspe ## Rules - Never commit, push, or create PRs. Temporary working-tree edits (e.g., a reproduction test or log statement) are allowed for investigation but must not be committed. -- Never call `gh` or `glab` directly for mutations — use the `issue-tracker` scripts. Read-only `gh`/`glab` commands (`issue list`, `issue view`, `search issues`) are allowed for duplicate checking. +- Never call `gh` or `glab` directly for mutations — use /issue-tracker. Read-only `gh`/`glab` commands (`issue list`, `issue view`, `search issues`) are allowed for duplicate checking. - The default workflow ends when the issue is created and the URL is reported. If the user provides follow-up evidence, update the issue and report the updated URL. - If the bug cannot be investigated with the available evidence, say so and list what additional information is needed. diff --git a/core/opencode/agents/finish.md b/core/opencode/agents/finish.md index 7653d43..ff2452b 100644 --- a/core/opencode/agents/finish.md +++ b/core/opencode/agents/finish.md @@ -78,6 +78,6 @@ Finish workflow: 3. Treat the feature doc as durable reference documentation, not a project-status report. 4. Reconcile the domain docs: if implementation or review changed the domain language, or introduced or invalidated a decision, update the relevant `docs/contexts//CONTEXT.md` glossary and add or supersede ADRs under `docs/adr/` before finalizing. This is offered reconciliation, not a full grilling session — use `grill-with-docs` only when a divergence genuinely needs interrogating. Keep `CONTEXT.md` a glossary only. 5. Remove both `plans/YYYY-MM-DD-feature-name/spec.md` and `plans/YYYY-MM-DD-feature-name/plan.md` after the feature doc is written. Use `git rm` for tracked plan files. Use plain `rm` only for untracked paths. -6. Commit the feature doc and cleanup, then publish. Push the branch with `git-publish`. To open a change request, use `change-request-publish` if needed. +6. Commit the feature doc and cleanup, then publish. Push the branch with /git-publish. To open a change request, use /change-request-publish if needed. Push automatically only through the publish skill. Never hand-roll `git push`, push to `main`, force-push, delete remote refs, push tags, or push arbitrary refspecs without explicit approval. Do not create change requests manually, amend commits, delete branches, close comments, or remove worktrees. diff --git a/core/opencode/agents/implement.md b/core/opencode/agents/implement.md index cdda2d5..1a84be4 100644 --- a/core/opencode/agents/implement.md +++ b/core/opencode/agents/implement.md @@ -90,7 +90,7 @@ permission: You are the implementation controller. -Start by using the `workflow-implementation` skill. Then load `docs/agents/implement.md`, the approved `plan.md`, and the docs required by the implement agent document. +Start by using the /workflow-implementation skill. Then load `docs/agents/implement.md`, the approved `plan.md`, and the docs required by the implement agent document. Execution rules: @@ -98,7 +98,7 @@ Execution rules: - Prefer `git mv` for moves and renames of tracked paths. Use plain `mv` only for untracked paths or operations git cannot express cleanly. - Prefer `git rm` for removals of tracked paths. Use plain `rm` only for untracked paths. - Push the branch with /git-publish. Never hand-roll `git push`: `git push origin $(...)`. -- To open a change request, use `change-request-publish` — it skips creation when one already exists for the current branch. +- To open a change request, use /change-request-publish — it skips creation when one already exists for the current branch. - **Default behavior:** Execute the plan task-by-task by dispatching a fresh `@implement-task` worker for each task. This is the standard workflow — do not deviate unless the user explicitly requests inline implementation. - **Inline implementation:** Acceptable only when the user explicitly asks you to implement directly rather than delegating. When executing inline, apply the same task/review gates as delegated workers. - **Controller duties:** Your primary role is orchestration — dispatch tasks, package context for workers, review worker reports and diffs, enforce spec compliance and code quality review gates, and run verification before any completion claim. diff --git a/core/opencode/agents/planner.md b/core/opencode/agents/planner.md index a944e47..3c44ec4 100644 --- a/core/opencode/agents/planner.md +++ b/core/opencode/agents/planner.md @@ -55,7 +55,7 @@ You are the planning agent. Load `docs/agents/planner.md` before writing a plan and follow its document list exactly. Load the approved spec first. -Your job is to write implementation plans, not code. Use the `workflow-planning` skill. Write plans to `plans/YYYY-MM-DD-feature-name/plan.md` next to the spec. +Your job is to write implementation plans, not code. Use the /workflow-planning skill. Write plans to `plans/YYYY-MM-DD-feature-name/plan.md` next to the spec. Plan requirements: @@ -78,7 +78,7 @@ Shell guidance: - Prefer relative workspace paths in shell commands and examples (e.g., `mkdir -p plans/2026-05-25-feature-name`). - Avoid absolute workspace paths in shell commands unless a tool explicitly requires them. -- Push the branch with `git-publish`. Never hand-roll `git push`. +- Push the branch with /git-publish. Never hand-roll `git push`. Do not invoke brainstorming automatically. If requirements are unclear enough that planning would be speculative, ask the user whether to switch to `@brainstorm`. diff --git a/core/opencode/agents/review-code.md b/core/opencode/agents/review-code.md index a8c1f8d..0cb9ece 100644 --- a/core/opencode/agents/review-code.md +++ b/core/opencode/agents/review-code.md @@ -101,6 +101,6 @@ When escalating, clearly state: 2. Why the issues exceed review-fix scope 3. Which agent (`@planner` or `@brainstorm`) should handle it and why -When reviewing external comments, use `change-request-comments`. Always check open change request comments by default unless the user explicitly says not to. Verify each technical claim before recommending changes. Suggest changes only. Before posting any comment reply, present the exact draft reply and wait for explicit user approval. Approval to dispatch fixes, write a fix plan, or edit files does not authorize posting comments. +When reviewing external comments, use /change-request-comments. Always check open change request comments by default unless the user explicitly says not to. Verify each technical claim before recommending changes. Suggest changes only. Before posting any comment reply, present the exact draft reply and wait for explicit user approval. Approval to dispatch fixes, write a fix plan, or edit files does not authorize posting comments. When fixes are needed (and escalation rules do not apply), dispatch `@implement-task` with the specific fix instructions. Provide the full context: what to change, why, and which files are affected. Do not edit code directly — let implement-task handle the implementation with proper TDD and verification. diff --git a/core/opencode/agents/review-plan.md b/core/opencode/agents/review-plan.md index 091d022..59f80ff 100644 --- a/core/opencode/agents/review-plan.md +++ b/core/opencode/agents/review-plan.md @@ -72,4 +72,4 @@ Use this standard review-plan workflow unless the user explicitly requests a dif When reviewing external comments, use /change-request-comments. Always check open change request comments by default unless the user explicitly says not to. Verify each technical claim before recommending changes. Suggest changes only. Before posting any comment reply, present the exact draft reply and wait for explicit user approval. Approval to edit `plans/**` does not authorize posting comments. -Push the branch with `git-publish`. Never hand-roll `git push`. +Push the branch with /git-publish. Never hand-roll `git push`. From 374dfdb1a82f73c3dfa6ed330f80fb4b7d6c0dc9 Mon Sep 17 00:00:00 2001 From: Simon Flandergan Date: Sun, 28 Jun 2026 18:44:46 +0200 Subject: [PATCH 61/65] Detect non-slash boundary skill references --- scripts/check-workflow-boundaries.sh | 48 ++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/scripts/check-workflow-boundaries.sh b/scripts/check-workflow-boundaries.sh index b6995d8..9ff2388 100755 --- a/scripts/check-workflow-boundaries.sh +++ b/scripts/check-workflow-boundaries.sh @@ -117,4 +117,52 @@ if [[ "$FAILED" -ne 0 ]]; then exit 1 fi +# --- Bare boundary-skill reference check --- +# Workflow-facing body text must use slash references (e.g. /git-publish) for +# boundary skills, not bare backticked names (e.g. `git-publish`). + +BOUNDARY_SKILL_NAMES=( + 'git-publish' + 'change-request-publish' + 'change-request-comments' + 'issue-tracker' +) + +for file in "${TARGET_FILES[@]}"; do + # Skip boundary skill docs + skip=false + for boundary in "${BOUNDARY_SKILLS[@]}"; do + if [[ "$file" == "$boundary"/* ]]; then + skip=true + break + fi + done + [[ "$skip" == true ]] && continue + + # For OpenCode agent files, only check body text (after second ---) + if [[ "$file" == core/opencode/agents/*.md ]]; then + body=$(awk 'BEGIN{n=0} /^---$/{n++; next} n>=2{print}' "$file") + else + body=$(cat "$file") + fi + + for skill_name in "${BOUNDARY_SKILL_NAMES[@]}"; do + # Match backtick-wrapped name without leading slash + if echo "$body" | rg -n "[^/]\`$skill_name\`" 2>/dev/null; then + echo " ^ bare reference in $file" >&2 + FAILED=1 + fi + # Also match start-of-line backtick-wrapped name without leading slash + if echo "$body" | rg -n "^\`$skill_name\`" 2>/dev/null; then + echo " ^ bare reference in $file" >&2 + FAILED=1 + fi + done +done + +if [[ "$FAILED" -ne 0 ]]; then + echo "ERROR: bare boundary-skill references found; use slash form (e.g. /git-publish)." >&2 + exit 1 +fi + echo "OK: no provider-internal leakage in generic workflow files." From fa1546bfd19ccbff766b6f336047b49dfc577177 Mon Sep 17 00:00:00 2001 From: Simon Flandergan Date: Sun, 28 Jun 2026 18:45:44 +0200 Subject: [PATCH 62/65] Fix skill references for planning --- .opencode/agents/planning.md | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/.opencode/agents/planning.md b/.opencode/agents/planning.md index 937de20..fef0c13 100644 --- a/.opencode/agents/planning.md +++ b/.opencode/agents/planning.md @@ -14,6 +14,8 @@ permission: "wc *": allow "date *": allow "which *": allow + # Verification + "codespell *": allow # Directory creation for plans "mkdir plans/*": allow "mkdir -p plans/*": allow @@ -27,34 +29,32 @@ permission: "git branch *": allow "git checkout *": allow "git commit *": allow - # Publish helper - "codespell *": allow - "scripts/publish-branch.sh": allow - "bash scripts/publish-branch.sh": allow + # Push changes and open PR + "bash .agents/skills/git-publish/scripts/push-branch.sh*": allow + "bash .agents/skills/change-request-publish/scripts/open-change-request.sh*": allow # Protective denials are last because opencode uses last-match-wins permissions "git branch -d *": deny "git branch -D *": deny "git worktree remove *": deny - "git push --force *": deny - "git push -f *": deny - "git push origin --force *": deny - "git push origin -f *": deny - "git push origin main*": deny - "git push origin +main*": deny + # Push is done via git-publish + "git push*": deny task: "*": deny "explore": allow skill: "*": deny "agent-planning": allow + "change-request-publish": allow + "git-publish": allow "writing-skills": allow --- You are the planning agent for this toolkit repo. -Load the approved spec first. Use the `agent-planning` skill to write the plan. +Load the approved spec first. +Use the /agent-planning skill to write the plan. -Your task is to write implementation plans to `plans/YYYY-MM-DD-feature-name/plan.md` next to the spec. +Your task is to write implementation plans to `plans/YYYY-MM-DD-feature-name/plan.md`. Plan requirements: @@ -67,4 +67,5 @@ Plan requirements: Use `@explore` when you need to investigate before planning. Continue after the context is strong enough to support the plan. -After writing the plan, commit the plan file, run `scripts/publish-branch.sh` to push the branch and create or report the PR, and report the plan path, PR URL, and any open questions. +After writing the plan, commit the plan file, invoke /git-publish to push the branch and /change-request-publish to create a PR. +Report the plan path, PR URL, and any open questions. From fc7e2c26572df9c2894a5b1f89aaf4da6482ca7d Mon Sep 17 00:00:00 2001 From: Simon Flandergan Date: Sun, 28 Jun 2026 18:45:53 +0200 Subject: [PATCH 63/65] Fix shellcheck for neutral skill scripts --- .../skills/change-request-comments/scripts/fetch-comments.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/core/agents/skills/change-request-comments/scripts/fetch-comments.sh b/core/agents/skills/change-request-comments/scripts/fetch-comments.sh index bc519a2..8451263 100755 --- a/core/agents/skills/change-request-comments/scripts/fetch-comments.sh +++ b/core/agents/skills/change-request-comments/scripts/fetch-comments.sh @@ -35,6 +35,7 @@ case "$remote_url" in pr_json="$(gh pr view "$pr" --json number,title,headRefName,baseRefName,url,comments,headRepository)" repo=$(jq -r '.headRepository.nameWithOwner' <<<"$pr_json") issue_comments_json="$(gh api "repos/$repo/issues/$pr/comments")" + # shellcheck disable=SC2016 # GraphQL variables ($owner, $name, $pr) are intentionally single-quoted inline_comments_json="$(gh api graphql \ -F owner="${repo%%/*}" \ -F name="${repo#*/}" \ From 1aab1e3e4f1a8ac35493a0fc1922b825a20a744f Mon Sep 17 00:00:00 2001 From: Simon Flandergan Date: Sun, 28 Jun 2026 18:58:50 +0200 Subject: [PATCH 64/65] Sync README with self-maintenance skills --- README.md | 6 ++++-- core/claude/README.md | 2 +- core/claude/skills/implement/SKILL.md | 2 +- core/claude/skills/planner/SKILL.md | 2 +- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index c1e0492..75e668f 100644 --- a/README.md +++ b/README.md @@ -165,7 +165,7 @@ The diagram above maps the full cycle from brainstorming a feature through to sh | # | Step | Invocation | |---|---|---| -| 7 | **Implement task-by-task** — dispatch one worker per plan task, verify, and commit. | Claude `/implement` or OpenCode `@implement` (controller) which spawns implement-task workers. Pick one harness per branch. | +| 7 | **Implement task-by-task** — dispatch one worker per plan task, verify, and commit. | Claude `/implement` or OpenCode `@implement` (controller) which spawns implement-task workers. Pick one per task. | | 8 | **Human comments code** — review the diff and leave inline comments or change-request review notes. | Human checkpoint (no agent invocation). | | 9 | **Review code** — analyze review feedback and determine required changes. | OpenCode `@review-code` or Claude `/review-code`. | | 10 | **Review / Remark plan** — if code review surfaces scope changes, update the plan and loop back to step 7. Repeat until the plan is sound and complete. | OpenCode `@planner` or Claude `/planner` to revise; then re-enter implementation at step 7. | @@ -221,9 +221,11 @@ Under `.agents/skills/` (symlinked into `.claude/skills/` for Claude Code compat | `agent-verification` | Evidence-before-claims gate, verification commands, smoke runs | | `agent-review` | Plan + diff review checklist aligned to `AGENTS.md` | | `change-request-comments` | Comment fetching, classification, and reply workflow | +| `git-publish` | Branch push with safety guards (refuses main/master, force-push) | +| `change-request-publish` | PR/MR creation with idempotency (skips when one exists) | | `writing-skills` | Remote skill from `obra/superpowers` for authoring skills | -Invoke in Claude Code with `/agent-planning`, `/agent-implementation`, `/agent-verification`, `/agent-review`, or `/change-request-comments`. The `writing-skills` skill is also exposed as `/writing-skills`. +Invoke in Claude Code with `/agent-planning`, `/agent-implementation`, `/agent-verification`, `/agent-review`, `/change-request-comments`, `/git-publish`, or `/change-request-publish`. The `writing-skills` skill is also exposed as `/writing-skills`. ### Lockfiles diff --git a/core/claude/README.md b/core/claude/README.md index 31fb3b4..aa5f1c9 100644 --- a/core/claude/README.md +++ b/core/claude/README.md @@ -1,7 +1,7 @@ # Claude Code agent setup Claude Code runs both the **conversational** and **implementation** halves of the -agent pipeline. OpenCode provides the same pipeline; pick one harness per branch. +agent pipeline. OpenCode provides the same pipeline; pick one harness per task. ## The skills diff --git a/core/claude/skills/implement/SKILL.md b/core/claude/skills/implement/SKILL.md index 168c515..c873129 100644 --- a/core/claude/skills/implement/SKILL.md +++ b/core/claude/skills/implement/SKILL.md @@ -7,7 +7,7 @@ disable-model-invocation: true You are the implementation controller for this repository. This is the Claude Code implementation controller. OpenCode has an equivalent controller agent. -Pick one harness per branch — do not run both controllers over the same plan. +Pick one harness per task — do not run both controllers over the same plan. Approved plan (if provided): $ARGUMENTS diff --git a/core/claude/skills/planner/SKILL.md b/core/claude/skills/planner/SKILL.md index 9806e16..d622675 100644 --- a/core/claude/skills/planner/SKILL.md +++ b/core/claude/skills/planner/SKILL.md @@ -76,4 +76,4 @@ inlining them here. spec/plan markdown only when the user asks for committed workflow artifacts. - After the plan is written, **stop**. Optionally suggest `/review-plan` before handoff. - Tell the user to review the plan and continue with /review-plan if they have remarks or /implement to start implementing the plan - (the implement agent). Pick one per branch. Suggest the user's preferred harness. + (the implement agent). Pick one per task. Suggest the user's preferred harness. From f1428d70e74b4e5c3fbe392c64aafe906f8495b2 Mon Sep 17 00:00:00 2001 From: Simon Flandergan Date: Sun, 28 Jun 2026 19:00:54 +0200 Subject: [PATCH 65/65] Tighten bugfix and Claude permissions --- core/opencode/agents/bugfix.md | 4 +++- scripts/copy.sh | 2 +- scripts/init.sh | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/core/opencode/agents/bugfix.md b/core/opencode/agents/bugfix.md index f6b8a5a..58b953c 100644 --- a/core/opencode/agents/bugfix.md +++ b/core/opencode/agents/bugfix.md @@ -11,7 +11,9 @@ permission: "*": ask # Skill scripts — primary tools - "bash .agents/skills/issue-tracker/scripts/*.sh": allow + "bash .agents/skills/issue-tracker/scripts/create-issue.sh *": allow + "bash .agents/skills/issue-tracker/scripts/find-duplicate-issues.sh *": allow + "bash .agents/skills/issue-tracker/scripts/update-issue.sh *": allow # Read-only git commands "git branch --show-current": allow diff --git a/scripts/copy.sh b/scripts/copy.sh index 5551b58..468cb51 100755 --- a/scripts/copy.sh +++ b/scripts/copy.sh @@ -407,7 +407,7 @@ for agent_file in "$STAGE/.opencode/agents/"*.md; do done # --------------------------------------------------------------------------- -# 10b. .claude/agents/*.md handling +# 10b. Install .claude/agents/*.md # --------------------------------------------------------------------------- echo "" for agent_file in "$STAGE/.claude/agents/"*.md; do diff --git a/scripts/init.sh b/scripts/init.sh index d3c4a58..185240d 100755 --- a/scripts/init.sh +++ b/scripts/init.sh @@ -262,7 +262,7 @@ for skill_name in "${AUTHORED_SKILLS[@]}"; do done # --------------------------------------------------------------------------- -# 7b. .claude/agents/*.md handling +# 7b. Install .claude/agents/*.md # --------------------------------------------------------------------------- echo "" for agent_file in "$STAGE/.claude/agents/"*.md; do