[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M71RDF0F6GGW2QJXFM3107YZ":3,"skill-same:01M71RDF0F6GGW2QJXFM3107YZ":94},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":18,"publishedAt":39,"linkOnly":40,"markdownContent":41,"markdownBody":42,"frontMatter":43,"refName":44,"commitSha":45,"skillDirectory":46,"forksCount":47,"repositoryHtmlUrl":48,"repositoryHomepageUrl":6,"ownerHtmlUrl":49,"ownerBlogUrl":6,"ownerDescription":50,"updatedAt":51,"install":52,"resources":65},"01M71RDF0F6GGW2QJXFM3107YZ","autospec-classify",null,"Use when the user wants to retro-apply autospec's Phase 3.5 model-fit rubric to already-existing auto-implement issues — walks open issues in the current GitHub repo, classifies each with ctx:* \u002F reasoning:* labels plus a lang:* label, and inserts","berlinguyinca\u002Fautospec","berlinguyinca","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F16364?v=4","01M71R7C0SWBG05FNHQE4XQ7Y3","Gert Wohlgemuth","01M71R7C1VY5K3Q715RNDDBVGQ",3,"MIT","https:\u002F\u002Fgithub.com\u002Fberlinguyinca\u002Fautospec\u002Fblob\u002Fmain\u002Fskills\u002Fautospec-classify\u002FSKILL.md",[],[19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38],"autospec classify","autospec","classify","with","implement","apply","github repo","Existing","use","fit","repo","rubric","phase","when","auto","open","labels","issues","implement issues","model","2026-11-10 13:02:02",false,"---\nname: autospec-classify\ndescription: Use when the user wants to retro-apply autospec's Phase 3.5 model-fit rubric to already-existing auto-implement issues — walks open issues in the current GitHub repo, classifies each with ctx:* \u002F reasoning:* labels plus a lang:* label, and inserts ## Model fit and ## Language fit blocks in the issue body. Defaults to labels-only; --apply-boards opts into ~\u002F.autospec\u002Fproject-map.yml board assignment.\n---\n\n# autospec-classify (harness-neutral)\n\nStandalone retro-labeler. Walk every open `auto-implement` issue in the current\nGitHub repo (excluding `type:tracker`-labeled issues), apply the Phase 3.5\nmodel-fit rubric, and write a `## Model fit` block into the issue body. Default\nmode is labels-only; the `--apply-boards` flag opts into board assignment from\n`~\u002F.autospec\u002Fproject-map.yml`.\n\nManage your own context — never exceed 60%. Delegate to subagents whenever your harness supports it.\n\n\u003C!-- autospec-block:startup-self-update SKILL_NAME=autospec-classify -->\n\n## Self-update mode\n\nIf the feature-request argument matches the regex `^\\s*update\\s*$` (case-insensitive, whitespace-padded), this skill enters self-update mode and does not run the normal pipeline:\n\n1. **Detect harness** by checking which install path exists for this skill:\n   - Claude Code: `~\u002F.claude\u002Fskills\u002Fautospec-classify\u002FSKILL.md`\n   - OpenCode:    `~\u002F.config\u002Fopencode\u002Fagent\u002Fautospec-classify.md`\n   - Codex CLI:   `~\u002F.codex\u002Fprompts\u002Fautospec-classify.md`\n2. **Re-install the full autospec suite from `main`** by piping the canonical installer:\n   ```bash\n   curl -fsSL https:\u002F\u002Fraw.githubusercontent.com\u002Fberlinguyinca\u002Fautospec\u002Fmain\u002Fbootstrap.sh | bash -s -- --skill all --harness all --update\n   ```\n   Run this one-liner once; it refreshes all autospec skills across all harnesses.\n3. **Show the diff** between the prior installed file(s) and the freshly fetched copy (e.g. `diff \u003C(cat \u003Cprior>) \u003C(curl -fsSL ...SKILL.md)` or the equivalent recorded by the installer).\n4. **Stop.** Do not enter Phase 0 \u002F Phase 1 \u002F any pipeline phase. Print the upgrade summary and return to the user.\n\nIf no install path is detected, print `Self-update: no installed copy of autospec-classify found; run install.sh first.` and exit.\n\n## Invocation\n\n```\n\u002Fautospec-classify [--issues N,N,N] [--label \u003Clabel>] [--apply-boards] [--dry-run]\n```\n\n- `--issues N,N,N` — restrict to a comma-separated list of issue numbers (default:\n  every open issue in the current repo).\n- `--label \u003Clabel>` — restrict to issues carrying a specific label\n  (default: `auto-implement`).\n- `--apply-boards` — also assign issues to GitHub Projects per\n  `~\u002F.autospec\u002Fproject-map.yml`. If the file is missing on first run, auto-init\n  writes a starter file keyed on the repo's labels with `null` project numbers\n  and exits with `Wrote ~\u002F.autospec\u002Fproject-map.yml. Edit project numbers\n  (currently null) and re-run.`. Without `--apply-boards` the project-map is\n  not consulted.\n- `--dry-run` — print proposed labels, model-fit blocks, and board assignments\n  without calling `gh issue edit` or `gh project item-add`.\n\nThe skill exits non-zero if `gh auth status` fails or the current cwd is not a\nGitHub-tracked repo.\n\n## Required capabilities & harness adapter\n\nThis workflow assumes a small set of capabilities. Map each one to your harness's actual tool. If a capability is missing, use the listed fallback.\n\n| Capability                  | Claude Code                          | OpenCode                                 | Codex CLI                                | Fallback if missing                                |\n|-----------------------------|--------------------------------------|------------------------------------------|------------------------------------------|----------------------------------------------------|\n| Read-only codebase research | `Agent` (subagent_type=Explore)      | `task` agent in read-only mode           | `apply_patch` read-only \u002F shell `grep`   | Do the search in-thread with `rg`\u002F`grep`           |\n| Foreground delegation       | `Agent` (subagent_type=general-purpose) | nested `task` agent, await output     | spawn nested CLI session                 | Do the work in-thread (more context cost)          |\n| Ask the user a question     | `AskUserQuestion`                    | inline prompt                            | inline prompt                            | Ask in the response and wait for the next turn     |\n| Subagent model tier         | Tier A: `opus` + `ultrathink`; Tier B: `sonnet` + medium thinking | Tier A: top `task` model + high reasoning; Tier B: smaller-tier `task` + medium reasoning | Tier A: top GPT + `reasoning_effort=high`; Tier B: current spark\u002Fcost-optimized Codex + `reasoning_effort=medium` | Honor the per-phase tier mapping in AGENTS.md; retry the same subagent UP on unavailability |\n\u003C!-- autospec-block:harness-adapter-core -->\n\n**Persistent project notes**: write durable preferences to **`AGENTS.md`** in the repo root — this is the de-facto standard recognized by Claude Code (also reads `CLAUDE.md`), OpenCode, and Codex. If your harness has its own private memory (e.g. Claude Code's `~\u002F.claude\u002F...\u002Fmemory\u002F`), mirror the same content there. Per AGENTS.md, subagent dispatches use a **two-tier policy**: Tier A (top model + extended thinking) for spec work and Tier B (cheaper model + medium thinking) for implementation work. This skill's per-issue classification is **deterministic-first**: the deterministic rubric runs with no LLM call, and only ambiguous issues escalate to a single Tier-B LLM tie-breaker — never Tier A. The orchestrator keeps the user's invoked model. Fall back UP the tier on quota\u002Fcapacity or other unavailability by retrying the same subagent with the stronger tier while preserving parent context.\n\n## Harness detection (run once at skill start, before Phase 0)\n\nDetect your harness by checking available tools before any phase:\n\n1. **Claude Code** — the `Agent` tool with a `subagent_type` parameter is available.\n   - `TIER_A` = `opus` + `ultrathink`  (the alias, which resolves to the current Claude Opus generation)\n   - `TIER_B` = `sonnet`               (the alias, which resolves to the current Claude Sonnet generation)\n\n2. **OpenCode** — a `task` tool with model\u002Ftier configuration is available (no `subagent_type`).\n   - `TIER_A` = top-tier task model + high reasoning\n   - `TIER_B` = smaller-tier task model + medium reasoning\n\n3. **Codex CLI** — neither `Agent` nor a configurable `task` tool is available; `apply_patch` is the primary edit tool.\n   - `TIER_A` = current top GPT model + `reasoning_effort=high`\n   - `TIER_B` = the spark \u002F cost-optimized variant of the configured model when one exists, else the configured model + `reasoning_effort=medium`\n\n**Fallback rule:** If `TIER_B` is not available in your harness (model unknown, quota\u002Fcapacity failure, authorization failure, or tool call returns an error for that model), silently retry the same subagent dispatch with `TIER_A`. Preserve the parent context on retry; for Codex native subagents, fork\u002Finherit the current conversation context and use the latest top GPT model instead of moving the work into the main session. Never ask the user.\n\nHold `TIER_A` and `TIER_B` for the entire skill run. Every \"Tier A\" and \"Tier B\" reference below resolves to these harness-specific values.\n\n## Relevant memory injection (run-start, once)\n\nBefore executing the main pipeline phases, call the injector to surface relevant saved lessons:\n\n```bash\nbash \"${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Finject-relevant-memory.sh\" \\\n  --context \"\u003Cskill-relevant keywords from request\u002Fissue\u002Fspec>\" \\\n  --top-k 5\n```\n\nPrepend the output block (if non-empty) to your working context. This surfaces lessons like\n`feedback_bash_return_trap_leak.md` that prevent re-occurrence of known pitfalls.\n\n## Pre-flight\n\n1. Verify `gh auth status` is authenticated.\n2. Capture `{repo}` from `gh repo view --json nameWithOwner -q .nameWithOwner`.\n3. Resolve the candidate set — walk **both** `auto-implement` AND\n   `needs-classify` issues (per spec §5.3, listener-filed issues land\n   labeled `needs-classify` and `\u002Fautospec-classify` is the entry point\n   that transitions them onto the implementation queue):\n   - `gh issue list --repo {repo} --label \u003Clabel> --state open --limit 500 --json number,title,labels,body,url`\n     for the value of `--label` (default `auto-implement`).\n   - Additionally, `gh issue list --repo {repo} --label needs-classify --state open --limit 500 --json number,title,labels,body,url`.\n   - Merge both result sets, deduplicating by issue number (an issue may\n     carry both labels during a partial transition).\n   - Filter out any issue whose labels include `type:tracker`.\n   - Apply the `--issues` filter if provided.\n\n### Issue intent safety gate\n\nThe classifier may persist model-fit and quality metadata, but it must never\nauthor an automatic safety decision. After the final body is persisted, the\nRust queue command is the only authority for an admission pass, ambiguity, or\nblock.\n\n### Label transition for `needs-classify` issues\n\nFor every issue in the candidate set whose labels include `needs-classify`, run\nthe Rust admission only after Steps 2–6 of the per-issue procedure have\npersisted the final body. First make the issue an interim queue candidate, then\nreview that exact issue:\n\n```bash\ngh issue edit \u003CN> --add-label auto-implement --remove-label needs-classify --repo {repo}\n\"${AUTOSPEC_BIN:-autospec}\" queue review-safety --repo {repo} --limit 1 --issue \u003CN>\n```\n\nRead the command's JSON totals. Only `pass: 1` admits this invocation. Any\nother result is already recorded by Rust and must be skipped without a prompt,\nshell, or semantic reviewer changing labels, comments, or issue body. Issues\nalready carrying `auto-implement` are re-classified in place, then receive the\nsame exact review after their final body is persisted.\n\n## Rubric\n\n### `ctx:*` — context-window axis\n\nPick the smallest tier that holds the staged context (issue body + every file\nlisted under `## Files to read first` + the relevant spec sections).\n\n| Label | Approx. token ceiling | Trigger |\n|---|---|---|\n| `ctx:32k`  | ~32k tokens of staged context | One canonical table or one shell script; ≤3 files in *Files to read first*; spec anchors are short. |\n| `ctx:64k`  | ~64k tokens                   | Multi-file change; 4-7 files staged; one trio + one installer; medium spec sections (~1-3 KB). |\n| `ctx:120k` | ~120k tokens                  | Cross-skill or cross-package; 8+ files; long spec excerpts; deep call graphs. |\n\nIf unsure between two tiers, prefer the larger tier.\n\n### `reasoning:*` — reasoning-depth axis\n\nPick the depth required to **derive** the implementation, not just transcribe it.\n\n| Label | Trigger |\n|---|---|\n| `reasoning:shallow` | Mechanical: copy-and-rename, regex-replace, README transcription, runbook authoring. Verbs in the issue: *copy*, *rename*, *transcribe*, *list*. |\n| `reasoning:medium`  | Template-following with judgment calls: synthesize a new SKILL.md by mirroring an existing one, modify a script with new flags, write tests for a documented contract. Verbs: *mirror*, *adapt*, *integrate*, *wire*. |\n| `reasoning:deep`    | Novel design choices: pick a new abstraction, resolve a contradiction in the spec, reconcile cross-cutting concerns. Verbs: *design*, *reconcile*, *resolve*, *redesign*. |\n\nDefault for issues that lack any of these signals: `ctx:64k`, `reasoning:medium`.\n\n## Per-issue procedure\n\n> **Model tier:** **deterministic-first; `TIER_B` on ambiguity (never `TIER_A`).**\n> Classification runs the deterministic\n> rubric (`${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Fclassify-model-fit.sh` — file counts, verb keywords, per\n> tracker #421) FIRST, with **no LLM dispatch** for issues it can score\n> confidently. The script itself never calls an LLM. Only an issue you judge\n> ambiguous from the script's reported confidence and rationale escalates to a\n> single `TIER_B` LLM tie-breaker — never `TIER_A`. Sibling normalization stays deterministic. Set\n> `AUTOSPEC_REVIEWER_TIER=opus` only governs the run-trio reviewer, not this\n> classifier; the classifier's LLM tie-breaker is always `TIER_B`.\n\nFor each candidate issue:\n\n1. **Sanity check.** Body must contain both `## Files to read first` and\n   `## Implementation scope`. If either is missing:\n   - Add label `needs-autospec-template` (idempotent, `gh label create --force`\n     once at the top of the run).\n   - Skip — do not modify body, do not assign a model-fit class.\n\n2. **Classify (deterministic-first).** Run the deterministic rubric first\n   (`${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Fclassify-model-fit.sh \u003Cbody-file>`): it assigns one `ctx:*` and one\n   `reasoning:*` label from file counts and verb keywords with **zero LLM cost**.\n   Only when you judge the result ambiguous from its reported confidence and\n   rationale (the script itself never calls an LLM) escalate that single\n   ambiguous issue to one `TIER_B` LLM tie-breaker; otherwise take the\n   deterministic result as final.\n   Print the rationale (and whether it was deterministic or escalated) in the\n   dry-run preview.\n\n3. **Apply labels.**\n   - `gh label create ctx:32k --color c5def5 --force` (and ctx:64k, ctx:120k).\n   - `gh label create reasoning:shallow --color c2e0c6 --force`\n     (and reasoning:medium, reasoning:deep).\n   - `gh label create needs-quality-bar --color fbca04 --force --repo {repo}` (once at run start, idempotent).\n   - `gh label create lang:\u003Cvalue> --color d4c5f9 --force --repo {repo}` once at run\n     start (idempotent) for each of the 12 values: `lang:rust`, `lang:go`,\n     `lang:python`, `lang:typescript`, `lang:javascript`, `lang:java`,\n     `lang:bash`, `lang:ruby`, `lang:csharp`, `lang:markdown`, `lang:mixed`,\n     `lang:unknown`.\n   - `gh issue edit \u003CN> --add-label \"ctx:\u003Ctier>,reasoning:\u003Cdepth>\" --repo {repo}`.\n     The `lang:\u003Cvalue>` label is applied by the Step 4 language-axis fragment,\n     not here.\n   - Skip in `--dry-run`.\n\n4. **Patch body.** Insert a `## Model fit` block immediately before the first\n   `## Dependencies` line (or, if absent, at end of body). Block format:\n\n   ```markdown\n   \u003C!-- autospec-classify:begin -->\n   ## Model fit\n\n   - **ctx:** `ctx:\u003Ctier>` — \u003C1-line rationale>.\n   - **reasoning:** `reasoning:\u003Cdepth>` — \u003C1-line rationale>.\n\n   *Auto-classified by `\u002Fautospec-classify` on YYYY-MM-DD.*\n   \u003C!-- autospec-classify:end -->\n   ```\n\n   **Idempotency:** if a `## Model fit` block already exists (delimited by the\n   `\u003C!-- autospec-classify:begin -->` \u002F `\u003C!-- autospec-classify:end -->`\n   markers), replace it in place. Never stack duplicate blocks.\n\n   Legacy blocks have `## Model fit` ABOVE\n   `\u003C!-- autospec-classify:begin -->`. Replacing only the marker-delimited\n   region orphans that heading outside the markers, where it still counts\n   against the budget, and adds a second one. Delete the legacy heading and\n   everything up to the begin marker first.\n\n    Apply via `gh issue edit \u003CN> --body-file \u003Ctmp>`.\n\n    **Language axis (deterministic).** After the model-fit write, run\n    `apply_lang_step \u003Cbody-file> \u003Clabels-csv>` (function below) on the\n    issue's current body file, with the issue's current label list as the\n    CSV. It invokes the deterministic classifier\n    (`${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Fclassify-language.sh`)\n    twice — once for the canonical `## Language fit` block, once with\n    `--json` for the label value — splices the block into\n    `\u003Cbody-file>.lang` (idempotent: it replaces the existing\n    `\u003C!-- autospec-language:begin -->` … `\u003C!-- autospec-language:end -->`\n    region in place — including any legacy `## Language fit` heading sitting\n    directly above the markers — or inserts a fresh block before the first\n    `## Dependencies` line, or at end of body if that section is absent),\n    and prints exactly two lines on stdout: the bare language value, then a\n    label fragment — `--add-label lang:\u003Cvalue> --remove-label lang:\u003Cold>`\n    if the issue already carries a different `lang:*` label, `--add-label\n    lang:\u003Cvalue>` if it carries none, or `LABEL_NOOP` if it already carries\n    the same one. Apply the fragment with `gh issue edit \u003CN> \u003Cfragment>\n    --repo {repo}` and the patched body with `gh issue edit \u003CN> --body-file\n    \u003Cbody-file>.lang`. `lang:unknown` is a real classification outcome and\n    is applied as-is. Skip both calls in `--dry-run` (print the block and\n    fragment to the preview instead).\n\n    ```bash\n    # autospec-classify lang-step begin\n    apply_lang_step() {\n      # apply_lang_step \u003Cbody-file> \u003Clabels-csv>\n      # Splices the canonical `## Language fit` block (from\n      # ${AUTOSPEC_SCRIPTS_DIR}\u002Fclassify-language.sh) into \u003Cbody-file>.lang and prints\n      # exactly two lines on stdout: the bare language value, then the\n      # label fragment (--add-label lang:\u003Cv> [--remove-label lang:\u003Cold>]\n      # | LABEL_NOOP).\n      local body_file=\"$1\" labels_csv=\"${2:-}\"\n      local classifier=\"${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Fclassify-language.sh\"\n      local md_block lang old l\n      if ! md_block=\"$(bash \"$classifier\" \"$body_file\")\"; then\n        echo \"apply_lang_step: classifier failed for $body_file\" >&2\n        return 2\n      fi\n      lang=\"$(bash \"$classifier\" \"$body_file\" --json | sed -n 's\u002F.*\"lang\":\"\\([^\"]*\\)\".*\u002F\\1\u002Fp' | sed -n '1p')\"\n      if [ -z \"$lang\" ]; then\n        echo \"apply_lang_step: no lang value in classifier --json output\" >&2\n        return 2\n      fi\n      old=\"\"\n      if [ -n \"$labels_csv\" ]; then\n        local IFS=','\n        for l in $labels_csv; do\n          case \"$l\" in\n            lang:*) old=\"$l\" ;;\n          esac\n        done\n      fi\n      old=\"${old#lang:}\"\n      if ! LANG_BLOCK=\"$md_block\" awk '\n        BEGIN { n = 0 }\n        {\n          n++\n          line[n] = $0\n          b = $0\n          sub(\u002F\\r$\u002F, \"\", b)\n          if (begin == 0 && b ~ \u002F^[[:space:]]*\u003C!-- autospec-language:begin -->[[:space:]]*$\u002F) begin = n\n          if (endm == 0 && b ~ \u002F^[[:space:]]*\u003C!-- autospec-language:end -->[[:space:]]*$\u002F) endm = n\n        }\n        END {\n          if ((begin == 0) != (endm == 0) || (begin != 0 && begin > endm)) {\n            print \"lang-splice: unpaired autospec-language markers\" > \"\u002Fdev\u002Fstderr\"\n            exit 1\n          }\n          if (begin != 0) {\n            del_begin = begin\n            i = begin - 1\n            while (i > 1 && line[i] ~ \u002F^[[:space:]]*$\u002F) i--\n            if (i >= 1 && line[i] ~ \u002F^[[:space:]]*## Language fit[[:space:]]*$\u002F) del_begin = i\n            del_end = endm\n            if (del_begin > 1 && line[del_begin - 1] ~ \u002F^[[:space:]]*$\u002F) del_begin--\n            if (del_end \u003C n && line[del_end + 1] ~ \u002F^[[:space:]]*$\u002F) del_end++\n            k = 0\n            for (i = 1; i \u003C= n; i++) {\n              if (i >= del_begin && i \u003C= del_end) continue\n              k++\n              kept[k] = line[i]\n            }\n          } else {\n            k = n\n            for (i = 1; i \u003C= n; i++) kept[i] = line[i]\n          }\n          ins = 0\n          for (i = 1; i \u003C= k; i++) {\n            t = kept[i]\n            sub(\u002F\\r$\u002F, \"\", t)\n            if (t ~ \u002F^[[:space:]]*## Dependencies[[:space:]]*$\u002F) { ins = i; break }\n          }\n          m = split(ENVIRON[\"LANG_BLOCK\"], bl, \"\\n\")\n          if (ins > 0) {\n            j = ins - 1\n            while (j > 0 && kept[j] ~ \u002F^[[:space:]]*$\u002F) j--\n            for (i = 1; i \u003C= j; i++) print kept[i]\n            if (j > 0) print \"\"\n            for (i = 1; i \u003C= m; i++) print bl[i]\n            print \"\"\n            for (i = ins; i \u003C= k; i++) print kept[i]\n          } else {\n            t = k\n            while (t > 0 && kept[t] ~ \u002F^[[:space:]]*$\u002F) t--\n            for (i = 1; i \u003C= t; i++) print kept[i]\n            if (t > 0) print \"\"\n            for (i = 1; i \u003C= m; i++) print bl[i]\n          }\n        }\n      ' \"$body_file\" > \"$body_file.lang\"; then\n        echo \"apply_lang_step: splice failed for $body_file\" >&2\n        return 2\n      fi\n      printf '%s\\n' \"$lang\"\n      if [ \"$old\" = \"$lang\" ]; then\n        printf '%s\\n' \"LABEL_NOOP\"\n      elif [ -n \"$old\" ]; then\n        printf '%s\\n' \"--add-label lang:$lang --remove-label lang:$old\"\n      else\n        printf '%s\\n' \"--add-label lang:$lang\"\n      fi\n    }\n    # autospec-classify lang-step end\n    ```\n\n5. **Board assignment** (only if `--apply-boards`):\n   - Read `~\u002F.autospec\u002Fproject-map.yml`. If the file is missing, auto-init it\n     (see below) and exit so the user can fill in project numbers.\n   - **File schema:**\n     ```yaml\n     # ~\u002F.autospec\u002Fproject-map.yml\n     multi_match: union          # `union` (assign to every match) or `first`\n     mappings:\n       ctx:32k: \u003Cproject_number>\n       ctx:64k: \u003Cproject_number>\n       ctx:120k: \u003Cproject_number>\n       reasoning:shallow: \u003Cproject_number>\n       reasoning:medium:  \u003Cproject_number>\n       reasoning:deep:    \u003Cproject_number>\n       \u003Cany-other-label>: \u003Cproject_number>\n     ```\n   - **Reader procedure.** For each label L on the issue, look up\n     `mappings[L]`. Skip null \u002F missing entries. With `multi_match: union`\n     (default), assign the issue to every matching project number; with\n     `multi_match: first`, assign only to the first match in label-order.\n     For each chosen `\u003CP>`:\n     `gh project item-add \u003CP> --owner \u003Cowner> --url \u003Cissue-url>`. The\n     command is idempotent so re-running this skill does not duplicate\n     project items.\n   - **Auto-init when the file is missing.** Probe\n     `gh project list --owner \u003Cowner> --format json` to confirm the user\n     can author projects. Probe\n     `gh label list --repo {repo} --json name -q '.[].name'` to enumerate\n     the repo's labels. Write a starter file with every label as a\n     `mappings:` key and `null` project numbers, plus `multi_match: union`\n     at the top. Print:\n     ```\n     Wrote ~\u002F.autospec\u002Fproject-map.yml. Edit project numbers (currently null) and re-run.\n     ```\n     Then **exit non-zero** (this is a hard stop unique to\n     `--apply-boards`; without the flag the run continues normally).\n   - Skip in `--dry-run`.\n\n6. **Quality audit.** After patching the `## Model fit` block:\n   - Pull body: `gh issue view \u003CN> --repo {repo} --json body -q .body > \u002Ftmp\u002Faudit-\u003CN>.md`\n   - Run: `bash \"${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Flint-issue.sh\" \u002Ftmp\u002Faudit-\u003CN>.md`\n   - On non-zero exit (lint fails):\n     - Apply label: `gh issue edit \u003CN> --add-label needs-quality-bar --repo {repo}`\n     - Insert `## Quality lint` block (idempotent, between `\u003C!-- autospec-quality:begin -->` and `\u003C!-- autospec-quality:end -->` markers) via `gh issue edit \u003CN> --body-file \u003Ctmp>`. A legacy block has the heading ABOVE the begin marker: delete the legacy heading and everything up to that marker first, or it keeps counting and a duplicate is added. Block format:\n       ```markdown\n       \u003C!-- autospec-quality:begin -->\n       ## Quality lint\n\n       - **GOAL** — \u003C1-line finding>.\n       - **AC#\u003Cn>** — \u003C1-line finding>.\n       - **SMOKE** — \u003C1-line finding>.\n\n       *Auto-linted by Phase 3.5 on YYYY-MM-DD.*\n       \u003C!-- autospec-quality:end -->\n       ```\n     - Comment findings: `gh issue comment \u003CN> --body \"\u003Cfindings>\" --repo {repo}`\n   - Do NOT remove `auto-implement` label. Operator decides whether to proceed.\n   - Skip in `--dry-run`.\n\n7. **Rust safety admission.** After every model-fit and quality-body write has\n   completed, admit the exact issue with the command in\n   [Label transition for `needs-classify` issues](#label-transition-for-needs-classify-issues).\n   For an issue already carrying `auto-implement`, do not change ordinary\n   labels first; invoke the same exact command. Only a JSON `pass: 1` result is\n   eligible for later implementation work.\n\n## Sibling normalization (forward reference)\n\nWhen 5+ sibling issues share a structural criterion (e.g. all are\n\"per-source-table writers\"), harmonize their `ctx:*` and `reasoning:*` labels so\nthe operator can run a single profile across the whole group. The full\nsibling-normalization prompt is part of Phase 3.5 (PR B1, issue #14); when it\nlands, this skill calls into it. Until then, classify each sibling\nindependently.\n\n## Run-end summary\n\nPrint:\n\n```\nautospec-classify run summary on {repo}\n- classified: N\n- skipped (needs-autospec-template): M\n- ctx:32k=A  ctx:64k=B  ctx:120k=C\n- reasoning:shallow=X  reasoning:medium=Y  reasoning:deep=Z\n- lang:rust=A  lang:go=B  … one entry per observed `lang:*` value\n  (`lang:unknown` is its own entry)\n- boards assigned: \u003CK>  (or \"skipped — --apply-boards not set\" \u002F \"skipped — no project-map.yml\")\n```\n\n## Hard rules\n\n- Never modify the issue title.\n- Never remove existing labels, except that the language axis may replace a\n  prior `lang:*` label (one `--remove-label lang:\u003Cold>` per\n  re-classification). Otherwise only add `ctx:*`, `reasoning:*`,\n  `needs-autospec-template`, `lang:*`.\n- Never call `gh issue edit` in `--dry-run` mode.\n- Immediately after every successful non-dry-run issue edit, capture the verified issue URL as\n  `ISSUE_URL` and run `bash \"${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Fproject-sync-issue.sh\" \"$ISSUE_URL\" \"$PWD\"`.\n  Continue only for a verified journaled-pending warning. A hard pre-journal failure stops classification after preserving the edited issue; never create a replacement issue.\n- Always idempotent — running twice on the same issue results in no diff after\n  the second run (same labels, same `## Model fit` block).\n- `gh` CLI only; no direct GraphQL.\n","# autospec-classify (harness-neutral)\n\nStandalone retro-labeler. Walk every open `auto-implement` issue in the current\nGitHub repo (excluding `type:tracker`-labeled issues), apply the Phase 3.5\nmodel-fit rubric, and write a `## Model fit` block into the issue body. Default\nmode is labels-only; the `--apply-boards` flag opts into board assignment from\n`~\u002F.autospec\u002Fproject-map.yml`.\n\nManage your own context — never exceed 60%. Delegate to subagents whenever your harness supports it.\n\n\u003C!-- autospec-block:startup-self-update SKILL_NAME=autospec-classify -->\n\n## Self-update mode\n\nIf the feature-request argument matches the regex `^\\s*update\\s*$` (case-insensitive, whitespace-padded), this skill enters self-update mode and does not run the normal pipeline:\n\n1. **Detect harness** by checking which install path exists for this skill:\n   - Claude Code: `~\u002F.claude\u002Fskills\u002Fautospec-classify\u002FSKILL.md`\n   - OpenCode:    `~\u002F.config\u002Fopencode\u002Fagent\u002Fautospec-classify.md`\n   - Codex CLI:   `~\u002F.codex\u002Fprompts\u002Fautospec-classify.md`\n2. **Re-install the full autospec suite from `main`** by piping the canonical installer:\n   ```bash\n   curl -fsSL https:\u002F\u002Fraw.githubusercontent.com\u002Fberlinguyinca\u002Fautospec\u002Fmain\u002Fbootstrap.sh | bash -s -- --skill all --harness all --update\n   ```\n   Run this one-liner once; it refreshes all autospec skills across all harnesses.\n3. **Show the diff** between the prior installed file(s) and the freshly fetched copy (e.g. `diff \u003C(cat \u003Cprior>) \u003C(curl -fsSL ...SKILL.md)` or the equivalent recorded by the installer).\n4. **Stop.** Do not enter Phase 0 \u002F Phase 1 \u002F any pipeline phase. Print the upgrade summary and return to the user.\n\nIf no install path is detected, print `Self-update: no installed copy of autospec-classify found; run install.sh first.` and exit.\n\n## Invocation\n\n```\n\u002Fautospec-classify [--issues N,N,N] [--label \u003Clabel>] [--apply-boards] [--dry-run]\n```\n\n- `--issues N,N,N` — restrict to a comma-separated list of issue numbers (default:\n  every open issue in the current repo).\n- `--label \u003Clabel>` — restrict to issues carrying a specific label\n  (default: `auto-implement`).\n- `--apply-boards` — also assign issues to GitHub Projects per\n  `~\u002F.autospec\u002Fproject-map.yml`. If the file is missing on first run, auto-init\n  writes a starter file keyed on the repo's labels with `null` project numbers\n  and exits with `Wrote ~\u002F.autospec\u002Fproject-map.yml. Edit project numbers\n  (currently null) and re-run.`. Without `--apply-boards` the project-map is\n  not consulted.\n- `--dry-run` — print proposed labels, model-fit blocks, and board assignments\n  without calling `gh issue edit` or `gh project item-add`.\n\nThe skill exits non-zero if `gh auth status` fails or the current cwd is not a\nGitHub-tracked repo.\n\n## Required capabilities & harness adapter\n\nThis workflow assumes a small set of capabilities. Map each one to your harness's actual tool. If a capability is missing, use the listed fallback.\n\n| Capability                  | Claude Code                          | OpenCode                                 | Codex CLI                                | Fallback if missing                                |\n|-----------------------------|--------------------------------------|------------------------------------------|------------------------------------------|----------------------------------------------------|\n| Read-only codebase research | `Agent` (subagent_type=Explore)      | `task` agent in read-only mode           | `apply_patch` read-only \u002F shell `grep`   | Do the search in-thread with `rg`\u002F`grep`           |\n| Foreground delegation       | `Agent` (subagent_type=general-purpose) | nested `task` agent, await output     | spawn nested CLI session                 | Do the work in-thread (more context cost)          |\n| Ask the user a question     | `AskUserQuestion`                    | inline prompt                            | inline prompt                            | Ask in the response and wait for the next turn     |\n| Subagent model tier         | Tier A: `opus` + `ultrathink`; Tier B: `sonnet` + medium thinking | Tier A: top `task` model + high reasoning; Tier B: smaller-tier `task` + medium reasoning | Tier A: top GPT + `reasoning_effort=high`; Tier B: current spark\u002Fcost-optimized Codex + `reasoning_effort=medium` | Honor the per-phase tier mapping in AGENTS.md; retry the same subagent UP on unavailability |\n\u003C!-- autospec-block:harness-adapter-core -->\n\n**Persistent project notes**: write durable preferences to **`AGENTS.md`** in the repo root — this is the de-facto standard recognized by Claude Code (also reads `CLAUDE.md`), OpenCode, and Codex. If your harness has its own private memory (e.g. Claude Code's `~\u002F.claude\u002F...\u002Fmemory\u002F`), mirror the same content there. Per AGENTS.md, subagent dispatches use a **two-tier policy**: Tier A (top model + extended thinking) for spec work and Tier B (cheaper model + medium thinking) for implementation work. This skill's per-issue classification is **deterministic-first**: the deterministic rubric runs with no LLM call, and only ambiguous issues escalate to a single Tier-B LLM tie-breaker — never Tier A. The orchestrator keeps the user's invoked model. Fall back UP the tier on quota\u002Fcapacity or other unavailability by retrying the same subagent with the stronger tier while preserving parent context.\n\n## Harness detection (run once at skill start, before Phase 0)\n\nDetect your harness by checking available tools before any phase:\n\n1. **Claude Code** — the `Agent` tool with a `subagent_type` parameter is available.\n   - `TIER_A` = `opus` + `ultrathink`  (the alias, which resolves to the current Claude Opus generation)\n   - `TIER_B` = `sonnet`               (the alias, which resolves to the current Claude Sonnet generation)\n\n2. **OpenCode** — a `task` tool with model\u002Ftier configuration is available (no `subagent_type`).\n   - `TIER_A` = top-tier task model + high reasoning\n   - `TIER_B` = smaller-tier task model + medium reasoning\n\n3. **Codex CLI** — neither `Agent` nor a configurable `task` tool is available; `apply_patch` is the primary edit tool.\n   - `TIER_A` = current top GPT model + `reasoning_effort=high`\n   - `TIER_B` = the spark \u002F cost-optimized variant of the configured model when one exists, else the configured model + `reasoning_effort=medium`\n\n**Fallback rule:** If `TIER_B` is not available in your harness (model unknown, quota\u002Fcapacity failure, authorization failure, or tool call returns an error for that model), silently retry the same subagent dispatch with `TIER_A`. Preserve the parent context on retry; for Codex native subagents, fork\u002Finherit the current conversation context and use the latest top GPT model instead of moving the work into the main session. Never ask the user.\n\nHold `TIER_A` and `TIER_B` for the entire skill run. Every \"Tier A\" and \"Tier B\" reference below resolves to these harness-specific values.\n\n## Relevant memory injection (run-start, once)\n\nBefore executing the main pipeline phases, call the injector to surface relevant saved lessons:\n\n```bash\nbash \"${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Finject-relevant-memory.sh\" \\\n  --context \"\u003Cskill-relevant keywords from request\u002Fissue\u002Fspec>\" \\\n  --top-k 5\n```\n\nPrepend the output block (if non-empty) to your working context. This surfaces lessons like\n`feedback_bash_return_trap_leak.md` that prevent re-occurrence of known pitfalls.\n\n## Pre-flight\n\n1. Verify `gh auth status` is authenticated.\n2. Capture `{repo}` from `gh repo view --json nameWithOwner -q .nameWithOwner`.\n3. Resolve the candidate set — walk **both** `auto-implement` AND\n   `needs-classify` issues (per spec §5.3, listener-filed issues land\n   labeled `needs-classify` and `\u002Fautospec-classify` is the entry point\n   that transitions them onto the implementation queue):\n   - `gh issue list --repo {repo} --label \u003Clabel> --state open --limit 500 --json number,title,labels,body,url`\n     for the value of `--label` (default `auto-implement`).\n   - Additionally, `gh issue list --repo {repo} --label needs-classify --state open --limit 500 --json number,title,labels,body,url`.\n   - Merge both result sets, deduplicating by issue number (an issue may\n     carry both labels during a partial transition).\n   - Filter out any issue whose labels include `type:tracker`.\n   - Apply the `--issues` filter if provided.\n\n### Issue intent safety gate\n\nThe classifier may persist model-fit and quality metadata, but it must never\nauthor an automatic safety decision. After the final body is persisted, the\nRust queue command is the only authority for an admission pass, ambiguity, or\nblock.\n\n### Label transition for `needs-classify` issues\n\nFor every issue in the candidate set whose labels include `needs-classify`, run\nthe Rust admission only after Steps 2–6 of the per-issue procedure have\npersisted the final body. First make the issue an interim queue candidate, then\nreview that exact issue:\n\n```bash\ngh issue edit \u003CN> --add-label auto-implement --remove-label needs-classify --repo {repo}\n\"${AUTOSPEC_BIN:-autospec}\" queue review-safety --repo {repo} --limit 1 --issue \u003CN>\n```\n\nRead the command's JSON totals. Only `pass: 1` admits this invocation. Any\nother result is already recorded by Rust and must be skipped without a prompt,\nshell, or semantic reviewer changing labels, comments, or issue body. Issues\nalready carrying `auto-implement` are re-classified in place, then receive the\nsame exact review after their final body is persisted.\n\n## Rubric\n\n### `ctx:*` — context-window axis\n\nPick the smallest tier that holds the staged context (issue body + every file\nlisted under `## Files to read first` + the relevant spec sections).\n\n| Label | Approx. token ceiling | Trigger |\n|---|---|---|\n| `ctx:32k`  | ~32k tokens of staged context | One canonical table or one shell script; ≤3 files in *Files to read first*; spec anchors are short. |\n| `ctx:64k`  | ~64k tokens                   | Multi-file change; 4-7 files staged; one trio + one installer; medium spec sections (~1-3 KB). |\n| `ctx:120k` | ~120k tokens                  | Cross-skill or cross-package; 8+ files; long spec excerpts; deep call graphs. |\n\nIf unsure between two tiers, prefer the larger tier.\n\n### `reasoning:*` — reasoning-depth axis\n\nPick the depth required to **derive** the implementation, not just transcribe it.\n\n| Label | Trigger |\n|---|---|\n| `reasoning:shallow` | Mechanical: copy-and-rename, regex-replace, README transcription, runbook authoring. Verbs in the issue: *copy*, *rename*, *transcribe*, *list*. |\n| `reasoning:medium`  | Template-following with judgment calls: synthesize a new SKILL.md by mirroring an existing one, modify a script with new flags, write tests for a documented contract. Verbs: *mirror*, *adapt*, *integrate*, *wire*. |\n| `reasoning:deep`    | Novel design choices: pick a new abstraction, resolve a contradiction in the spec, reconcile cross-cutting concerns. Verbs: *design*, *reconcile*, *resolve*, *redesign*. |\n\nDefault for issues that lack any of these signals: `ctx:64k`, `reasoning:medium`.\n\n## Per-issue procedure\n\n> **Model tier:** **deterministic-first; `TIER_B` on ambiguity (never `TIER_A`).**\n> Classification runs the deterministic\n> rubric (`${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Fclassify-model-fit.sh` — file counts, verb keywords, per\n> tracker #421) FIRST, with **no LLM dispatch** for issues it can score\n> confidently. The script itself never calls an LLM. Only an issue you judge\n> ambiguous from the script's reported confidence and rationale escalates to a\n> single `TIER_B` LLM tie-breaker — never `TIER_A`. Sibling normalization stays deterministic. Set\n> `AUTOSPEC_REVIEWER_TIER=opus` only governs the run-trio reviewer, not this\n> classifier; the classifier's LLM tie-breaker is always `TIER_B`.\n\nFor each candidate issue:\n\n1. **Sanity check.** Body must contain both `## Files to read first` and\n   `## Implementation scope`. If either is missing:\n   - Add label `needs-autospec-template` (idempotent, `gh label create --force`\n     once at the top of the run).\n   - Skip — do not modify body, do not assign a model-fit class.\n\n2. **Classify (deterministic-first).** Run the deterministic rubric first\n   (`${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Fclassify-model-fit.sh \u003Cbody-file>`): it assigns one `ctx:*` and one\n   `reasoning:*` label from file counts and verb keywords with **zero LLM cost**.\n   Only when you judge the result ambiguous from its reported confidence and\n   rationale (the script itself never calls an LLM) escalate that single\n   ambiguous issue to one `TIER_B` LLM tie-breaker; otherwise take the\n   deterministic result as final.\n   Print the rationale (and whether it was deterministic or escalated) in the\n   dry-run preview.\n\n3. **Apply labels.**\n   - `gh label create ctx:32k --color c5def5 --force` (and ctx:64k, ctx:120k).\n   - `gh label create reasoning:shallow --color c2e0c6 --force`\n     (and reasoning:medium, reasoning:deep).\n   - `gh label create needs-quality-bar --color fbca04 --force --repo {repo}` (once at run start, idempotent).\n   - `gh label create lang:\u003Cvalue> --color d4c5f9 --force --repo {repo}` once at run\n     start (idempotent) for each of the 12 values: `lang:rust`, `lang:go`,\n     `lang:python`, `lang:typescript`, `lang:javascript`, `lang:java`,\n     `lang:bash`, `lang:ruby`, `lang:csharp`, `lang:markdown`, `lang:mixed`,\n     `lang:unknown`.\n   - `gh issue edit \u003CN> --add-label \"ctx:\u003Ctier>,reasoning:\u003Cdepth>\" --repo {repo}`.\n     The `lang:\u003Cvalue>` label is applied by the Step 4 language-axis fragment,\n     not here.\n   - Skip in `--dry-run`.\n\n4. **Patch body.** Insert a `## Model fit` block immediately before the first\n   `## Dependencies` line (or, if absent, at end of body). Block format:\n\n   ```markdown\n   \u003C!-- autospec-classify:begin -->\n   ## Model fit\n\n   - **ctx:** `ctx:\u003Ctier>` — \u003C1-line rationale>.\n   - **reasoning:** `reasoning:\u003Cdepth>` — \u003C1-line rationale>.\n\n   *Auto-classified by `\u002Fautospec-classify` on YYYY-MM-DD.*\n   \u003C!-- autospec-classify:end -->\n   ```\n\n   **Idempotency:** if a `## Model fit` block already exists (delimited by the\n   `\u003C!-- autospec-classify:begin -->` \u002F `\u003C!-- autospec-classify:end -->`\n   markers), replace it in place. Never stack duplicate blocks.\n\n   Legacy blocks have `## Model fit` ABOVE\n   `\u003C!-- autospec-classify:begin -->`. Replacing only the marker-delimited\n   region orphans that heading outside the markers, where it still counts\n   against the budget, and adds a second one. Delete the legacy heading and\n   everything up to the begin marker first.\n\n    Apply via `gh issue edit \u003CN> --body-file \u003Ctmp>`.\n\n    **Language axis (deterministic).** After the model-fit write, run\n    `apply_lang_step \u003Cbody-file> \u003Clabels-csv>` (function below) on the\n    issue's current body file, with the issue's current label list as the\n    CSV. It invokes the deterministic classifier\n    (`${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Fclassify-language.sh`)\n    twice — once for the canonical `## Language fit` block, once with\n    `--json` for the label value — splices the block into\n    `\u003Cbody-file>.lang` (idempotent: it replaces the existing\n    `\u003C!-- autospec-language:begin -->` … `\u003C!-- autospec-language:end -->`\n    region in place — including any legacy `## Language fit` heading sitting\n    directly above the markers — or inserts a fresh block before the first\n    `## Dependencies` line, or at end of body if that section is absent),\n    and prints exactly two lines on stdout: the bare language value, then a\n    label fragment — `--add-label lang:\u003Cvalue> --remove-label lang:\u003Cold>`\n    if the issue already carries a different `lang:*` label, `--add-label\n    lang:\u003Cvalue>` if it carries none, or `LABEL_NOOP` if it already carries\n    the same one. Apply the fragment with `gh issue edit \u003CN> \u003Cfragment>\n    --repo {repo}` and the patched body with `gh issue edit \u003CN> --body-file\n    \u003Cbody-file>.lang`. `lang:unknown` is a real classification outcome and\n    is applied as-is. Skip both calls in `--dry-run` (print the block and\n    fragment to the preview instead).\n\n    ```bash\n    # autospec-classify lang-step begin\n    apply_lang_step() {\n      # apply_lang_step \u003Cbody-file> \u003Clabels-csv>\n      # Splices the canonical `## Language fit` block (from\n      # ${AUTOSPEC_SCRIPTS_DIR}\u002Fclassify-language.sh) into \u003Cbody-file>.lang and prints\n      # exactly two lines on stdout: the bare language value, then the\n      # label fragment (--add-label lang:\u003Cv> [--remove-label lang:\u003Cold>]\n      # | LABEL_NOOP).\n      local body_file=\"$1\" labels_csv=\"${2:-}\"\n      local classifier=\"${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Fclassify-language.sh\"\n      local md_block lang old l\n      if ! md_block=\"$(bash \"$classifier\" \"$body_file\")\"; then\n        echo \"apply_lang_step: classifier failed for $body_file\" >&2\n        return 2\n      fi\n      lang=\"$(bash \"$classifier\" \"$body_file\" --json | sed -n 's\u002F.*\"lang\":\"\\([^\"]*\\)\".*\u002F\\1\u002Fp' | sed -n '1p')\"\n      if [ -z \"$lang\" ]; then\n        echo \"apply_lang_step: no lang value in classifier --json output\" >&2\n        return 2\n      fi\n      old=\"\"\n      if [ -n \"$labels_csv\" ]; then\n        local IFS=','\n        for l in $labels_csv; do\n          case \"$l\" in\n            lang:*) old=\"$l\" ;;\n          esac\n        done\n      fi\n      old=\"${old#lang:}\"\n      if ! LANG_BLOCK=\"$md_block\" awk '\n        BEGIN { n = 0 }\n        {\n          n++\n          line[n] = $0\n          b = $0\n          sub(\u002F\\r$\u002F, \"\", b)\n          if (begin == 0 && b ~ \u002F^[[:space:]]*\u003C!-- autospec-language:begin -->[[:space:]]*$\u002F) begin = n\n          if (endm == 0 && b ~ \u002F^[[:space:]]*\u003C!-- autospec-language:end -->[[:space:]]*$\u002F) endm = n\n        }\n        END {\n          if ((begin == 0) != (endm == 0) || (begin != 0 && begin > endm)) {\n            print \"lang-splice: unpaired autospec-language markers\" > \"\u002Fdev\u002Fstderr\"\n            exit 1\n          }\n          if (begin != 0) {\n            del_begin = begin\n            i = begin - 1\n            while (i > 1 && line[i] ~ \u002F^[[:space:]]*$\u002F) i--\n            if (i >= 1 && line[i] ~ \u002F^[[:space:]]*## Language fit[[:space:]]*$\u002F) del_begin = i\n            del_end = endm\n            if (del_begin > 1 && line[del_begin - 1] ~ \u002F^[[:space:]]*$\u002F) del_begin--\n            if (del_end \u003C n && line[del_end + 1] ~ \u002F^[[:space:]]*$\u002F) del_end++\n            k = 0\n            for (i = 1; i \u003C= n; i++) {\n              if (i >= del_begin && i \u003C= del_end) continue\n              k++\n              kept[k] = line[i]\n            }\n          } else {\n            k = n\n            for (i = 1; i \u003C= n; i++) kept[i] = line[i]\n          }\n          ins = 0\n          for (i = 1; i \u003C= k; i++) {\n            t = kept[i]\n            sub(\u002F\\r$\u002F, \"\", t)\n            if (t ~ \u002F^[[:space:]]*## Dependencies[[:space:]]*$\u002F) { ins = i; break }\n          }\n          m = split(ENVIRON[\"LANG_BLOCK\"], bl, \"\\n\")\n          if (ins > 0) {\n            j = ins - 1\n            while (j > 0 && kept[j] ~ \u002F^[[:space:]]*$\u002F) j--\n            for (i = 1; i \u003C= j; i++) print kept[i]\n            if (j > 0) print \"\"\n            for (i = 1; i \u003C= m; i++) print bl[i]\n            print \"\"\n            for (i = ins; i \u003C= k; i++) print kept[i]\n          } else {\n            t = k\n            while (t > 0 && kept[t] ~ \u002F^[[:space:]]*$\u002F) t--\n            for (i = 1; i \u003C= t; i++) print kept[i]\n            if (t > 0) print \"\"\n            for (i = 1; i \u003C= m; i++) print bl[i]\n          }\n        }\n      ' \"$body_file\" > \"$body_file.lang\"; then\n        echo \"apply_lang_step: splice failed for $body_file\" >&2\n        return 2\n      fi\n      printf '%s\\n' \"$lang\"\n      if [ \"$old\" = \"$lang\" ]; then\n        printf '%s\\n' \"LABEL_NOOP\"\n      elif [ -n \"$old\" ]; then\n        printf '%s\\n' \"--add-label lang:$lang --remove-label lang:$old\"\n      else\n        printf '%s\\n' \"--add-label lang:$lang\"\n      fi\n    }\n    # autospec-classify lang-step end\n    ```\n\n5. **Board assignment** (only if `--apply-boards`):\n   - Read `~\u002F.autospec\u002Fproject-map.yml`. If the file is missing, auto-init it\n     (see below) and exit so the user can fill in project numbers.\n   - **File schema:**\n     ```yaml\n     # ~\u002F.autospec\u002Fproject-map.yml\n     multi_match: union          # `union` (assign to every match) or `first`\n     mappings:\n       ctx:32k: \u003Cproject_number>\n       ctx:64k: \u003Cproject_number>\n       ctx:120k: \u003Cproject_number>\n       reasoning:shallow: \u003Cproject_number>\n       reasoning:medium:  \u003Cproject_number>\n       reasoning:deep:    \u003Cproject_number>\n       \u003Cany-other-label>: \u003Cproject_number>\n     ```\n   - **Reader procedure.** For each label L on the issue, look up\n     `mappings[L]`. Skip null \u002F missing entries. With `multi_match: union`\n     (default), assign the issue to every matching project number; with\n     `multi_match: first`, assign only to the first match in label-order.\n     For each chosen `\u003CP>`:\n     `gh project item-add \u003CP> --owner \u003Cowner> --url \u003Cissue-url>`. The\n     command is idempotent so re-running this skill does not duplicate\n     project items.\n   - **Auto-init when the file is missing.** Probe\n     `gh project list --owner \u003Cowner> --format json` to confirm the user\n     can author projects. Probe\n     `gh label list --repo {repo} --json name -q '.[].name'` to enumerate\n     the repo's labels. Write a starter file with every label as a\n     `mappings:` key and `null` project numbers, plus `multi_match: union`\n     at the top. Print:\n     ```\n     Wrote ~\u002F.autospec\u002Fproject-map.yml. Edit project numbers (currently null) and re-run.\n     ```\n     Then **exit non-zero** (this is a hard stop unique to\n     `--apply-boards`; without the flag the run continues normally).\n   - Skip in `--dry-run`.\n\n6. **Quality audit.** After patching the `## Model fit` block:\n   - Pull body: `gh issue view \u003CN> --repo {repo} --json body -q .body > \u002Ftmp\u002Faudit-\u003CN>.md`\n   - Run: `bash \"${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Flint-issue.sh\" \u002Ftmp\u002Faudit-\u003CN>.md`\n   - On non-zero exit (lint fails):\n     - Apply label: `gh issue edit \u003CN> --add-label needs-quality-bar --repo {repo}`\n     - Insert `## Quality lint` block (idempotent, between `\u003C!-- autospec-quality:begin -->` and `\u003C!-- autospec-quality:end -->` markers) via `gh issue edit \u003CN> --body-file \u003Ctmp>`. A legacy block has the heading ABOVE the begin marker: delete the legacy heading and everything up to that marker first, or it keeps counting and a duplicate is added. Block format:\n       ```markdown\n       \u003C!-- autospec-quality:begin -->\n       ## Quality lint\n\n       - **GOAL** — \u003C1-line finding>.\n       - **AC#\u003Cn>** — \u003C1-line finding>.\n       - **SMOKE** — \u003C1-line finding>.\n\n       *Auto-linted by Phase 3.5 on YYYY-MM-DD.*\n       \u003C!-- autospec-quality:end -->\n       ```\n     - Comment findings: `gh issue comment \u003CN> --body \"\u003Cfindings>\" --repo {repo}`\n   - Do NOT remove `auto-implement` label. Operator decides whether to proceed.\n   - Skip in `--dry-run`.\n\n7. **Rust safety admission.** After every model-fit and quality-body write has\n   completed, admit the exact issue with the command in\n   [Label transition for `needs-classify` issues](#label-transition-for-needs-classify-issues).\n   For an issue already carrying `auto-implement`, do not change ordinary\n   labels first; invoke the same exact command. Only a JSON `pass: 1` result is\n   eligible for later implementation work.\n\n## Sibling normalization (forward reference)\n\nWhen 5+ sibling issues share a structural criterion (e.g. all are\n\"per-source-table writers\"), harmonize their `ctx:*` and `reasoning:*` labels so\nthe operator can run a single profile across the whole group. The full\nsibling-normalization prompt is part of Phase 3.5 (PR B1, issue #14); when it\nlands, this skill calls into it. Until then, classify each sibling\nindependently.\n\n## Run-end summary\n\nPrint:\n\n```\nautospec-classify run summary on {repo}\n- classified: N\n- skipped (needs-autospec-template): M\n- ctx:32k=A  ctx:64k=B  ctx:120k=C\n- reasoning:shallow=X  reasoning:medium=Y  reasoning:deep=Z\n- lang:rust=A  lang:go=B  … one entry per observed `lang:*` value\n  (`lang:unknown` is its own entry)\n- boards assigned: \u003CK>  (or \"skipped — --apply-boards not set\" \u002F \"skipped — no project-map.yml\")\n```\n\n## Hard rules\n\n- Never modify the issue title.\n- Never remove existing labels, except that the language axis may replace a\n  prior `lang:*` label (one `--remove-label lang:\u003Cold>` per\n  re-classification). Otherwise only add `ctx:*`, `reasoning:*`,\n  `needs-autospec-template`, `lang:*`.\n- Never call `gh issue edit` in `--dry-run` mode.\n- Immediately after every successful non-dry-run issue edit, capture the verified issue URL as\n  `ISSUE_URL` and run `bash \"${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Fproject-sync-issue.sh\" \"$ISSUE_URL\" \"$PWD\"`.\n  Continue only for a verified journaled-pending warning. A hard pre-journal failure stops classification after preserving the edited issue; never create a replacement issue.\n- Always idempotent — running twice on the same issue results in no diff after\n  the second run (same labels, same `## Model fit` block).\n- `gh` CLI only; no direct GraphQL.\n",{"name":5,"description":7},"main","9e7f04357ff46ab731d4f56a4ac5ca5449c13bb0","skills\u002Fautospec-classify",1,"https:\u002F\u002Fgithub.com\u002Fberlinguyinca\u002Fautospec","https:\u002F\u002Fgithub.com\u002Fberlinguyinca","Love to lead, code, cook and contribute to open source and believe that you can learn anything you set your mind too.\r\n","2026-11-11 07:09:35",{"source":8,"skillName":5,"commands":53,"prompt":63,"zipAvailable":64},[54,57,60],{"tool":55,"command":56},"npx","npx skills add berlinguyinca\u002Fautospec --skill autospec-classify",{"tool":58,"command":59},"bunx","bunx skills add berlinguyinca\u002Fautospec --skill autospec-classify",{"tool":61,"command":62},"pnpm","pnpm dlx skills add berlinguyinca\u002Fautospec --skill autospec-classify","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fberlinguyinca\u002Fautospec\u002Fblob\u002Fmain\u002Fskills\u002Fautospec-classify\u002FSKILL.md",true,[66,72,78,82,86,90],{"path":67,"resourceType":68,"resourceTypeDesc":69,"sizeBytes":70,"sourceHtmlUrl":71},"codex\u002Fprompt.md","REFERENCE","参考文档",25142,"https:\u002F\u002Fgithub.com\u002Fberlinguyinca\u002Fautospec\u002Fblob\u002Fmain\u002Fskills\u002Fautospec-classify\u002Fcodex\u002Fprompt.md",{"path":73,"resourceType":74,"resourceTypeDesc":75,"sizeBytes":76,"sourceHtmlUrl":77},"install.sh","SCRIPT","脚本",11521,"https:\u002F\u002Fgithub.com\u002Fberlinguyinca\u002Fautospec\u002Fblob\u002Fmain\u002Fskills\u002Fautospec-classify\u002Finstall.sh",{"path":79,"resourceType":68,"resourceTypeDesc":69,"sizeBytes":80,"sourceHtmlUrl":81},"opencode\u002Fagent.md",25543,"https:\u002F\u002Fgithub.com\u002Fberlinguyinca\u002Fautospec\u002Fblob\u002Fmain\u002Fskills\u002Fautospec-classify\u002Fopencode\u002Fagent.md",{"path":83,"resourceType":68,"resourceTypeDesc":69,"sizeBytes":84,"sourceHtmlUrl":85},"prompts\u002Fclassifier-contract.md",9190,"https:\u002F\u002Fgithub.com\u002Fberlinguyinca\u002Fautospec\u002Fblob\u002Fmain\u002Fskills\u002Fautospec-classify\u002Fprompts\u002Fclassifier-contract.md",{"path":87,"resourceType":68,"resourceTypeDesc":69,"sizeBytes":88,"sourceHtmlUrl":89},"README.md",4579,"https:\u002F\u002Fgithub.com\u002Fberlinguyinca\u002Fautospec\u002Fblob\u002Fmain\u002Fskills\u002Fautospec-classify\u002FREADME.md",{"path":91,"resourceType":74,"resourceTypeDesc":75,"sizeBytes":92,"sourceHtmlUrl":93},"uninstall.sh",3942,"https:\u002F\u002Fgithub.com\u002Fberlinguyinca\u002Fautospec\u002Fblob\u002Fmain\u002Fskills\u002Fautospec-classify\u002Funinstall.sh",[95,108,117,126,149,172],{"skillNo":96,"name":97,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":98,"categories":99,"keywords":105,"publishedAt":39},"01M71RJHYMKPTC9AAPXWQ6F4RT","trio-pass-skill","https:\u002F\u002Fgithub.com\u002Fberlinguyinca\u002Fautospec\u002Fblob\u002Fmain\u002Ftests\u002Ffixtures\u002Flockstep-trio-pass\u002FSKILL.md",[100],{"categoryNo":101,"categoryName":102,"taxonomyType":103,"taxonomyTypeDesc":104},"01JBSEEDCAT000000000000023","Skill与智能体开发","SCENARIO","使用场景",[106,107],"trio","trio pass skill",{"skillNo":109,"name":110,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":111,"categories":112,"keywords":114,"publishedAt":39},"01M71RJFBQ1KAF9XM3T3Y4VMSK","duo-pass-skill","https:\u002F\u002Fgithub.com\u002Fberlinguyinca\u002Fautospec\u002Fblob\u002Fmain\u002Ftests\u002Ffixtures\u002Flockstep-duo-pass\u002FSKILL.md",[113],{"categoryNo":101,"categoryName":102,"taxonomyType":103,"taxonomyTypeDesc":104},[115,116],"duo pass skill","duo",{"skillNo":118,"name":119,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":120,"categories":121,"keywords":123,"publishedAt":39},"01M71RJDT1TB3P9TRWR6A534FB","duo-divergence-skill","https:\u002F\u002Fgithub.com\u002Fberlinguyinca\u002Fautospec\u002Fblob\u002Fmain\u002Ftests\u002Ffixtures\u002Flockstep-duo-divergence\u002FSKILL.md",[122],{"categoryNo":101,"categoryName":102,"taxonomyType":103,"taxonomyTypeDesc":104},[124,116,125],"duo divergence skill","divergence",{"skillNo":127,"name":20,"nameZh":6,"description":128,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":129,"categories":130,"keywords":134,"publishedAt":39},"01M71RJAC4NNEQSYBDSY3NZS73","Use when the user wants to ship a feature end-to-end across multiple commits — bootstraps repo if missing, brainstorms a design spec, decomposes into linked GitHub issues, or splits an existing spec into issues, then runs an autonomous implementation loop with auto-merge.","https:\u002F\u002Fgithub.com\u002Fberlinguyinca\u002Fautospec\u002Fblob\u002Fmain\u002Fskills\u002Fautospec\u002FSKILL.md",[131],{"categoryNo":132,"categoryName":133,"taxonomyType":103,"taxonomyTypeDesc":104},"01JBSEEDCAT000000000000015","视觉设计",[20,135,136,36,137,138,33,139,32,140,141,142,143,144,145,146,147,29,148,27],"ship a feature","end","design","autonomous","loop","across","design spec","merge","ship","implementation loop","github issues","feature","commits","missing",{"skillNo":150,"name":151,"nameZh":6,"description":152,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":153,"categories":154,"keywords":155,"publishedAt":39},"01M71RJ4F9HT8PT26CKNM9XE1M","autospec-upgrade","Use when the user wants to upgrade an Angular, Next.js, or React project to the latest official versions safely — by locking observable behavior before touching versions, upgrading one major at a time with official codemods, and gating completion on mutation score rather than coverage theater.","https:\u002F\u002Fgithub.com\u002Fberlinguyinca\u002Fautospec\u002Fblob\u002Fmain\u002Fskills\u002Fautospec-upgrade\u002FSKILL.md",[],[156,20,157,158,159,160,161,162,163,32,164,165,166,167,27,168,169,22,170,171],"autospec upgrade","upgrade","mutation","coverage","official","project","time","gating","angular","react","next","at","Next.js","one","behavior","latest",{"skillNo":173,"name":174,"nameZh":6,"description":175,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":176,"categories":177,"keywords":183,"publishedAt":39},"01M71RJ28FJ4PM6DXHB7T5CF8H","autospec-ui-audit","Use when a React Router application needs a deterministic whole-site route inventory before UI, UX, navigation, or evidence auditing begins.","https:\u002F\u002Fgithub.com\u002Fberlinguyinca\u002Fautospec\u002Fblob\u002Fmain\u002Fskills\u002Fautospec-ui-audit\u002FSKILL.md",[178],{"categoryNo":179,"categoryName":180,"taxonomyType":181,"taxonomyTypeDesc":182},"01JBSEEDCAT000000000000032","设计师","PROFESSION","适用职业",[184,20,185,186,187,27,188,189,190,191,192,193,194,195,196,165,197,32,198],"ui audit","audit","autospec ui audit","ui","inventory","evidence","deterministic","route","ux","site","react router","navigation","application","needs","router"]