Skip to content
Back to skills

Hunt

ASecurity

Begin work on a ticket — creates a worktree and writes the first test.

  • 2 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added October 19, 2026
toolspythonshellbashgit

Works with

  • cli

Security analysis

A100/100

Scanned October 19, 2026

npx -y skills add MinhHaDuong/ImperialDragonHarness --skill hunt --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Hunt?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Hunt
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/minhhaduong-hunt/badge)](https://www.skillsdirectory.com/skills/minhhaduong-hunt)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: hunt
description: "Begin work on a ticket — creates a worktree and writes the first test."
disable-model-invocation: false
user-invocable: true
argument-hint: "<ticket-id> [inline]"
---

# Hunt — begin work on ticket $ARGUMENTS

For helper commands, set `IDH_ROOT="$(cd -P "$(dirname "<loaded-SKILL.md>")/../.." && pwd -P)"` in the same shell call. Replace `<loaded-SKILL.md>` with the absolute path the runtime supplied for this skill. This follows a projected skill symlink to the canonical checkout; do not derive the helper root from the project cwd.

`[Plan → Execute]`

## Steps

1. Read the ticket (from git-erg `tickets/` directory or forge).
2. Check the **Exit criteria** section. If unclear, ask the author before writing code.
   - If all exit criteria are **already met** (verify by inspection/grep before writing any code),
     close the ticket through the **normal branch + PR flow** — never commit the close on `main`.
     Enter the worktree (step 3) and create the branch (step 4) first, then on that branch run
     `${ERG:-tickets/erg} close $ARGUMENTS already-done`, commit the ticket file
     (`git add -u tickets/ && git commit -m "ticket($ARGUMENTS): close — already-done"`
     — `-u` stages the close edit and any dependent Blocked-by removals, never a
     stray file in the shared `tickets/`), and open the
     merge request (step 10). Skip the test/implement steps (5–9); the merge request lands the close
     via review like any other change. Do not stop with an uncommitted-to-`main` or unpushed close.
2b. **Route before you execute.** This triage runs once, at hunt entry, before any
   code is written. Step 2's already-met fast path never reaches it, and needs no
   triage: it executes nothing, it only lands a close through the normal PR flow.
   Of the hunts that do arrive here, three skip it entirely and proceed straight to step 3:
   an executor already running detached, identified by step 3's worktree ownership
   check (that check is the sole discriminator — do not restate its conditions
   here); a hunt the author invoked with an explicit `inline` argument, which
   keeps the co-working behaviour in the author's own session — arguments are
   `<ticket-id>` optionally followed by `inline`, so the ticket id is the
   leading token of `$ARGUMENTS` and is what every `t$ARGUMENTS` worktree name
   and `${ERG:-tickets/erg} close $ARGUMENTS` substitution in this file refers
   to; and a headless run
   (`claude -p "/hunt <id>"`), which is already the detached case an orchestrator
   asked for. Only a hunt in the author's live interactive session reaches the
   fork below.
   Each skip is total, the needs-human branch included: an executor spawned by an
   interactive hunt was triaged by that hunt before it was spawned, so re-reading
   the tells buys nothing. A raid, though, picks its own targets and no
   interactive hunt precedes them. `erg ready` already skip-lists the label
   (`tickets/.ergrc`), and raid Phase 1 screens its own targets ([[0390]]);
   neither is a second triage here.
   - **Needs-human triage.** Read the ticket for these tells, mostly mechanical: a
     `Label: needs-human` header; exit criteria carrying decision verbs (decide,
     arbitrate, sign-off, choose among); manuscript prose as the deliverable, which
     rules/git.md § Prose workpackages already reserves for author arbitration; a
     premise resting on conflicting sources. On a hit, do not execute and write no
     code. Return ONE batched decision list to the author, each item with a
     recommended default, and end the turn. That return is a success outcome of the
     hunt, not a failure, exactly as the raid drift guard treats a premise objection.
   - **Detach by default.** No tell hit, and the hunt is running in the author's
     interactive session: hand the ticket to ONE background agent, which creates
     its own worktree in step 3. Not a raid — for a single ticket its orchestrator and review panels
     cost more than the ticket returns. Launch it with the coder profile (`agents/coder.md`; choose the model per launch from the
     `route` skill, there is no frontmatter pin). The agent's FIRST action is mechanical:
     ```
     Skill(skill: "hunt", args: "$ARGUMENTS")
     ```
     The launch prompt must NOT paraphrase, summarize, or inline hunt's steps;
     `skills/hunt/SKILL.md` is the single live execution contract and the loader
     supplies it fresh on every run (mirrors raid Phase 5). Instruct the agent to
     push its branch and open a merge request as hunt's flow dictates. Then report
     the handoff. Block on the runner with bounded `agent.wait` slices when the
     author is hands-off or the runtime's notifications cannot wake the parent
     turn; a client interrupt cancels the watch, not the runner — re-attach and
     wait again. Otherwise end the turn and say a prompt retrieves the result:
     the interactive session stays at decision altitude instead of accumulating
     the executor's test dumps, diffs, and review rounds, which measured 5.4x the
     cost of the same contract run detached.
3. Work in the ticket's **own** worktree. A worktree is **owned** when you created
   it for this ticket, or the spawner handed it to you by path with
   `git status --porcelain` printing nothing. A shared or `explore-*` worktree that
   may host a live session is **not owned**: a hunt must never rebase, branch, or
   leave uncommitted files in it (2026-06-11: a hunt inherited an orchestration
   session's worktree, rebased its branch, and stranded in-progress test edits
   there). Otherwise create one with plain git under the primary checkout,
   `<pid>` from `bash -c 'echo $$'` so parallel sessions get distinct paths:
   ```bash
   R=$(dirname "$(git rev-parse --path-format=absolute --git-common-dir)")
   W=$R/.claude/worktrees/t$ARGUMENTS-<pid>
   git worktree add "$W" -b t$ARGUMENTS-short-description origin/main
   python3 "$IDH_ROOT/scripts/worktree-tmp-guard.py" register "$W"
   git worktree lock --reason "hunt t$ARGUMENTS (pid <owner-pid>)" "$W"
   cd "$W"
   ```
   Plain `git` works from any checkout of the repo: every worktree shares one
   git store. The `cd` keeps a bare command off the primary checkout.
   If the branch already exists (re-hunt, second session), drop `-b` and name
   it: `git worktree add "$W" <branch>`. Without `origin/main`, use `main`.
   `<owner-pid>` is the long-lived runtime process: `echo $PPID` in the Bash tool,
   whose shell is the runtime's child. Not the `bash -c 'echo $$'` child, which
   dies at once and would let `worktree-gc` unlock a live tree. The lock marks it
   in use for `worktree-gc` and molt while that pid lives; `worktree-gc` reclaims
   it once the pid is dead (it parses `(pid N` from the reason). Work only there: absolute
   paths under it, `git -C <worktree>` for git. Ad hoc orchestrators should not
   hand-type this contract: spawn the hunt headlessly with `claude -p "/hunt <id>" --model <token>`.
   Choose the model of each launched worker per launch, from the `route` skill grid
   (`skills/route/SKILL.md`); seats that must be independent follow
   `skills/route/references/decorrelation.md` ("The launch line").
   Use per-command `TMPDIR` settings such as `TMPDIR="$W/.tmp" <command>`;
   do not export TMPDIR for the session; never session-wide export it. `.tmp/` is ignored through common Git
   `info/exclude`, remains owned by the worktree, and is never purged separately.
   Evidence stays outside `.tmp/`; deliverables stay outside `.tmp/` too.
4. In a handed-over worktree, create or checkout the ticket branch (step 3 already made it otherwise):
   ```bash
   git switch -c t$ARGUMENTS-short-description
   python3 "$IDH_ROOT/scripts/worktree-tmp-guard.py" register "$(git rev-parse --show-toplevel)"
   ```
   Registration is idempotent; run it after branch setup for both newly
   created and handed-over worktrees.
5. Read the files listed in **Relevant files**.
6. Write the first test from the **Test** section of the ticket.
7. Run `make check-fast` — confirm the test fails.
8. Announce `[Plan → Execute]`, then implement until `make check-fast` (or the affected test file alone) passes — that is the loop gate. The project's pre-PR gate runs once immediately before step 10 opens the PR — not per edit.
9. Pre-PR self-gate: run `/verify-adherence <branch>` (the branch created in step 4).
   - Clean → proceed to step 10. Note adherence passed in the merge-request description so `/gaze` can skip the mechanical phase on its next pass.
   - Blockers → decide per blocker:
     - Cheap and mechanical (obvious fix, no design judgement) → fix in place, re-run `make check-fast` and `/verify-adherence`, then proceed only once clean. Up to 3 fix-and-recheck cycles; if still not clean after 3 rounds, escalate.
     - Otherwise → STOP. Do not open the PR. Escalate with the adherence report and the blocker list.
   - Circuit breaker: if `/verify-adherence` itself errors, times out, or returns an unparseable result → ESCALATE. Do not open the PR and do not silently skip the gate.
10. Run the project's declared pre-PR gate once, then push the branch and open a merge request. Run it through `python3 "$IDH_ROOT/scripts/raid-gate.py" -- <gate command>` so a raid can observe a live long-running gate. If the project has `.idh-checks.json`, its gate command is the project's scoped entry point (or `python3 "$IDH_ROOT/scripts/scoped-check.py"` from its root); quote `selected:` and `skipped:` in the PR description. A mapped doc-only diff may run fewer targets; Python code, unmapped paths, or a project without a map run the full `make check`.
11. Review the merge request. This action is mechanical — invoke the review-pr
    skill with the PR number:
    ```
    Skill(skill: "review-pr", args: <pr-number>)
    ```
    Follow the contract the skill loader returns; do not paraphrase or inline its
    steps (mirrors raid Phase 5's mechanical `Skill(hunt)` invocation, ticket 0293).
    Each pass through the 11–12 loop is one **review round**. Do not pass a round
    number: `/review-pr` derives its own round from the merge request's posted
    review history and scopes the panel accordingly — round 1 uses the
    configured small-diff width from `skills/review-pr/panel-width.json`
    (Correctness only when eligible; `review:standard` requests all five
    perspectives), while later rounds re-run only perspectives that objected
    plus a regression check (§ Round scoping in `skills/review-pr/SKILL.md`,
    ticket 0377).
12. Fix all comments regardless of severity. Per fix cycle, run `make check-fast` plus the tests implicated by the comments — not the full suite. If any cycle's fix touches code outside the fast tier, run the full `make check` once, in addition — not on every cycle.
13. Repeat 11–12 up to 3 times, i.e. up to round 3. If still not clean, escalate (see workflow rules).

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.