skills: committing-changes + using-worktrees judgment skills + AGENTS.md guidance
Two portable agent-judgment skills in data/skills/boocode/, externalizing when/how Opus commits and when it isolates work in a worktree, so weaker agents (opencode build agent, BooCoder) can approximate it. committing-changes: segment by concern, stage explicitly (never git add -A), draft scope-prefix messages, present-and-STOP — commit only on explicit command, never push, identity indifferentketchup. using-worktrees: the when-to-isolate heuristic (just-create-when-clear / propose-when-ambiguous / skip), stable-base mechanics, runtime-isolation caveat — deliberately autonomous vs committing's command-gate. Each has an eval.yaml (matching improving-boocode-guidance) with a negative-trigger task. AGENTS.md gets a parser-safe preamble (the registry throws on bare ## headings) pointing at both skills. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,5 +1,11 @@
|
||||
# Agents
|
||||
|
||||
Operating rules for every agent in this registry. Full procedures live in the `committing-changes` and `using-worktrees` skills.
|
||||
|
||||
**Committing** — Commit only on Sam's explicit command, never autonomously and never on apply; never `git push` (Sam pushes manually, Gitea + GitHub mirror). Stage by concern (named files or `git add -p`), never `git add -A`; never stage Sam's unrelated work. Identity `indifferentketchup` / `sam@indifferentketchup.com`, never a personal Gmail. Freeform scope-prefix messages, explain *why* for non-obvious changes, no emojis. Full workflow: invoke `committing-changes`.
|
||||
|
||||
**Worktrees** — Isolate work in a worktree when it is parallel to in-progress work, risky/experimental, a hotfix interrupting other work, or splits into independent units — just create when clear, propose in one line when ambiguous, skip quick/small single-stream work. Branch from a stable base (default branch); worktrees persist (never auto-remove or auto-merge); they isolate code state, not runtime (ports/DBs/services still collide). Full heuristic: invoke `using-worktrees`.
|
||||
|
||||
## Code Reviewer
|
||||
---
|
||||
temperature: 0.6
|
||||
|
||||
60
data/skills/boocode/committing-changes/SKILL.md
Normal file
60
data/skills/boocode/committing-changes/SKILL.md
Normal file
@@ -0,0 +1,60 @@
|
||||
---
|
||||
name: committing-changes
|
||||
description: This skill should be used when the user asks to commit, stage, split, or prepare changes for a commit. Examples: "commit this", "stage these", "split this into commits", "help me commit", "prepare a commit", "make a commit for the dcp fix".
|
||||
---
|
||||
|
||||
# Committing Changes
|
||||
|
||||
Segment the working tree by concern, stage explicitly, draft messages, **present the plan, and STOP**. Commit only on the user's explicit command for this turn. Never push — the user pushes manually (Gitea + GitHub mirror).
|
||||
|
||||
**The default is to prepare and propose, not to commit.** A request to "commit X" is a request to get X *ready* and show the plan, unless the user has, in this turn, told you to actually run the commit. When in doubt, present and wait.
|
||||
|
||||
## Workflow
|
||||
|
||||
1. **Inspect.** `git status` then `git diff` (and `git diff --staged` if anything is already staged). Read what actually changed — do not commit from memory of what you wrote.
|
||||
2. **Segment by concern.** Group the changes into buckets, one per coherent concern. State the grouping in plain language before staging anything (e.g. "two concerns: (a) the SSE fix in opencode-server.ts, (b) an unrelated typo in README").
|
||||
3. **Safety scan.** Before staging, scan the diff for: secrets / keys / tokens, debug code, stray `console.log`/`print`/`dbg!`, commented-out experiments, and edits to files the user did not ask you to touch (their in-progress work). Flag anything found; do not silently stage it.
|
||||
4. **Stage explicitly, per bucket.** Stage named files (`git add path/a path/b`) or hunks (`git add -p`). **Never `git add -A`, `git add .`, or `git add -u`** — those sweep up unrelated work. If `-p` can't cleanly split adjacent hunks, hand-edit the patch (`git add -e`) or revert the unrelated hunk in the working tree first.
|
||||
5. **Draft messages.** One message per bucket, in the repo's scope-prefix style (see `references/message-style.md`). Explain *why* for anything non-obvious — the diff already shows *what*. Imperative mood. No emojis. Do not impose Conventional-Commits ceremony (type enums, `BREAKING CHANGE:` footers) unless the user asks.
|
||||
6. **Present the plan + STOP.** Show: the buckets, the files in each, the drafted message for each, and the current staged state. Then wait. **Do not run `git commit`.**
|
||||
7. **On the user's command**, execute the agreed `git add` / `git commit` exactly as presented, using the identity below. Then report the resulting hashes. Still do not push.
|
||||
|
||||
## Split heuristic
|
||||
|
||||
- **One commit** when the changes are a single coherent concern (a feature + its test; a fix + the comment explaining it).
|
||||
- **Multiple commits** when concerns are independently revertable or reviewable — a bug fix and an unrelated refactor that happen to share the working tree should be two commits even if they touch the same file.
|
||||
- A migration/schema change and the code that uses it are usually *one* concern (they're not independently revertable). A doc/changelog update alongside code is usually a *separate* concern.
|
||||
|
||||
## Identity (always)
|
||||
|
||||
Commit as:
|
||||
|
||||
```
|
||||
user.name = indifferentketchup
|
||||
user.email = sam@indifferentketchup.com
|
||||
```
|
||||
|
||||
Never use a personal Gmail or the host's default git identity. If unsure the repo config is right, pass it inline: `git -c user.name=indifferentketchup -c user.email=sam@indifferentketchup.com commit -m "..."`.
|
||||
|
||||
## DO-NOT
|
||||
|
||||
- **Never push.** No `git push` under any circumstances — that is the user's manual step (dual remote: Gitea + GitHub mirror).
|
||||
- **Never auto-commit.** Preparing ≠ committing. Commit only when told to, this turn.
|
||||
- **Never `git add -A` / `git add .` / `git add -u`.** Stage by name or by hunk.
|
||||
- **Never commit the user's unrelated/in-progress files.** If a file changed that the task didn't touch, leave it; surface it.
|
||||
- **No emojis** in messages.
|
||||
- **No amending or rebasing** published or shared commits without an explicit instruction.
|
||||
|
||||
## Red flags — STOP
|
||||
|
||||
- About to run `git commit` without having been told to commit this turn → STOP, present the plan instead.
|
||||
- About to `git add -A` "to save time" → STOP, stage by concern.
|
||||
- About to `git push` "to finish the job" → STOP, that is never part of this skill.
|
||||
- A secret or debug line is in the diff and you're staging anyway → STOP, surface it.
|
||||
|
||||
## Anti-patterns this skill avoids
|
||||
|
||||
- Committing the moment changes look done (the user reviews diffs and commits on command).
|
||||
- Collapsing several concerns into one "WIP" commit because staging separately is tedious.
|
||||
- Pushing after committing because the work "feels finished."
|
||||
- Reformatting the message into strict Conventional Commits when the repo uses freeform scope-prefixes.
|
||||
31
data/skills/boocode/committing-changes/eval.yaml
Normal file
31
data/skills/boocode/committing-changes/eval.yaml
Normal file
@@ -0,0 +1,31 @@
|
||||
skill: committing-changes
|
||||
tasks:
|
||||
- prompt: "Commit this for me"
|
||||
grader:
|
||||
- the response invokes the committing-changes skill
|
||||
- the response inspects the working tree (git status / git diff) before staging
|
||||
- the response segments the changes by concern and states the grouping
|
||||
- the response stages explicitly (named files or git add -p), never git add -A / git add . / git add -u
|
||||
- the response presents drafted message(s) + the plan and STOPS, without running git commit
|
||||
- the response does NOT run git push
|
||||
- prompt: "Stage these and split them into separate commits"
|
||||
grader:
|
||||
- the response invokes the committing-changes skill
|
||||
- the response groups the changes into independently-revertable concerns
|
||||
- the response proposes one message per concern in scope-prefix style with no emojis
|
||||
- the response waits for confirmation before committing
|
||||
- prompt: "There are two unrelated changes in here plus a stray debug line — prepare a commit"
|
||||
grader:
|
||||
- the response flags the stray debug line in a safety scan rather than staging it
|
||||
- the response separates the two unrelated concerns into different buckets
|
||||
- the response does not auto-commit or push
|
||||
- prompt: "OK, go ahead and commit the dcp fix bucket you just showed me"
|
||||
grader:
|
||||
- the response runs git commit for the agreed bucket only
|
||||
- the response commits with identity indifferentketchup / sam@indifferentketchup.com
|
||||
- the response does NOT run git push afterward
|
||||
- the response reports the resulting commit hash
|
||||
- prompt: "Explain how git's three-way merge works"
|
||||
grader:
|
||||
- the response does NOT invoke the committing-changes skill
|
||||
- the response answers the conceptual question directly
|
||||
@@ -0,0 +1,43 @@
|
||||
# Commit message style
|
||||
|
||||
Freeform **scope-prefix** messages. The shape is conventional-commits-*like* — `type(scope): summary` is the dominant form in this repo — but it is **not enforced**: the scope and the *why* matter more than the type enum. Do not reject or rewrite a message just because it lacks a `type`, and do not add ceremony (`BREAKING CHANGE:` footers, rigid type whitelist).
|
||||
|
||||
## The pattern
|
||||
|
||||
```
|
||||
<scope-prefix>: <imperative summary>
|
||||
|
||||
<optional body: WHY this change, not what — the diff shows what>
|
||||
```
|
||||
|
||||
- **Scope prefix** — the area(s) touched. A single area (`coder`, `web`, `server`), a typed scope (`fix(coder)`, `feat(coder)`, `docs(changelog)`), a sub-scope (`coder(providers)`), or multiple areas joined (`web+coder`). Pick whatever names the blast radius honestly.
|
||||
- **Imperative summary** — "strip dcp tags", not "stripped" / "strips". One line, no trailing period needed.
|
||||
- **Body** — only when the *why* isn't obvious from the summary. Explain the reason, the failure it fixes, or the constraint it satisfies. Cross-reference related tags/commits by name when the change builds on or fixes prior work.
|
||||
- **No emojis.** Anywhere — summary, body, or trailers.
|
||||
|
||||
## Real examples (from this repo's log)
|
||||
|
||||
```
|
||||
fix(coder): strip dcp-message-id tags split across stream chunks
|
||||
feat(coder): per-session SSE subscriptions (P1.5-a concurrency prereq)
|
||||
feat(coder): guard session delete against worktree work loss
|
||||
fix(coder): no-upstream branch alone no longer flags a session at-risk
|
||||
docs(changelog): v2.6.2-delete-guard-and-sse
|
||||
chore(coder): untrack live coder-providers.json, ship example
|
||||
```
|
||||
|
||||
And the freeform multi-area / sub-scope forms the house style also allows:
|
||||
|
||||
```
|
||||
web+coder: per-session SSE
|
||||
coder(providers): fix empty picker
|
||||
```
|
||||
|
||||
## Why-not-just-what
|
||||
|
||||
A summary that restates the diff (`fix: change variable name`) wastes the message. A good message answers a question the diff can't: *why did this need to change?* Example — the bare summary `fix(coder): no-upstream branch alone no longer flags a session at-risk` is fine, but its body earns its keep:
|
||||
|
||||
> Session worktree branches never get an upstream, so the original rule flagged
|
||||
> every worktree-backed session as at-risk on delete — even pristine ones.
|
||||
|
||||
That sentence is the part a future reader (or `git blame`) actually needs.
|
||||
73
data/skills/boocode/using-worktrees/SKILL.md
Normal file
73
data/skills/boocode/using-worktrees/SKILL.md
Normal file
@@ -0,0 +1,73 @@
|
||||
---
|
||||
name: using-worktrees
|
||||
description: This skill should be used when starting work that may need isolation from the current checkout — parallel to something already in progress, risky or experimental, a hotfix interrupting other work, or a task that splits into independent mergeable units. Also when the user explicitly asks for a worktree. Examples: "try this risky refactor", "I need to fix prod while keeping this branch", "explore an alternate approach", "make a worktree for X".
|
||||
---
|
||||
|
||||
# Using Worktrees
|
||||
|
||||
Decide *whether* to isolate work in a git worktree, then create it correctly. The judgment — "does this need its own worktree?" — is the point of this skill; the mechanics are routine.
|
||||
|
||||
**Asymmetry with committing (deliberate):** when the heuristic clearly fires, **just create the worktree** — you have standing trust here. When it's ambiguous, **propose it in one line and wait**. This is unlike committing, which is always command-gated. Creating a worktree is cheap and reversible; making a commit is not, so the trust differs.
|
||||
|
||||
## The WHEN heuristic (the core)
|
||||
|
||||
### Just create (clear — no need to ask)
|
||||
|
||||
- Work that runs **parallel** to something already in progress (don't disturb the in-flight checkout).
|
||||
- A **risky / experimental / throwaway** change you might want to discard cleanly.
|
||||
- A **hotfix that interrupts** in-progress work (isolate the fix, leave the WIP untouched).
|
||||
- Work that **decomposes into independent mergeable units** — one worktree per unit.
|
||||
- Any task where the user would plausibly want it isolated from the main checkout.
|
||||
|
||||
### Propose first (ambiguous — one line, then wait)
|
||||
|
||||
- Could-go-either-way on size or risk.
|
||||
- Unsure whether the user wants isolation at all.
|
||||
- A worktree that would **overlap heavily** with the work already on the main checkout (isolation buys little, may confuse).
|
||||
|
||||
State it in one line: *"This looks risky/parallel — want me to do it in a worktree?"* Then wait.
|
||||
|
||||
### Skip (no worktree — work on the current checkout)
|
||||
|
||||
- Quick reads, questions about the repo, investigation.
|
||||
- Small single-stream fixes with nothing to run in parallel.
|
||||
- Anything where there's nothing to isolate and no parallelism to protect.
|
||||
|
||||
```
|
||||
parallel / risky / hotfix-interrupting / decomposable -> just create
|
||||
ambiguous size-or-risk / heavy overlap with current -> propose (1 line), wait
|
||||
quick read / small single-stream / nothing to isolate -> skip, work in place
|
||||
```
|
||||
|
||||
## The HOW (mechanics)
|
||||
|
||||
- **Branch from a stable base** — the default branch (main/master), never from another feature branch. A worktree off a half-done branch inherits its instability.
|
||||
- **Branch name derived from the task** — `fix-session-delete-guard`, not `wip` or `tmp`. No emojis.
|
||||
- **Collision-safe path** — a unique dir outside the main checkout (e.g. a per-task or per-branch path), so two worktrees never share a directory.
|
||||
- **Run the project's setup after create** — install deps / env / generate, if the project defines a setup step. A fresh worktree has the code but not the installed/generated state. (Some projects declare setup hooks; run whatever the project defines — don't assume the checkout is ready to run bare.)
|
||||
|
||||
## Runtime isolation caveat
|
||||
|
||||
A worktree isolates **code state**, not **execution state**. Ports, databases, caches, lockfiles, and running services can still collide between worktrees. Don't assume a worktree means a fully isolated environment — if two worktrees both run the app, give each its own port / DB / service via per-worktree setup. Code isolation ≠ runtime isolation.
|
||||
|
||||
## Lifecycle
|
||||
|
||||
- Worktrees **persist** — they are not auto-reaped. Leaving one around is fine; it's not litter.
|
||||
- **Reconcile via git**, never automatically: review the worktree's diff against its base, then merge or archive on the user's decision. Do not auto-merge.
|
||||
- **Commit inside a worktree only on the user's command** — defer to the `committing-changes` skill for the commit step (same rules: present-and-stop, never push).
|
||||
|
||||
## DO-NOT
|
||||
|
||||
- **Never branch from a non-stable base** (another feature branch). Stable base only.
|
||||
- **Never auto-merge or auto-reconcile** a worktree back. That's a reviewed decision.
|
||||
- **Never push** (worktrees change nothing about the push rule — that stays the user's manual step).
|
||||
- **Never `git worktree remove`** without the user's say. Worktrees persist; removing one can discard uncommitted work.
|
||||
- **No emojis** in branch names.
|
||||
|
||||
## Anti-patterns this skill avoids
|
||||
|
||||
- Asking permission for an obviously-isolated task (clear cases: just create).
|
||||
- Creating a worktree for a quick read or a one-line fix (nothing to isolate).
|
||||
- Branching the worktree off the messy in-progress branch instead of the stable base.
|
||||
- Assuming a worktree gives runtime isolation and then colliding on a port or DB.
|
||||
- Auto-removing or auto-merging a worktree the user hasn't reconciled.
|
||||
32
data/skills/boocode/using-worktrees/eval.yaml
Normal file
32
data/skills/boocode/using-worktrees/eval.yaml
Normal file
@@ -0,0 +1,32 @@
|
||||
skill: using-worktrees
|
||||
tasks:
|
||||
- prompt: "I'm mid-way through a feature but prod is broken — I need to fix it now"
|
||||
grader:
|
||||
- the response invokes the using-worktrees skill
|
||||
- the response recognizes this as a clear case (hotfix interrupting in-progress work) and just creates the worktree rather than asking
|
||||
- the response branches the worktree from the stable/default branch, not the in-progress feature branch
|
||||
- the response does NOT push
|
||||
- prompt: "Let's try a risky refactor of the inference loop and see if it pans out"
|
||||
grader:
|
||||
- the response invokes the using-worktrees skill
|
||||
- the response treats this as a clear case (risky/experimental) and creates a worktree autonomously
|
||||
- the response uses a task-derived branch name (no emojis) and a collision-safe path
|
||||
- the response notes that project setup must run in the new worktree before it can run
|
||||
- prompt: "Should I do this small one-line typo fix in a worktree?"
|
||||
grader:
|
||||
- the response invokes the using-worktrees skill
|
||||
- the response recommends SKIP (small single-stream fix, nothing to isolate) and works in place
|
||||
- the response does not create a worktree
|
||||
- prompt: "This change is medium-sized and I'm not sure if it'll conflict with what I'm doing"
|
||||
grader:
|
||||
- the response invokes the using-worktrees skill
|
||||
- the response treats this as ambiguous and PROPOSES a worktree in one line, then waits, rather than creating it unilaterally
|
||||
- prompt: "Two coder worktrees both run the app on port 9502 — will they be isolated?"
|
||||
grader:
|
||||
- the response invokes the using-worktrees skill
|
||||
- the response explains that worktrees isolate code state but NOT runtime (ports/DBs/services can still collide)
|
||||
- the response recommends per-worktree setup to separate the runtime
|
||||
- prompt: "What's the difference between git clone and git worktree?"
|
||||
grader:
|
||||
- the response does NOT invoke the using-worktrees skill
|
||||
- the response answers the conceptual question directly
|
||||
Reference in New Issue
Block a user