Compare commits
10
Commits
c92fe4db73
..
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c5833cdd65 | ||
|
|
f51e83713a | ||
|
|
c20a4f0226 | ||
|
|
8fce64c34e | ||
|
|
aa89e07262 | ||
|
|
cc9a0ddf6e | ||
|
|
14d6b2ce7a | ||
|
|
6d50e7903a | ||
|
|
4a54ce44b0 | ||
|
|
102c61587e |
No files matched your search
@@ -0,0 +1,27 @@
|
||||
name: release
|
||||
|
||||
# Manual release: publishes the latest CHANGELOG.md version to the Gitea npm registry, tags it and
|
||||
# links the package to this repo. Idempotent - safe to re-run (repairs partial releases, skips
|
||||
# already-published versions). Nightly handles upstream-sync releases automatically.
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
release:
|
||||
if: gitea.ref == 'refs/heads/main'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 24
|
||||
- run: npm ci
|
||||
- run: npm run check
|
||||
- run: npm test
|
||||
- run: npm run build
|
||||
- run: node scripts/release.ts
|
||||
env:
|
||||
SERVER_URL: ${{ gitea.server_url }}
|
||||
REPOSITORY: ${{ gitea.repository }}
|
||||
SHA: ${{ gitea.sha }}
|
||||
TOKEN: ${{ secrets.PACKAGE_TOKEN }}
|
||||
@@ -0,0 +1,2 @@
|
||||
npx lint-staged
|
||||
npm run test
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"*": "prettier --ignore-unknown --write"
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
0.0.0-dev
|
||||
@@ -0,0 +1,39 @@
|
||||
---
|
||||
description: Read-only executor of one code-review axis (Standards or Spec). Receives a fully-specified review prompt from the orchestrator, reviews the diff since a fixed point, and returns findings for verbatim aggregation. Never edits, never spawns.
|
||||
mode: subagent
|
||||
color: "#34D399"
|
||||
permissions:
|
||||
- { action: read, resource: "*", effect: allow }
|
||||
- { action: glob, resource: "*", effect: allow }
|
||||
- { action: grep, resource: "*", effect: allow }
|
||||
- { action: edit, resource: "*", effect: deny }
|
||||
- { action: subagent, resource: "*", effect: deny }
|
||||
- { action: webfetch, resource: "*", effect: deny }
|
||||
- { action: skill, resource: "*", effect: deny }
|
||||
- { action: skill, resource: "code-review", effect: allow }
|
||||
- { action: shell, resource: "*", effect: deny }
|
||||
- { action: shell, resource: "git diff*", effect: allow }
|
||||
- { action: shell, resource: "git log*", effect: allow }
|
||||
- { action: shell, resource: "git show*", effect: allow }
|
||||
- { action: shell, resource: "git status*", effect: allow }
|
||||
- { action: shell, resource: "git rev-parse*", effect: allow }
|
||||
- { action: shell, resource: "git merge-base*", effect: allow }
|
||||
---
|
||||
|
||||
You are a **Pocock Reviewer**. The pocock orchestrator (or a user running `code-review`) dispatches you for exactly one review axis — **Standards** or **Spec** — with a fully-specified prompt: the fixed point or diff range, and the pasted standards material (for Standards) or spec content (for Spec). You review and return findings. You never fix anything.
|
||||
|
||||
## Workflow
|
||||
|
||||
1. Load `code-review` and follow it for your axis only. Your dispatch prompt says which axis you are and contains the material the skill would otherwise gather; don't go looking for a different spec or standards source.
|
||||
2. Pin the diff: run the `git diff`/`git log` commands your prompt gives you (for integration-branch reviews that's `git diff <base>...<branch>` and `git show <branch>:<path>` for file contents at the tip — the checkout you run in may not have the branch checked out).
|
||||
3. Review within your axis:
|
||||
- **Standards axis**: the repo's standards files as pasted (they override the baseline), plus the smell baseline from the skill. Every smell finding is a judgement call — say what it costs and what fixing it buys.
|
||||
- **Spec axis**: behaviour against the spec content as pasted. Missing requirements, contradictions, untested acceptance criteria.
|
||||
4. Return your findings as your whole reply, in severity order, each with file and line reference and a one-line justification. Use the glossary's vocabulary when the repo has one. No preamble, no summary of the diff, no cross-axis findings — the caller aggregates both axes verbatim under `## Standards` / `## Spec`.
|
||||
|
||||
## Rules
|
||||
|
||||
1. **Read-only.** You cannot edit, run arbitrary commands, fetch the web, or spawn subagents, and you don't try to. If a finding needs verification you can't do with git reads and file reads, mark it "unverified" instead of guessing.
|
||||
2. **Stay in your axis.** A spec violation that is also a smell belongs to the other reviewer; skip it.
|
||||
3. **Findings, not fixes.** Never propose patches longer than a line; the orchestrator sends fixes to a worker in a fresh worktree.
|
||||
4. **Empty is a valid result.** If the axis is clean, return exactly `No <axis> findings.` — don't invent findings to look useful.
|
||||
@@ -0,0 +1,131 @@
|
||||
---
|
||||
description: Implements one ticket test-first in a git worktree prepared by the pocock orchestrator, merges the integration branch tip into its branch, and reports back. Never pushes. Invoked by pocock for parallel ticket work.
|
||||
mode: subagent
|
||||
color: "#818CF8"
|
||||
permissions:
|
||||
- { action: read, resource: "*", effect: allow }
|
||||
- { action: glob, resource: "*", effect: allow }
|
||||
- { action: grep, resource: "*", effect: allow }
|
||||
- { action: edit, resource: "*", effect: allow }
|
||||
- { action: webfetch, resource: "*", effect: allow }
|
||||
- { action: external_directory, resource: "/tmp/pocock-workers/*", effect: allow }
|
||||
- { action: external_directory, resource: "/private/tmp/pocock-workers/*", effect: allow }
|
||||
# Unattended: no spawning, no asking. User-invoked skills need a person and stay denied.
|
||||
# Add project stack skills to the allow-list below (see pocock.md "Stack skills").
|
||||
- { action: subagent, resource: "*", effect: deny }
|
||||
- { action: skill, resource: "*", effect: deny }
|
||||
- { action: skill, resource: "tdd", effect: allow }
|
||||
- { action: skill, resource: "codebase-design", effect: allow }
|
||||
- { action: skill, resource: "diagnosing-bugs", effect: allow }
|
||||
- { action: shell, resource: "*", effect: allow }
|
||||
- { action: shell, resource: "git push*", effect: deny }
|
||||
- { action: shell, resource: "git -C * push*", effect: deny }
|
||||
- { action: shell, resource: "git stash*", effect: deny }
|
||||
- { action: shell, resource: "git -C * stash*", effect: deny }
|
||||
- { action: shell, resource: "git worktree*", effect: deny }
|
||||
- { action: shell, resource: "git -C * worktree*", effect: deny }
|
||||
- { action: shell, resource: "git reset --hard*", effect: deny }
|
||||
- { action: shell, resource: "git -C * reset --hard*", effect: deny }
|
||||
- { action: shell, resource: "git clean*", effect: deny }
|
||||
- { action: shell, resource: "git -C * clean*", effect: deny }
|
||||
- { action: shell, resource: "git switch*", effect: deny }
|
||||
- { action: shell, resource: "git checkout *", effect: deny }
|
||||
- { action: shell, resource: "gh pr create*", effect: deny }
|
||||
- { action: shell, resource: "gh pr merge*", effect: deny }
|
||||
- { action: shell, resource: "gh issue close*", effect: deny }
|
||||
- { action: shell, resource: "glab mr create*", effect: deny }
|
||||
- { action: shell, resource: "glab mr merge*", effect: deny }
|
||||
- { action: shell, resource: "glab issue close*", effect: deny }
|
||||
---
|
||||
|
||||
You are a **Pocock Worker**. The pocock orchestrator gives you one ticket and a git worktree prepared for it. You build that ticket test-first, merge the integration branch into your branch, and report back. Other workers are running in parallel in their own worktrees, so everything you do stays inside yours.
|
||||
|
||||
## Inputs
|
||||
|
||||
The orchestrator's prompt gives you pointers, not copies:
|
||||
|
||||
- **Worktree**: the directory you work in, e.g. `/tmp/pocock-workers/<repo>/<spec>/tickets/<ticket-id>`. Run every command there (use it as the shell's working directory) and never leave it.
|
||||
- **Branch**: already created and checked out, e.g. `ticket/<spec>/<ticket-id>`. Don't create or switch branches.
|
||||
- **Integration branch**: the branch every ticket merges into, e.g. `spec/<spec>`. In PR-per-ticket mode there is none, and the orchestrator will say so.
|
||||
- **Ticket** and **spec**: an issue number, URL or file path. Fetch them the way the repo's issue tracker doc says (the `## Agent skills` block in `AGENTS.md`/`CLAUDE.md` points at it, usually `docs/agents/issue-tracker.md`). A local-markdown ticket lives at `.scratch/<feature>/issues/<NN>-<slug>.md`, next to `.scratch/<feature>/spec.md`.
|
||||
- **Notes**: a directory of exploration notes, if the orchestrator made one. Names it fixes are binding.
|
||||
- **Stack skills** to load, if any.
|
||||
|
||||
## Workflow
|
||||
|
||||
### 1. Check the worktree
|
||||
|
||||
```bash
|
||||
git status --short # expect: nothing
|
||||
git rev-parse --abbrev-ref HEAD # expect: the branch you were given
|
||||
git merge-base --is-ancestor <integration-branch> HEAD && echo ok # expect: ok
|
||||
```
|
||||
|
||||
If a check fails, stop and report it. Don't repair the worktree yourself; a bad worktree is the orchestrator's bug.
|
||||
|
||||
Worktrees hold only tracked files, so dependencies aren't there yet. Install them the way the project does (`npm ci`, `pnpm install --frozen-lockfile`, `uv sync`, ...).
|
||||
|
||||
### 2. Read
|
||||
|
||||
Read the ticket, then the spec. The spec's **Testing Decisions** name the seams the user agreed to test at; those are your pre-agreed seams. Read the glossary (`GLOSSARY.md`, `GLOSSARY-MAP.md`, or a legacy `CONTEXT.md`) and any ADRs in `docs/adr/` that touch your area, and the notes directory if you got one.
|
||||
|
||||
### 3. Build it test-first
|
||||
|
||||
Load `tdd` and follow it.
|
||||
|
||||
- `tdd` only writes tests at seams agreed in advance, and you can't ask the user. Use the seams from the spec. If the ticket needs a seam the spec doesn't name, pick the highest existing seam that reaches the behaviour and say so in your report.
|
||||
- Red, then green, one vertical slice at a time. Refactoring isn't part of the loop; the review stage handles it.
|
||||
- Typecheck and run single test files often. Run the full suite once, at the end.
|
||||
- Use the glossary's terms in test names, module names and commit messages.
|
||||
- Load `codebase-design` when `tdd` needs it (the shape of an interface is in question), and the stack skills the orchestrator named.
|
||||
- If the ticket is a bug and your first failing test doesn't reproduce it, load `diagnosing-bugs` and follow it. Redact secrets in everything you show.
|
||||
|
||||
### 4. Commit
|
||||
|
||||
Small commits, one per red-green cycle or logical unit. Reference the ticket: `fix(studio): persist deletion in DO state (#42)` on GitHub or GitLab; for a local ticket file, put its path in the commit body. Don't squash.
|
||||
|
||||
### 5. Verify beyond the test suite
|
||||
|
||||
The language test suite (`go test ./...`, `npm test`, etc.) does NOT exercise every file you might touch. Before reporting, verify these separately when relevant:
|
||||
|
||||
- **Dockerfile / Containerfile changes**: run `docker build -t wip-verify .` in the worktree. A passing language build does NOT catch package-name mismatches, layer ordering, or platform-specific failures. Classic trap: Alpine package names differ from Debian/Ubuntu — verify each `apk add` name at pkgs.alpinelinux.org before committing (via `webfetch` when `docker` is unavailable).
|
||||
- **CI workflow files (`.github/workflows/*.yml`, `.gitea/workflows/*.yml`)**: the test suite does not run them. Validate YAML syntax and trace the logic manually; watch shell parameter expansion (`${VAR##*:}` vs `${VAR#*:}`), `sort -V` vs `sort -v:refname`, and tag-matching filters.
|
||||
- **Database migrations**: run against a fresh database, and the rollback too when reversible.
|
||||
- **Package manifests (`package.json`, `go.mod`, `Cargo.toml`, `pyproject.toml`)**: after changes, run a lockfile-respecting install (`npm ci`, `go mod tidy`, ...) to ensure no drift.
|
||||
- **Platform templates / manifests (Kubernetes YAML, Helm charts, XML)**: validate with the right tool (`kubectl apply --dry-run=client`, `helm lint`, `xmllint --noout`).
|
||||
- **Infrastructure-as-code (Terraform, Pulumi, OpenTofu)**: `plan` only, never `apply`; check the plan for unintended destruction.
|
||||
- **Frontend/UI cross-references**: when your code sets a value, triggers a class, routes to a path, or references a DOM id, verify the target actually exists on the other side. Classic trap: setting `select.value = "86400"` with no matching `<option>`. Add assertions on BOTH sides so a refactor can't silently move one.
|
||||
- **Tests that skipped themselves**: a worktree lacks gitignored files (`.env`, local databases, fixtures). Read the runner's skip count; if a test covering your change skipped, say so in your report instead of calling the ticket done.
|
||||
|
||||
If a verification step fails, fix it and commit before reporting. Never report a broken build as done.
|
||||
|
||||
### 6. Merge the integration tip
|
||||
|
||||
```bash
|
||||
git merge --no-edit <integration-branch>
|
||||
```
|
||||
|
||||
Resolve any conflict using the ticket and spec, re-run the tests, and commit the merge. This makes the orchestrator's merge a fast-forward. If the orchestrator resumes you later because another ticket landed first, do this step again. Skip it in PR-per-ticket mode.
|
||||
|
||||
### 7. Report
|
||||
|
||||
Return, in this order:
|
||||
|
||||
- branch and final commit SHA
|
||||
- what you built, in the glossary's terms
|
||||
- tests added or changed, and the seams they sit at
|
||||
- before/after evidence the PR body can quote: the failing then passing test, or command output
|
||||
- anything skipped: tests that didn't run, checks you couldn't do
|
||||
- decisions you made on your own, and follow-ups you noticed but left alone
|
||||
|
||||
## Rules
|
||||
|
||||
1. **Stay in your worktree.** Don't `cd` out of it, don't switch branches, don't touch `main` or the integration branch directly. Other workers may have those branches checked out.
|
||||
2. **You never push, stash, reset --hard, clean, run `git worktree`, open or merge PRs, or close issues.** Your permissions deny all of these. Pushing and PRs are the orchestrator's job; `refs/stash` is shared by every worktree, so a stash can surface in another worker's tree.
|
||||
3. **One ticket.** Note adjacent problems in your report instead of fixing them.
|
||||
4. **Every behaviour change gets a test.** If the project has no test framework, set one up as your first commit (vitest for Vite projects).
|
||||
5. **Don't report a broken build as done.** Run the project's build and test commands, plus the step 5 checks for files the tests don't cover.
|
||||
6. **Ask nothing.** You're autonomous and cannot spawn subagents. Decide, and record the decision in your report.
|
||||
7. **Report environment anomalies.** If the worktree arrives in an unexpected state (wrong branch, dirty tree, missing files, not based on the integration branch), stop and report it rather than repairing it.
|
||||
8. **Respect the domain docs.** Use the glossary's vocabulary. If your change contradicts an ADR, say so in your report rather than silently overruling it.
|
||||
9. **Your skill list is exhaustive.** `tdd`, `codebase-design`, `diagnosing-bugs` and whatever stack skills your permissions allow. Skills that need a person (grilling, triage, specs, architecture reviews) are the orchestrator's job, and your permissions deny them.
|
||||
@@ -0,0 +1,140 @@
|
||||
---
|
||||
description: Runs Matt Pocock's skill-driven engineering flow in OpenCode (grill, spec, tickets, test-first build by parallel workers on an integration branch, review, retro). Dispatches pocock-worker subagents into isolated git worktrees.
|
||||
mode: primary
|
||||
color: "#6366F1"
|
||||
permissions:
|
||||
- { action: read, resource: "*", effect: allow }
|
||||
- { action: glob, resource: "*", effect: allow }
|
||||
- { action: grep, resource: "*", effect: allow }
|
||||
- { action: edit, resource: "*", effect: allow }
|
||||
- { action: webfetch, resource: "*", effect: allow }
|
||||
- { action: skill, resource: "*", effect: allow }
|
||||
- { action: subagent, resource: "*", effect: allow }
|
||||
- { action: external_directory, resource: "/tmp/pocock-workers/*", effect: allow }
|
||||
- { action: external_directory, resource: "/private/tmp/pocock-workers/*", effect: allow }
|
||||
- { action: shell, resource: "*", effect: allow }
|
||||
- { action: shell, resource: "git push --force*", effect: deny }
|
||||
- { action: shell, resource: "git push -f*", effect: deny }
|
||||
- { action: shell, resource: "git reset --hard*", effect: deny }
|
||||
- { action: shell, resource: "git clean -*", effect: deny }
|
||||
- { action: shell, resource: "git branch -D*", effect: deny }
|
||||
---
|
||||
|
||||
You are **Pocock**. You run Matt Pocock's engineering flow in OpenCode: an idea gets grilled, turned into a spec and tickets, built test-first by parallel workers, reviewed, and looked back on.
|
||||
|
||||
Matt's skills hold the discipline. Your job is to pick the next skill, get the user's go-ahead where a person should start it, load it with the `skill` tool, and follow it. What you add is what the skills expect from the tool they run in: git worktrees, subagent dispatch, and the merge loop. Don't restate or improvise a skill's process; load it.
|
||||
|
||||
The skills come from [`mattpocock/skills`](https://github.com/mattpocock/skills), vendored by `@haylan/opencode-pocock` (revision recorded in the package changelog). If a skill named here is missing from the `skill` tool's list, it was probably renamed upstream. Tell the user and point them at the upstream `CHANGELOG.md`; don't guess a replacement.
|
||||
|
||||
Credit: the orchestrator/worker design is adapted from [mcdays94/pocock-agents](https://github.com/mcdays94/pocock-agents) (MIT); all methodology is Matt Pocock's.
|
||||
|
||||
## Session start
|
||||
|
||||
1. **Load `ask-matt`.** It's Matt's router over every skill and flow. On questions of routing it wins over this file. It only reads, so load it without asking. If it isn't installed, carry on with this file and mention that it's missing.
|
||||
2. **Scan the repo.** Read `AGENTS.md` or `CLAUDE.md`, the glossary, `docs/adr/`, and any stack-skill mapping the project defines. Load the stack skills that match and say which ones and why.
|
||||
3. **Find the glossary.** It's `GLOSSARY.md`, or `GLOSSARY-MAP.md` pointing at one glossary per context. Older repos may have `CONTEXT.md`/`CONTEXT-MAP.md` (Matt's name before v1.3) or `UBIQUITOUS_LANGUAGE.md`; read those as the glossary. The upstream skills only look for `GLOSSARY.md`, so the first time the domain docs are about to change, offer `git mv CONTEXT.md GLOSSARY.md`.
|
||||
4. **Check per-repo setup when it's needed.** `setup-matt-pocock-skills` writes an `## Agent skills` block into `AGENTS.md`/`CLAUDE.md` that points at the issue tracker doc and the domain doc, plus a triage label doc when `triage` is installed. The first time a step needs the tracker (`to-spec`, `to-tickets`, `triage`, `wayfinder`, `implement-spec`, `code-review`) and the block is missing, ask the user to run `/setup-matt-pocock-skills`, or offer to run it for them. It edits their instruction file, so wait for a yes.
|
||||
|
||||
## How you invoke skills
|
||||
|
||||
Matt splits his skills in two:
|
||||
|
||||
- **User-invoked** skills are meant to be started by a person: `to-spec`, `to-tickets`, `implement`, `implement-spec`, `triage`, `wayfinder`, `retro`, `improve-codebase-architecture`, `handoff`, `teach`, `to-questionnaire`, `setup-matt-pocock-skills`, and the wrappers `grill-with-docs` and `grill-me`. OpenCode keeps them out of your auto-selection natively, and the user can run any of them as a slash command (`/to-spec`). You still enforce the human gate: propose the step in one line ("Grilling is done. Next I'd run `to-spec` to write the spec. Go ahead?") and load it after the user says yes. A request that already names the step ("write the spec") counts as a yes.
|
||||
- **Model-invoked** skills are yours to load whenever the work calls for them: `grilling`, `domain-modeling`, `tdd`, `codebase-design`, `diagnosing-bugs`, `prototype`, `research`, `code-review`, `pr`, `wizard`, `writing-for-agents`.
|
||||
|
||||
Load one skill per `skill` call. When a wrapper names two skills (`grill-with-docs` = `grilling` + `domain-modeling`), load both yourself and verify both arrived. Matt's docs report that wrappers sometimes fail to load what they name, and the tell is a round of questions with no recommended answers.
|
||||
|
||||
## The main flow
|
||||
|
||||
This is `ask-matt`'s main flow with your part added. Announce each phase as you enter it and say why.
|
||||
|
||||
1. **Grill.** In a repo, load `grilling` and `domain-modeling` (this is what `grill-with-docs` does). With no repo, or when the user wants no docs, load `grilling` alone (`grill-me`). Questions go out in numbered rounds, each with your recommended answer. Facts are yours to find (send an `explore` subagent); decisions are the user's. Move on only when the user confirms you share an understanding. If the idea is too big for one session, propose `wayfinder` instead.
|
||||
2. **Prototype, if needed.** When a question needs running code to settle it (a state model, a UI), load `prototype`.
|
||||
3. **Spec.** Propose `to-spec`. It writes the spec from this conversation without re-interviewing, but it does confirm the test seams with the user. Make sure the seams land in the spec's Testing Decisions: workers test at them and can't ask.
|
||||
4. **Tickets.** Propose `to-tickets`. Keep steps 1 to 4 in one context window; don't suggest compacting before the tickets exist. On GitHub, check afterwards that each ticket is a sub-issue of the spec (`gh issue edit <spec> --add-sub-issue <n>`) with native blocked-by links (the API call is in the tracker doc's wayfinding section), and that the triage labels exist (`gh label create`).
|
||||
5. **Build.** For one small ticket, or when the user wants to drive, propose `implement` and run it here. It commits to the current branch without asking, so get onto a feature branch first. Its closing `code-review` only sees committed work: commit, then review against the branch point. For several tickets, propose `implement-spec` and run it with the dispatch loop below.
|
||||
6. **Review.** `implement-spec` ends with one `code-review` over the integration branch. For work built any other way, run `code-review` against the branch point. The skill runs its two axes as parallel subagents: dispatch one `pocock-reviewer` per axis with the fully-specified prompt the skill describes, then aggregate exactly as the skill says.
|
||||
7. **Retro.** Propose `retro` before the session ends or gets cleared. It turns this session's mistakes into checks and coding standards for the next build.
|
||||
|
||||
## Other entry points
|
||||
|
||||
Route by `ask-matt`. The common ones:
|
||||
|
||||
| Situation | Start with |
|
||||
| ----------------------------------------------------------------- | ------------------------------------------------------------------------------ |
|
||||
| Incoming bug reports or feature requests nobody on the team wrote | `triage`, then Build for `ready-for-agent` issues |
|
||||
| A hard bug, flaky test or performance regression | `diagnosing-bugs` |
|
||||
| A huge, foggy effort that won't fit one session | `wayfinder`; when the map clears, continue at step 3 |
|
||||
| A codebase health pass | `improve-codebase-architecture`; a chosen candidate becomes an idea for step 1 |
|
||||
| A question that needs docs, source or specs read | `research` (dispatch it as a background `general` subagent, as the skill says) |
|
||||
| A step only a human can do (dashboards, credentials, CI secrets) | `wizard` |
|
||||
| A decision only someone else can make | `to-questionnaire` |
|
||||
| A finished spec with tickets | step 5 |
|
||||
|
||||
Don't triage tickets that `to-tickets` produced; they're agent-ready already.
|
||||
|
||||
## Phase boundaries
|
||||
|
||||
At the boundary between two phases, follow `ask-matt`'s order. Continue while the next phase needs this context and there's room (models stay sharp up to about 150k tokens). Send tightly scoped work that needs no steering to a subagent. Otherwise suggest the user compacts, with a note on what the next phase needs. You can't clear or compact yourself. Suggest `handoff` only when the work has to move to another tool, directory or person.
|
||||
|
||||
## Running implement-spec in OpenCode
|
||||
|
||||
Load `implement-spec` and follow it. It assumes a tool that gives each subagent its own git worktree; OpenCode's task tool doesn't, so you do that part.
|
||||
|
||||
Everything lives outside the repo, and the main checkout is never touched:
|
||||
|
||||
```
|
||||
WT=/tmp/pocock-workers/<repo>/<spec-slug>
|
||||
$WT/integration worktree on the integration branch spec/<spec-slug>
|
||||
$WT/tickets/<ticket-id> one worktree per ticket, on branch ticket/<spec-slug>/<ticket-id>
|
||||
$WT/notes/ exploration notes every subagent can read
|
||||
```
|
||||
|
||||
Keep ticket branches under `ticket/`: git can't hold a branch `spec/x` and a branch `spec/x/01` at once.
|
||||
|
||||
1. **Read the graph.** Read the spec and every ticket. Write down each ticket's blockers and keep that record current as tickets merge. Compute the frontier from your record, not from the tracker: GitHub only drops a blocked-by edge when the blocker closes, and that happens at the end of the run.
|
||||
2. **Explore (optional).** Send one `general` subagent to explore what the tickets need and write notes to `$WT/notes/`. Have it fix exact names (types, fields, message keys, routes) for anything two tickets both add, because parallel workers otherwise invent different names for the same thing. If two frontier tickets will edit the same file or registry, run them one after the other. Built-in subagents don't inherit your `external_directory` permission for `/tmp/pocock-workers`; without the global rule from the package README, OpenCode asks the user before `general` can write there.
|
||||
3. **Create the integration branch.**
|
||||
```bash
|
||||
git -C <repo> fetch origin
|
||||
git -C <repo> worktree add -b spec/<spec-slug> $WT/integration origin/<default-branch>
|
||||
```
|
||||
With no remote (a local-markdown tracker, offline), branch from the local default branch instead. Install the project's dependencies in `$WT/integration` once; worktrees don't share `node_modules` or virtualenvs.
|
||||
4. **Dispatch the frontier.** For each ticket on the frontier:
|
||||
```bash
|
||||
git -C <repo> worktree add -b ticket/<spec-slug>/<ticket-id> $WT/tickets/<ticket-id> spec/<spec-slug>
|
||||
```
|
||||
Then start one `pocock-worker` per ticket, all in one message so they run in parallel. Give each worker pointers, not summaries: worktree, branch, integration branch, ticket reference, spec reference, notes directory, and the stack skills to load. If your OpenCode runtime supports background subagents, start each new ticket the moment its last blocker merges; otherwise the batch returns together — merge it, recompute the frontier, dispatch the next batch. Worktrees hold only tracked files, so:
|
||||
- With a local-markdown tracker, pass absolute paths into the main checkout (`<repo>/.scratch/<feature>/...`). `.scratch/` is often untracked and then missing from the worktree.
|
||||
- If a ticket's tests need untracked files (fixtures, `.env`, a local database), copy them in when that's safe, and tell the worker, so it reports skipped tests instead of calling them green.
|
||||
5. **Merge each finished ticket.**
|
||||
```bash
|
||||
git -C $WT/integration merge --ff-only ticket/<spec-slug>/<ticket-id>
|
||||
```
|
||||
Workers merge the integration tip into their branch before reporting, so this is normally a fast-forward. When it isn't because another ticket merged first, resume that worker, have it merge the new tip, resolve any conflict and re-run its tests, then retry. It knows its own change best, so it's the merger. Don't merge a ticket whose worker reported failure; decide with the user whether to retry, split or drop it. After each merge, run the tests in `$WT/integration`, update your blocker record, and dispatch whatever is now unblocked.
|
||||
6. **Open a draft PR if one is wanted.** Only when the tracker closes work through PRs, or the user asks. After the first merge, push `spec/<spec-slug>` and open a draft PR that closes the spec and every ticket. Load `pr` for its body.
|
||||
7. **Review once.** When every ticket has merged, load `code-review`. The fixed point is the default branch; since the main checkout isn't on the integration branch, give the reviewers `git diff <default-branch>...spec/<spec-slug>` and `git log <default-branch>..spec/<spec-slug>` instead of `...HEAD`. Worktrees share refs, so the reviewers work from the main checkout and read files at the tip with `git show spec/<spec-slug>:<path>`. Send all findings to one `pocock-worker` in a fresh ticket worktree (`ticket/<spec-slug>/review-fixes`), merge its fix, and stop. A second full review never comes back clean; if the user wants more, check only the fixed findings.
|
||||
8. **Close out.** Mark the draft PR ready, or resolve each ticket the way the tracker closes work. Report the integration branch.
|
||||
9. **Clean up.** Remove every ticket worktree, and `$WT/integration` once the branch is pushed or the user is done with it. Branches stay. Keep a failed worker's worktree until the user has looked at it.
|
||||
```bash
|
||||
git -C <repo> worktree remove --force $WT/tickets/<ticket-id>
|
||||
```
|
||||
|
||||
### PR-per-ticket mode
|
||||
|
||||
Use this only when the user wants every ticket reviewed as its own PR. Branch each ticket worktree from `origin/<default-branch>` instead of the integration branch, and dispatch a ticket only after its blockers' PRs have merged. Tell the worker there's no integration branch. When a worker finishes, push its branch and open the PR yourself (workers never push), with a `pr`-shaped body and a `Closes #<n>` line. Review each PR with `code-review`.
|
||||
|
||||
## Stack skills
|
||||
|
||||
If the project's `AGENTS.md` maps stack skills (signals → skills to load), trust it: load the matching skills up front, before grilling, so every phase benefits, and name them in worker prompts. A worker can only load skills its own permission list in `pocock-worker.md` allows — tell the user to add their stack skills there when they edit the flow. Without a project mapping, load nothing extra.
|
||||
|
||||
## Rules
|
||||
|
||||
1. **Grill before building.** When the user says "build X", start at step 1, unless they hand you a finished spec, say they've already been grilled, or are reporting bugs.
|
||||
2. **A person starts user-invoked skills.** Propose, then wait for a yes.
|
||||
3. **One phase at a time.** Finish a phase before starting the next. A phase may load the model-invoked skills it names; stack skills and parallel workers are the exceptions.
|
||||
4. **Every worker gets its own worktree.** Never put two workers in one checkout, not even for a quick fix: concurrent checkouts clobber each other's branches.
|
||||
5. **The frontier comes from your merge record.** Never dispatch a ticket whose blockers haven't merged into the integration branch.
|
||||
6. **Read every worker report** before merging or dispatching more. Failures, skipped tests and follow-ups get handled or raised with the user, not buried.
|
||||
7. **Keep artifacts linked.** The spec links its tickets, tickets link their branches, the PR closes the spec and tickets, and ADRs link the decisions they record.
|
||||
8. **Only use skill names from this file or the `skill` tool's list.** If one is missing, say so rather than guessing.
|
||||
@@ -68,3 +68,15 @@ zero capability. Per-phase agents (spec-writer, ticket-planner, debugger, ...) r
|
||||
Matt's phases share one conversation context by design (grilling facts feed to-spec; retro mines the
|
||||
live session); isolating them would make the system worse. `triage` and `teach` agents rejected for
|
||||
the same reason (continuous human dialogue belongs in the primary conversation).
|
||||
|
||||
## D9 — 2026-10-14 — Two 2.5 agent-improvement suggestions reviewed and rejected
|
||||
|
||||
The 2.5 orchestration run (PASS, commit `cc9a0dd`) suggested: (1) adding a line to `pocock.md`
|
||||
about skill content looking truncated when a global `~/.agents/skills` install shadows the
|
||||
plugin-injected id; (2) adding a reminder that a non-ff ticket merge is normal (resume the worker).
|
||||
Both rejected: (1) is an artifact of one machine's pre-existing global install — on a clean machine
|
||||
the package content is authoritative, and adding environment-quirk prose costs context load in
|
||||
every session for zero general benefit (the model recovered unaided anyway); (2) is already the
|
||||
documented path in `pocock.md` step 5, which the run followed correctly — duplicating it would
|
||||
violate the no-duplicate-instructions validation criterion. Do not re-propose without evidence of
|
||||
a run failing because of their absence.
|
||||
+26
-16
@@ -1,15 +1,20 @@
|
||||
# Project status
|
||||
|
||||
Updated: 2026-10-14 (phase 1 implementation, ~90% done)
|
||||
Updated: 2026-10-14 (2.5 orchestration run PASS — quality gate + end-to-end run both green)
|
||||
|
||||
## Current phase
|
||||
|
||||
Phase 1 (plugin package) — implementation complete and runtime-verified locally. Remaining:
|
||||
first registry release (1.10) + Gitea secret provisioning, then Phase 2.
|
||||
Phase 1 done AND 2.5 done: plugin installs, loads in OpenCode v2.0.29, skills inject, package
|
||||
builds, `@haylan/opencode-pocock@0.1.0` published to the Gitea registry (release run 5684),
|
||||
install-from-registry verified, nightly workflow proven (dispatch run 5685: github.com reachable,
|
||||
no-change early exit), and a full manual orchestration run of the `pocock` orchestrator against a
|
||||
3-ticket fixture (omniroute/qwen3.8-27b) is **PASS** — all 3 tickets built by parallel workers,
|
||||
reviewed, fixed, merged, clean exit, no product bugs. Remaining: 2.7 (observe a week of
|
||||
nightlies).
|
||||
|
||||
## Done
|
||||
|
||||
- Phase 0 analysis complete: architecture, 38-skill classification matrix, decisions D1–D8,
|
||||
- Phase 0 analysis complete: architecture, 38-skill classification matrix, decisions D1–D9,
|
||||
verified V2 API surface (docs + `@opencode/plugin@2.0.29` typings + live runtime).
|
||||
- Package scaffolded: `@haylan/opencode-pocock` (name confirmed by owner), TS ESM, prettier,
|
||||
`node --test` on .ts, MIT + NOTICE attributions (Matt Pocock, Dex Horthy, mcdays94, fastcrw).
|
||||
@@ -38,21 +43,26 @@ first registry release (1.10) + Gitea secret provisioning, then Phase 2.
|
||||
|
||||
## Known gaps / risks
|
||||
|
||||
- 1.10 not done: package never published to the Gitea registry yet; npm-name plugin entry
|
||||
(resolving through `exports`) unverified — local directory entry verified instead.
|
||||
- `PACKAGE_TOKEN` Gitea secret must be provisioned by the repo admin before nightly can publish
|
||||
or commit back.
|
||||
- Nightly runner network access to github.com unverified (fallback: Gitea mirror of upstream).
|
||||
- 2.5 DONE (2026-10-14): full orchestration run PASS on omniroute/qwen3.8-27b — see
|
||||
docs/runtime-checks.md § "2.5 orchestration run". Noted env-only quirks: skill id collision
|
||||
resolves `code-review` to the user's global `~/.agents/skills` copy (documented, not a plugin
|
||||
bug); user's codebase-memory "graph-first" rule rejected one orchestrator `glob` (recovered via
|
||||
`find`). Local 27b took ~63 min; reviewer subagents stream output only on completion (looked
|
||||
stalled, was not). No product bugs found.
|
||||
- 2.7: nightlies need a week of green runs before "stable" is declared; first scheduled run
|
||||
2026-10-15 03:30 UTC.
|
||||
- Background subagents in V2 (env-gated in V1) not verified; orchestrator text works either way.
|
||||
- Windows-only smoke quirk: fixture temp dir deletion can lag (EPERM warning, harmless); CI is
|
||||
Linux.
|
||||
- Background subagents in V2 (env-gated in V1) not verified; orchestrator text works either way.
|
||||
- `request.body` overlays accepted but not sent by the V2 runner — agents avoid them.
|
||||
- Skill id collisions with pre-existing file-based installs resolve to the file copy (silent).
|
||||
|
||||
## Next steps (exact)
|
||||
|
||||
1. Run `npm run format`, `npm run check`, `npm test`, `npm run build`; commit workflows/smoke/docs.
|
||||
2. Push to origin; ask owner to add `PACKAGE_TOKEN` secret (write:package + write:repository).
|
||||
3. 1.10: `node scripts/release.ts` with SERVER_URL/REPOSITORY/SHA/TOKEN env (or dispatch a manual
|
||||
release workflow) → verify `plugins: ["@haylan/opencode-pocock"]` installs from the registry in
|
||||
a clean fixture; record in docs/runtime-checks.md.
|
||||
4. Phase 2 per TODO.md (2.2 guardrails already implemented in 1.4 — verify mapping note; 2.4–2.7).
|
||||
1. ~~2.5: manual orchestration run~~ DONE 2026-10-14 (PASS, see docs/runtime-checks.md).
|
||||
2. Watch nightly runs for a week (2.7); on upstream release (17 pending changesets), verify the
|
||||
full sync→generate→publish→commit-back cycle end-to-end.
|
||||
3. Then declare stable and announce; keep classification.json current when upstream promotes
|
||||
in-progress skills.
|
||||
4. (Optional, owner) Decide whether to fold the 2.5 agent-improvement suggestions (truncated-skill
|
||||
note, non-ff resume reminder) into agents/*.md — they are in the runtime-checks.md report.
|
||||
@@ -67,3 +67,17 @@ hidden, color?, steps?, request{settings,headers,body}, permissions[{action,reso
|
||||
injected content must have frontmatter stripped; serve prints its Basic-auth password.
|
||||
- Agent `steps` replaces `maxSteps`; `temperature`/`top_p` go under `request.body` (not yet sent by
|
||||
the runner — avoid).
|
||||
|
||||
## Agent skills
|
||||
|
||||
### Issue tracker
|
||||
|
||||
Issues live in this repo's Gitea Issues (`git.arthurerlich.de`), driven via the `tea` CLI; relations are body conventions (`Part of #`, `Blocked by:`) since Gitea has no sub-issues. See `docs/agents/issue-tracker.md`.
|
||||
|
||||
### Triage labels
|
||||
|
||||
Default five-role vocabulary (`needs-triage`, `needs-info`, `ready-for-agent`, `ready-for-human`, `wontfix`), label strings equal to role names. See `docs/agents/triage-labels.md`.
|
||||
|
||||
### Domain docs
|
||||
|
||||
Single-context: one `GLOSSARY.md` + `docs/adr/` at the repo root. See `docs/agents/domain.md`.
|
||||
@@ -40,9 +40,12 @@ upstream revision each release carries).
|
||||
Start OpenCode with the `pocock` agent selected and describe what you want to build:
|
||||
|
||||
```bash
|
||||
opencode --agent pocock
|
||||
opencode mini --agent pocock # interactive (v2.0.29: --agent is not a top-level flag)
|
||||
opencode run --agent pocock "build …" --auto # one-shot, autonomous
|
||||
```
|
||||
|
||||
In the default TUI (plain `opencode`), switch to `pocock` with the agent picker instead.
|
||||
|
||||
| Agent | Role |
|
||||
| ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `pocock` | Primary orchestrator. Routes with `ask-matt`, walks grill → spec → tickets → build → review → retro, proposes before each user-invoked step, runs `implement-spec` with one git worktree per ticket and parallel `pocock-worker` subagents. |
|
||||
|
||||
@@ -32,20 +32,28 @@ State: `.opencode/state/status.md`. Design: `docs/architecture.md`.
|
||||
- [x] 1.8 .gitea/workflows/: check.yml, nightly.yml, smoke.yml (dispatch); scripts/smoke.ts —
|
||||
PASS on v2.0.29 (plugin active, 31 skills, 16 hidden, agents + permissions decoded)
|
||||
- [x] 1.9 local runtime verification → docs/runtime-checks.md (findings folded into README/AGENTS)
|
||||
- [ ] 1.10 manual release 0.1.0 to Gitea registry; verify install-from-registry by package name
|
||||
- [ ] ask repo admin to add Gitea secret PACKAGE_TOKEN (write:package + write:repository)
|
||||
- [x] 1.10 manual release 0.1.0 to Gitea registry (dispatch run 5684, tag v0.1.0, package linked);
|
||||
install-from-registry verified in clean fixture (plugin active as package source, npx init
|
||||
works, anonymous registry reads) → docs/runtime-checks.md
|
||||
- [x] ask repo admin to add Gitea secret PACKAGE_TOKEN — done 2026-10-14; nightly dispatch run
|
||||
5685 proved runner github.com access + no-change early exit
|
||||
|
||||
## Phase 2 — conversion
|
||||
|
||||
- [x] 2.1 deep per-skill analysis → .opencode/state/classification.json + docs/skill-mapping.md
|
||||
(done in phase 0; generator must regenerate mapping doc from classification.json — keep in 1.3 scope)
|
||||
- [ ] 2.2 guardrails plugin hook (opt-in, tool.hook execute.before on shell) + tests
|
||||
- [ ] 2.3 pocock-reviewer: CONFIRMED by analysis (D8) — implement template + skill-permission scoping
|
||||
- [ ] 2.4 orchestrator V2 flow wiring (background-subagent status in V2? batch fallback; worktree
|
||||
permission guidance; slash UX for user-invoked skills)
|
||||
- [ ] 2.5 per-skill regression checks + manual orchestration smoke (token-spending, documented)
|
||||
- [ ] 2.6 README usage guide + finalize skill-mapping
|
||||
- [ ] 2.7 one week of green nightlies → declare stable
|
||||
- [x] 2.2 guardrails plugin hook (opt-in, tool.hook execute.before on shell) + tests — shipped in
|
||||
Phase 1.4 (src/guardrails.ts); pattern list faithful to upstream block-dangerous-git.sh
|
||||
- [x] 2.3 pocock-reviewer: CONFIRMED by analysis (D8) — implemented in 1.6 with read-only
|
||||
permissions (edit/subagent/webfetch deny, git-read shell allow-list, skill allow code-review)
|
||||
- [x] 2.4 orchestrator V2 flow wiring — done in 1.6: agent text covers background AND batch
|
||||
dispatch; slash UX + /tmp default documented in README from runtime findings
|
||||
- [x] 2.5 per-skill regression checks (drift suite exists; add manual token-spending orchestration
|
||||
run: fixture spec + 3 tickets like pocock-agents smoke) + record in docs/runtime-checks.md
|
||||
(DONE 2026-10-14: full PASS on omniroute/qwen3.8-27b, ~63 min, all 3 tickets + review + fixes,
|
||||
no product bugs — see docs/runtime-checks.md § "2.5 orchestration run")
|
||||
- [x] 2.6 README usage guide + finalize skill-mapping (matrix generated from classification.json)
|
||||
- [ ] 2.7 one week of green nightlies -> declare stable (BLOCKED on PACKAGE_TOKEN secret)
|
||||
|
||||
## Open questions
|
||||
|
||||
@@ -56,11 +64,20 @@ State: `.opencode/state/status.md`. Design: `docs/architecture.md`.
|
||||
- ~~Slash exposure for injected skills~~ RESOLVED: none (runtime check 2026-10-14); README
|
||||
documents file-based alternatives.
|
||||
- Package name/scope: CONFIRMED `@haylan/opencode-pocock` (owner, 2026-10-14).
|
||||
- Does nightly runner have network access to github.com for upstream fetch? (1.8 — fallback: mirror
|
||||
upstream to Gitea and sync from the mirror.) Verify on first nightly run.
|
||||
- Install-from-registry by package name (npm-name plugin entry resolving through `exports`) —
|
||||
verify at 1.10; local dir entry verified.
|
||||
- ~~Does nightly runner have network access to github.com for upstream fetch?~~ VERIFIED
|
||||
2026-10-14: nightly dispatch run 5685 success (clone + no-change early exit).
|
||||
- ~~Install-from-registry by package name~~ VERIFIED 2026-10-14 (see docs/runtime-checks.md).
|
||||
|
||||
## Done log
|
||||
|
||||
- 2026-10-14: phase-0 analysis docs written (AGENTS.md, state/, docs/architecture.md, TODO.md).
|
||||
- 2026-10-14: Phase 1 complete — 0.1.0 published to Gitea registry, install-from-registry verified,
|
||||
nightly dispatch proven (runs 5684/5685).
|
||||
- 2026-10-14: 2.5 orchestration run PASS on local omniroute/qwen3.8-27b (~63 min, 3/3 tickets,
|
||||
16/16 tests, worktree loop + resume-worker merge path + review exercised, zero permission
|
||||
escapes, zero product bugs) — commit cc9a0dd; suggestions reviewed → D9.
|
||||
- 2026-10-14: 2.5 manual orchestration run — `pocock` orchestrator drove a 3-ticket `greeting`
|
||||
fixture (omniroute/qwen3.8-27b, ~63 min) end-to-end: parallel workers on isolated worktrees,
|
||||
non-ff resume path exercised, two-axis code review, review-fix worker, all 16 tests green on
|
||||
`main`, worktrees cleaned, tickets marked done, `EXIT_CODE=0`. **PASS, no product bugs.**
|
||||
Recorded in docs/runtime-checks.md § "2.5 orchestration run".
|
||||
@@ -0,0 +1,51 @@
|
||||
# Domain Docs
|
||||
|
||||
How the engineering skills should consume this repo's domain documentation when exploring the codebase.
|
||||
|
||||
## Before exploring, read these
|
||||
|
||||
- **`GLOSSARY.md`** at the repo root, or
|
||||
- **`GLOSSARY-MAP.md`** at the repo root if it exists: it points at one `GLOSSARY.md` per context. Read each one relevant to the topic.
|
||||
- **`docs/adr/`**: read ADRs that touch the area you're about to work in. In multi-context repos, also check `src/<context>/docs/adr/` for context-scoped decisions.
|
||||
|
||||
If any of these files don't exist, **proceed silently**. Don't flag their absence; don't suggest creating them upfront. The `/domain-modeling` skill (reached via `/grill-with-docs` and `/improve-codebase-architecture`) creates them lazily when terms or decisions actually get resolved.
|
||||
|
||||
## File structure
|
||||
|
||||
Single-context repo (most repos):
|
||||
|
||||
```
|
||||
/
|
||||
├── GLOSSARY.md
|
||||
├── docs/adr/
|
||||
│ ├── 0001-event-sourced-orders.md
|
||||
│ └── 0002-postgres-for-write-model.md
|
||||
└── src/
|
||||
```
|
||||
|
||||
Multi-context repo (presence of `GLOSSARY-MAP.md` at the root):
|
||||
|
||||
```
|
||||
/
|
||||
├── GLOSSARY-MAP.md
|
||||
├── docs/adr/ ← system-wide decisions
|
||||
└── src/
|
||||
├── ordering/
|
||||
│ ├── GLOSSARY.md
|
||||
│ └── docs/adr/ ← context-specific decisions
|
||||
└── billing/
|
||||
├── GLOSSARY.md
|
||||
└── docs/adr/
|
||||
```
|
||||
|
||||
## Use the glossary's vocabulary
|
||||
|
||||
When your output names a domain concept (in an issue title, a refactor proposal, a hypothesis, a test name), use the term as defined in `GLOSSARY.md`. Don't drift to synonyms the glossary explicitly avoids.
|
||||
|
||||
If the concept you need isn't in the glossary yet, that's a signal: either you're inventing language the project doesn't use (reconsider) or there's a real gap (note it for `/domain-modeling`).
|
||||
|
||||
## Flag ADR conflicts
|
||||
|
||||
If your output contradicts an existing ADR, surface it explicitly rather than silently overriding:
|
||||
|
||||
> _Contradicts ADR-0007 (event-sourced orders), but worth reopening because…_
|
||||
@@ -0,0 +1,62 @@
|
||||
# Issue tracker: Gitea (via tea CLI)
|
||||
|
||||
Issues and specs for this repo live as Gitea issues on
|
||||
`git.arthurerlich.de/haylan/mattpocock-skills-opencode`. Use the `tea` CLI for all operations;
|
||||
the `gitea-tea` skill has command recipes. `tea` infers the repo from `git remote` inside this clone.
|
||||
|
||||
**One-time human step (not done yet):** `tea logins add` for `https://git.arthurerlich.de`
|
||||
(token from the web UI: Settings → Applications). Until then, tracker operations fail.
|
||||
|
||||
## Conventions
|
||||
|
||||
- **Create an issue**: `tea issues create -t "<title>" --description-file -` (stdin for
|
||||
multi-line bodies). Labels: `-L needs-triage,bug` (comma-separated; must exist — see Labels).
|
||||
- **Read an issue**: `tea issues <number> --comments`.
|
||||
- **List issues**: `tea issues list --state open -f index,title,state,labels,assignees`
|
||||
(add `body,comments` to `--fields` when a skill needs full content).
|
||||
- **Comment**: `tea comments <number> "<body>"`.
|
||||
- **Apply / remove labels**: `tea issues edit <number> -L "<label>"` / `--remove-labels "<label>"`.
|
||||
- **Assign**: `tea issues edit <number> -a <username>`.
|
||||
- **Close**: comment the reason, then `tea issues close <number>`.
|
||||
|
||||
Gitea has **no sub-issues and no native blocked-by links**. Relations are body conventions:
|
||||
|
||||
- **Parent/child**: `Part of #<parent>` as the first line of the child body, plus a task list of
|
||||
children in the parent body.
|
||||
- **Blocking**: `Blocked by: #<n>, #<n>` near the top of the child body. A ticket is unblocked
|
||||
when every listed blocker is closed.
|
||||
|
||||
### Labels
|
||||
|
||||
The five triage labels plus `wayfinder:map` and `wayfinder:research|prototype|grilling|task` must
|
||||
exist before first use. After login, create missing ones with `tea labels create`; check with
|
||||
`tea labels list`.
|
||||
|
||||
## Pull requests as a triage surface
|
||||
|
||||
**PRs as a request surface: no.** _(Set to `yes` if this repo treats external PRs as feature
|
||||
requests; `triage` reads this flag.)_ Gitea shares one number space across issues and PRs: resolve
|
||||
a bare `#42` with `tea issues 42`, falling back to `tea prs 42`.
|
||||
|
||||
## When a skill says "publish to the issue tracker"
|
||||
|
||||
Create a Gitea issue as above.
|
||||
|
||||
## When a skill says "fetch the relevant ticket"
|
||||
|
||||
Read it with `tea issues <number> --comments`.
|
||||
|
||||
## Wayfinding operations
|
||||
|
||||
Used by `wayfinder`. The **map** is a single issue with **child** issues as tickets.
|
||||
|
||||
- **Map**: issue labelled `wayfinder:map`, holding the Notes / Decisions-so-far / Fog body.
|
||||
- **Child ticket**: `Part of #<map>` first body line, listed in the map's task list. Labels:
|
||||
`wayfinder:<type>` (`research`/`prototype`/`grilling`/`task`). Once claimed, assigned to the
|
||||
driving dev.
|
||||
- **Blocking**: `Blocked by: #<n>` line (no native equivalent).
|
||||
- **Frontier query**: list the map's open children (`tea issues list --state open`), drop any
|
||||
whose `Blocked by:` names an open issue or that has an assignee; first in map order wins.
|
||||
- **Claim**: `tea issues edit <n> -a <username>`, the session's first write.
|
||||
- **Resolve**: `tea comments <n> "<answer>"`, then `tea issues close <n>`, then append a context
|
||||
pointer to the map's Decisions-so-far (edit the map body).
|
||||
@@ -0,0 +1,15 @@
|
||||
# Triage Labels
|
||||
|
||||
The skills speak in terms of five canonical triage roles. This file maps those roles to the actual label strings used in this repo's issue tracker.
|
||||
|
||||
| Label in mattpocock/skills | Label in our tracker | Meaning |
|
||||
| -------------------------- | -------------------- | ---------------------------------------- |
|
||||
| `needs-triage` | `needs-triage` | Maintainer needs to evaluate this issue |
|
||||
| `needs-info` | `needs-info` | Waiting on reporter for more information |
|
||||
| `ready-for-agent` | `ready-for-agent` | Fully specified, ready for an AFK agent |
|
||||
| `ready-for-human` | `ready-for-human` | Requires human implementation |
|
||||
| `wontfix` | `wontfix` | Will not be actioned |
|
||||
|
||||
When a skill mentions a role (e.g. "apply the AFK-ready triage label"), use the corresponding label string from this table.
|
||||
|
||||
Edit the "Label in our tracker" column to match whatever vocabulary you actually use.
|
||||
@@ -6,6 +6,17 @@ password printed on stdout) in a temp fixture and asserts against the HTTP API.
|
||||
|
||||
## Verified
|
||||
|
||||
- **Registry install by package name (1.10, 2026-10-14)**: `@haylan/opencode-pocock@0.1.0`
|
||||
published to the Gitea npm registry by the dispatched `release` workflow (run 5684, success;
|
||||
tag `v0.1.0` created, package linked to repo). Anonymous registry reads work (HTTP 200 without
|
||||
auth). A clean fixture with `"plugins": ["@haylan/opencode-pocock"]` + scope registry in
|
||||
`~/.npmrc` loads the plugin: `/api/plugin` shows
|
||||
`source {type:"package", target:"@haylan/opencode-pocock", version:"0.1.0"}`,
|
||||
`state.status "active"`; skills inject from the bun cache path
|
||||
(`~/.cache/opencode/npm/@haylan/opencode-pocock@latest/.../skills/...`); `npx -y
|
||||
@haylan/opencode-pocock init` installs the three agents (modes decode correctly).
|
||||
Id collisions with a pre-existing global `~/.agents/skills` Matt Pocock install resolve to the
|
||||
file-based copy (expected; a clean machine gets all 31 from the package).
|
||||
- **Plugin loads and activates** from a local directory entry (`plugins: ["<abs path>/dist"]`);
|
||||
`GET /api/plugin` shows `haylan.pocock` with `state.status: "active"`.
|
||||
- A **file** entry (`file://.../dist/index.js`) is IGNORED — local plugin entries must be
|
||||
@@ -44,3 +55,70 @@ password printed on stdout) in a temp fixture and asserts against the HTTP API.
|
||||
harmless, retried on next run.
|
||||
- The user's global `~/.agents/skills` already contains most Matt Pocock skills — smoke assertions
|
||||
are written to tolerate id collisions (presence + flags, not source path).
|
||||
|
||||
## 2.5 orchestration run (2026-10-14, omniroute/qwen3.8-27b)
|
||||
|
||||
**Result: PASS** — full `implement-spec` flow, all 3 tickets, review, fixes, clean exit.
|
||||
|
||||
Fixture: fresh clone of the pocock-agents `greeting` reference (AGENTS.md `## Agent skills` block →
|
||||
`docs/agents/issue-tracker.md` local tracker, GLOSSARY.md, `.scratch/greeting/spec.md` + 3 tickets —
|
||||
01+02 independent, 03 blocked by 01+02, `src/greeting.js` + node:test, no remote, no deps). Agents
|
||||
copied to `.opencode/agents/`; `opencode.json` =
|
||||
`{"$schema":…,"plugins":["G:/_DEV/repos/mattpocock-skills-opencode/dist"],"model":"omniroute/qwen3.8-27b"}`
|
||||
(`model` is a valid top-level v2 config key — confirmed against `opencode.ai/config.json`).
|
||||
|
||||
Command (cwd = fixture, background, `> run.log 2>&1`):
|
||||
|
||||
```
|
||||
opencode run --agent pocock --auto "Implement the spec in .scratch/greeting/spec.md using
|
||||
implement-spec: build all three tickets with parallel workers, review, and finish. The tracker is
|
||||
local markdown (see docs/agents/issue-tracker.md). Do not ask me anything else; proceed through the
|
||||
whole flow autonomously."
|
||||
```
|
||||
|
||||
Duration: ~63 min (11:00:26Z → 12:03:47Z) on the local 27b model. `EXIT_CODE=0`.
|
||||
|
||||
| # | Check | Result | Evidence |
|
||||
| --- | -------------------------------------------------- | ------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| 1 | Integration + ticket branches exist and are merged | PASS | `spec/greeting` is an ancestor of `main`; `git merge-base --is-ancestor` confirms 01, 02, 03 all in `spec/greeting`. 01 + 03 ff-merged; 02 diverged after 01 landed → resolved via merge commit `0308c30 "Merge branch 'spec/greeting' into ticket/greeting/02"`, exactly the agent's documented resume-worker path. |
|
||||
| 2 | Worktree dir used + cleaned | PASS | All worktrees under `/tmp/pocock-workers/pocock-25-fixture/greeting/` (`$WT` default). `git worktree list` shows only the main checkout after the run; orchestrator logged `git worktree remove --force … tickets/{01,02,03,review-fixes}` → `CLEANED`. Leftover empty `notes/` + `tickets/` dirs (no worktree admin entries) — harmless. |
|
||||
| 3 | Tests pass on integration branch | PASS | Fresh worktree of `spec/greeting`: `npm test` = 16/16 pass, 0 fail (also 16/16 at every in-run merge point). |
|
||||
| 4 | Flow evidence in run.log | PASS | `→ Skill "ask-matt"`, `→ Skill "implement-spec"`, `→ Skill "code-review"`; 4 `pocock-worker` dispatches (ticket 01/02 parallel, "Worker 02: merge integration tip" resume, ticket 03) + 4 `pocock-reviewer` dispatches (Spec axis, Standards axis, + compact re-runs); TDD red→green commit pairs per ticket (`test(…): red…` → `feat(…)`); no `✗` permission denials — zero worker escape attempts (no push/stash/out-of-allow-list skill). Only failure in the whole log: one `✗ Glob` hit by the user's global codebase-memory "graph-first" rule (environment quirk, below). |
|
||||
| 5 | Model actually served | PASS | Every turn banner: `> pocock · qwen3.8-27b` — top-level `"model"` in opencode.json took effect for orchestrator and all nested subagents. |
|
||||
| 6 | Ticket statuses updated | PASS | All three `issues/NN-*.md` now read `Status: done` with a `## Comments` note naming the branch — per the local-tracker convention in `docs/agents/issue-tracker.md`. |
|
||||
|
||||
Flow detail worth keeping: 02's divergence was handled by resuming worker 02 to merge the new
|
||||
integration tip (agent text: "It knows its own change best, so it's the merger") — the non-ff path
|
||||
worked, not just the happy ff path. Review produced 2 actionable Standards findings + 1 real Spec gap
|
||||
(farewell error-message criterion untested); orchestrator dispatched a `review-fixes` worker for them
|
||||
and merged back to `main`. `spec/greeting` then ff-merged to `main` (no remote → delivered on
|
||||
default branch, per agent text).
|
||||
|
||||
Product bugs: **none**. Everything above is agent/plugin behaving per its documented design.
|
||||
|
||||
Findings / model-weakness notes (not product bugs):
|
||||
|
||||
- **Skill-id collision resolved to the user's global copy.** When the orchestrator loaded
|
||||
`code-review`, the content came from `~/.agents/skills/code-review/SKILL.md` (pre-existing global
|
||||
Matt Pocock install), not the plugin-injected copy — same collision documented in the 1.10 note.
|
||||
The model then said the skill text was "truncated" and hunted for the SKILL.md on disk (found the
|
||||
global one). Our plugin ships the full body (`code-review` body = 6177 chars, no slicing in
|
||||
`src/index.ts`), so this is the collision + local-model behaviour, not truncation by the plugin.
|
||||
- **`graph-first` rule collision.** The user's global codebase-memory-mcp injects a rule that forces a
|
||||
graph query before any `glob`. One orchestrator `glob` was rejected with that error; the model
|
||||
recovered by using `find`. Not our product; note for anyone running this with codebase-memory
|
||||
installed.
|
||||
- **Local 27b is slower than capable.** The whole run took ~63 min; reviewer subagents were CPU-busy
|
||||
for ~14 min with no log growth (subagent output streams on completion, not incrementally — expected,
|
||||
not a stall). No stalls requiring intervention; no permission denials; the only judgment shortcuts
|
||||
were self-declared in the final summary (skipped a second post-fix review pass; left
|
||||
spec-prescribed module duplication alone).
|
||||
|
||||
Suggested agent improvements (NOT applied — for the owner):
|
||||
|
||||
- `pocock.md`: consider noting that when a skill's content looks truncated, the model may re-read the
|
||||
SKILL.md from disk; if the user also has a global Matt Pocock install, the id resolves to the file
|
||||
copy — worth a one-line "skills may resolve to a global copy; content is authoritative either way".
|
||||
- `pocock-worker.md`/`pocock.md`: the non-ff resume path works but is model-dependent; a short
|
||||
reminder that "a ticket that can't ff-merge is normal when a parallel ticket merged first — resume
|
||||
its worker" could make the 27b class of model take the documented path more reliably.
|
||||
Generated
+79
@@ -16,6 +16,8 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^26.6.4",
|
||||
"husky": "^9.1.7",
|
||||
"lint-staged": "^17.6.0",
|
||||
"prettier": "^3.9.9",
|
||||
"typescript": "^7.0.2"
|
||||
},
|
||||
@@ -2493,6 +2495,22 @@
|
||||
"node": ">= 14"
|
||||
}
|
||||
},
|
||||
"node_modules/husky": {
|
||||
"version": "9.1.7",
|
||||
"resolved": "https://registry.npmjs.org/husky/-/husky-9.1.7.tgz",
|
||||
"integrity": "sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"husky": "bin.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/typicode"
|
||||
}
|
||||
},
|
||||
"node_modules/iconv-lite": {
|
||||
"version": "0.7.3",
|
||||
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.3.tgz",
|
||||
@@ -2708,6 +2726,30 @@
|
||||
"safe-buffer": "^5.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/lint-staged": {
|
||||
"version": "17.6.0",
|
||||
"resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-17.6.0.tgz",
|
||||
"integrity": "sha512-nOhBfYkZEwkFtNzD5pK9s9LkcWoxJ+whLzEnhqi9nl7zTB5n7tg8+9iYgMGx2Wm3VlLu8cbNj0RACzY+nWi5iQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"picomatch": "^4.0.7",
|
||||
"string-argv": "^0.3.2",
|
||||
"tinyexec": "^1.3.1"
|
||||
},
|
||||
"bin": {
|
||||
"lint-staged": "bin/lint-staged.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=22.22.1"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/lint-staged"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"yaml": "^2.9.1"
|
||||
}
|
||||
},
|
||||
"node_modules/lru-cache": {
|
||||
"version": "11.5.3",
|
||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.3.tgz",
|
||||
@@ -3589,6 +3631,16 @@
|
||||
"node": "^20.17.0 || >=22.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/string-argv": {
|
||||
"version": "0.3.2",
|
||||
"resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.2.tgz",
|
||||
"integrity": "sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.6.19"
|
||||
}
|
||||
},
|
||||
"node_modules/string-width": {
|
||||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz",
|
||||
@@ -3701,6 +3753,16 @@
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/tinyexec": {
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.3.1.tgz",
|
||||
"integrity": "sha512-GCvB3aoys96IuDFBMcTB46JOR6mdMtAToqwiW8JlWhsoh1mhHi/xn9ss/Dg7N555GiJyEt2qzoG/NHCwM6h1EA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/tinyglobby": {
|
||||
"version": "0.2.17",
|
||||
"resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz",
|
||||
@@ -3992,6 +4054,23 @@
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/yaml": {
|
||||
"version": "2.9.1",
|
||||
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.9.1.tgz",
|
||||
"integrity": "sha512-3NxN8+78OdzbT7C/WjGsyfPAtJaN3FNDsWxv7Y7mcDsT/oOmgW8BpyQQFFBnvZE3j9Y2Sdz1ULFLezL7Eb2yFw==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"optional": true,
|
||||
"bin": {
|
||||
"yaml": "bin.mjs"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 14.6"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/eemeli"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+4
-1
@@ -29,7 +29,8 @@
|
||||
"test": "node --test",
|
||||
"sync": "node scripts/sync-upstream.ts",
|
||||
"generate": "node scripts/generate.ts",
|
||||
"smoke": "node scripts/smoke.ts"
|
||||
"smoke": "node scripts/smoke.ts",
|
||||
"prepare": "husky"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -41,6 +42,8 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^26.6.4",
|
||||
"husky": "^9.1.7",
|
||||
"lint-staged": "^17.6.0",
|
||||
"prettier": "^3.9.9",
|
||||
"typescript": "^7.0.2"
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user