AGENTS.md · diff

git:20261105.ff8771c to git:20261106.7b51ffd

77 added, 442 removed. Audit A to A.

# Guidelines for AI Agents
This repository distributes the IDD (Issue-Driven Development)
workflow — a portable set of `.github/instructions/` files that
wire up a multi-agent issue-driven pipeline for any GitHub
project.
This file is the canonical, tool-neutral instruction source for AI
coding agents in this repository, following the
[AGENTS.md](https://agents.md) open standard that Codex CLI, OpenCode,
Grok Build, Cursor CLI, and GitHub Copilot (CLI, coding agent, and Chat)
all discover automatically at the repository root. `CLAUDE.md` and
`GEMINI.md` are thin adapters that import this file for Claude Code and
Antigravity CLI (formerly Gemini CLI), the two tools in this
repository's harness mix that read their own dedicated entry file
instead, and
[.github/copilot-instructions.md](.github/copilot-instructions.md)
carries only the small amount of guidance specific to GitHub Copilot's
own UI terminology. See [docs/ai-strategy.md](docs/ai-strategy.md) for
the reasoning behind this layout.
## Conversation
- When asking the user to decide or take a
action, include enough context to understand the request and state the
exact decision or action needed in the same message. If you offer
options, identify the recommended option and the main cost of each.
Keep the ask concise and do not repeat context already present in the same message.
- For user-facing questions about idd-skill decisions, actions, and
clarifications during issue authoring and ordinary IDD execution,
including scope, hold/recovery, and approval questions, assume an
engineer skilled in manual issue-driven development and GitHub Flow
who is unfamiliar with the idd-skill product and its automation
conventions.
- When a question uses an idd-skill-specific term, briefly explain the
meaning or automation constraint needed for that decision. For
example, phase codes describe workflow state; `Candidate files` lists
editable paths; an authoring hold pauses automation; and claim and nonce
evidence helps establish current ownership, together with the required
claim, worktree, token, and revalidation checks. State the exact action
requested. Do not infer product knowledge from the IDD acronym,
technical vocabulary, repeated use, or prior sessions; an explicit
operator request can change the presentation level. This
question-writing rule does not change issue/PR prose or execution
authority, approvals, ownership, CI, or review. The fixed audience
reflects the operator report observed 2026-10-26 in issue `#4743`.
## Minimum requirements
- Match the conversational language to the user's language.
- Write comments and documentation in English unless there is a
clear project-specific reason otherwise.
- When editing `README.md`, also apply the equivalent change to
`README.ja.md`, and vice versa. Keep both files in sync in the
same commit.
- Avoid hard-coded repository file counts in docs unless the
number is mechanically maintained. If count-based wording is
necessary, update every mirrored reference in the same commit.
- When documentation or instruction text names an anti-pattern or
failure mode, cite the observed incident per
[docs/idd-design-rationale.md](docs/idd-design-rationale.md#cite-the-observed-incident).
- Continue autonomously for low-risk work, but pause and ask a
concise question when uncertainty or hidden risk makes the next
step unsafe. When that pause is needed, provide one or more
recommended response options.
- Keep changes small and reviewable. Follow the project's
Conventional Commits rules and keep each commit atomic.
- Do not modify community documents (`CODE_OF_CONDUCT*`,
`CONTRIBUTING*`) without explicit approval.
## Project standards
- **Indentation**: 2 spaces
- **Line endings**: LF only
- **Trailing whitespace**: trimmed except in Markdown
- **Final newline**: always present
- **File naming**: lowercase with hyphens unless a platform
convention requires otherwise
- **Helper sources**: the helper migration to TypeScript is complete —
every `scripts/*.mjs` / `bin/*.mjs` is generated from a
`src/**/*.mts` source by `pnpm run build` and committed; no
hand-written helper `.mjs` path remains. `.mts` is the source of
truth — edit the `.mts`, never the generated `.mjs`.
See [docs/typescript-sources.md](docs/typescript-sources.md).
- **Inline code span wrapping**: a code span may wrap at a word
boundary but must never wrap mid-token (right after a hyphen,
underscore, slash, or dot the token continues through) — CommonMark
renders the break as a literal space and corrupts the token. Put a
command too long for one line in a fenced code block instead. If the
wrap-point character is a hand-added artifact rather than part of
the real value, delete it instead of just relocating the break.
Enforced by `node scripts/audit-code-span-wrap.mjs`
(repository-local; not distributed to `idd-template/`). The same
script also flags this failure mode outside code spans, in prose
Markdown text: a hyphenated compound word (e.g. "transport-layer")
must never wrap right after the hyphen inside `**bold**` / `*italic*`
emphasis, for the same corrupting-space reason (issue `#2876`).
- **Bare issue/PR reference wrapping**: a bare `#NNN` reference must
never be the first token of a paragraph, list item, or wrapped
continuation line in prose Markdown — `dprint fmt`'s automatic
line-wrap can relocate it there, and markdownlint's MD018 rule
(`no-missing-space-atx`) then flags it as a malformed ATX heading.
MD018 only fires at zero leading indentation, so it misses the same
drift inside an indented list-item continuation line — do not rely
on the linter alone. Prefer "issue `#NNN`" (or another phrasing that
keeps a word before the `#`) whenever the reference could plausibly
open a sentence, bullet, or wrapped line.
## Key workflow rules
- `## Branch strategy` and `## Commit rules` below cover those two rule
- sets in full. This section records repository-local dogfood policies
- layered on top of the distributed IDD defaults:
-
- - **Merge policy**: This source repository records
- `fully_autonomous_merge` as an explicit local IDD dogfooding opt-in
- against the distributed `human_merge` default
- (applies only to `kurone-kito/idd-skill`). An IDD session may
- continue through F3 merge execution only after normal claim,
- freshness, CI, advisory, review, and unresolved-thread gates
- pass.
- - **Discover concurrency**: This source repository also records
- `discover.selectionDesync: session-offset` as a local IDD
- dogfooding policy (applies only to `kurone-kito/idd-skill`),
- spreading concurrent-session A4 Step 2 candidate selection across
- a same-score tie band instead of every session converging on the
- same lowest-numbered issue, to cut claim races under this
- repository's heavy concurrent-session load.
- - **Advisory-convergence waiver backstop**: This source repository
- also records `ciGate.externalCheckWaivers.mode:
- "maintainer-authorized"` with `idd-advisory-convergence` registered
- under `ciGate.externalChecks.waivable` as a local IDD dogfooding
- policy (applies only to `kurone-kito/idd-skill`), giving a trusted
- maintainer a human off-ramp when the autonomous advisory-convergence
- loop cannot converge on its own (Refs #1465): once the configured
- convergence deadline (default 24h) has elapsed from when GitHub first
- recorded the current PR HEAD (its earliest check suite), a trusted
- maintainer can post a valid
- external-check waiver for `idd-advisory-convergence` to unblock the
- gate. Treat this the same as any other merge-gate bypass — a
- deliberate, short-lived, maintainer-authorized exception for a
- genuinely stuck check, not a routine substitute for a fresh Copilot
- review. See [Customizing IDD](docs/customization.md) and
- [docs/idd-helper-scripts.md](docs/idd-helper-scripts.md#external-check-waiver-contract)
- for the general mechanism.
- - **Advisory-convergence self-referential-bootstrap-auto waiver**: A
- second, narrower `idd-advisory-convergence` bypass alongside the
- maintainer-authorized one above (Refs #2657): when a PR's own diff
- touches this check's committed bootstrap trigger files (its waiver
- trust path, policy inputs, or workflow files) and none of its
- decision-rule files, a dedicated CI job
- auto-posts a run-bound waiver as `github-actions[bot]`, verified
- against the GitHub Actions runs API and this PR's own changed files
- before it is trusted. Unlike the maintainer-authorized waiver, this
- one is evaluated **unconditionally** — it can make `ready` true
- immediately, with no fresh Copilot review and before the
- convergence deadline elapses — because its whole purpose is
- bootstrapping a fix to the checker (including the deadline mechanism
- itself) while a PR editing it is still unmerged. It exists only for
- that narrow trigger set, never as a general substitute for review.
- A diff that touches one of the check's decision-rule files gets no
- such waiver; it needs a converged review, an approval of its HEAD
- from a `trustedMarkerActors` login, or the maintainer-authorized
- waiver after the deadline or while Copilot is terminally unavailable
- (issue `#4015`). See
- [docs/idd-helper-scripts.md](docs/idd-helper-scripts.md#automated-self-referential-bootstrap-auto-waiver-kurone-kitoidd-skill2657)
- for the full trust model.
- - **ciGate F2 bootstrap**: This source repository follows the
- distributed preload-first procedure in
- [ciGate F2 bootstrap](docs/customization.md#cigate-f2-bootstrap)
- when a new `ciGate.*` key must land before F2 can honor it (observed
- on `kurone-kito/kurone-kito#33` and `kurone-kito/kurone-kito#37`).
- Do not generalize issue `#2657`'s self-referential-bootstrap-auto
- waiver to an arbitrary `ciGate.*` key.
- - **Advisory-convergence deadline**: This source repository also
- records `advisoryWait.convergenceDeadline: "PT9H"` as a local IDD
- dogfooding policy (applies only to `kurone-kito/idd-skill`),
- shortening the maintainer-authorized-waiver deadline from the
- distributed `idd-template/` default (`PT24H`) to fit this
- repository's more autonomous, higher-concurrency dogfooding setup
- (Refs #1465, #2076).
- - **Secondary-bot quiet window**: This source repository also records
- `advisoryWait.secondaryBotLogin: "coderabbitai[bot]"` and
- `advisoryWait.secondaryQuietWindow: "PT5M"` as a local IDD dogfooding
- opt-in (applies only to `kurone-kito/idd-skill`), waiting up to five
- minutes, measured from the last substantive activity, after E-phase
- convergence conditions are first observed before pre-merge readiness
- treats review as settled. The window was first set
- to one hour (`PT1H`, commit `c0909776c`, 2026-09-02) and was shortened
- to five minutes for the reasons in the 2026-10-13 measurement below
- (issue `#4167`). This repository
- dogfoods CodeRabbit alongside Copilot and has twice hit CodeRabbit
- rate-limiting during a PR's review cycle, each time working around
- it with an ad hoc one-hour wait before merging; this config turns
- that informal practice into a proper `pre-merge-readiness` blocker
- (Refs #2335, #2410). As of #2544, the wait is conditioned on live
- review evidence rather than unconditional: once CodeRabbit has
- already posted a genuine (non-rate-limited) review for the current
- HEAD, only a short fixed confirmation buffer applies instead of the
- full wait -- a HEAD CodeRabbit has not yet reviewed still waits the
- full configured window unchanged, keeping the wait a fallback for
- genuine secondary-bot degradation rather than a tax on every merge.
- As of #2547, a definitive decline verdict for the current HEAD -- a
- rate-limit or skip-review notice with no genuine comment after it --
- is checked before that #2544 short-buffer path and completes the
- wait immediately -- zero delay, not even the confirmation buffer:
- once CodeRabbit has conclusively said it will not review this
- commit, #2335's "might still be mid-review" protection has nothing
- left to protect.
- Measured 2026-10-13 (issue `#4167`): of 9 open pull requests, the
- window was the only blocker on none, and it was among the blockers on
- one (pull request `#4154`, 60 minutes remaining after activity at
- 05:49:04Z, plus four other blockers: unresolved threads, missing
- dispositions, a missing watermark, and failing or pending CI). Of 16
- merged pull requests that could be read, the time from the head commit
- to merge had a median of about 27 minutes. CodeRabbit declined (rate
- limit) on 8, reviewed the head on 2, and was silent on 6; silent pull
- requests merged after a median of about 21 minutes, with a maximum of
- 43 minutes. A late CodeRabbit wave does happen: on pull request `#4131`,
- one CodeRabbit event came more than five minutes after its first review
- on the head. The evidence sets the floor: `docs/policy-constants.md`
- records that on pull request `#2330`, findings landed 34 seconds and 2
- minutes after a zero-unresolved snapshot, so a one-minute window would
- have missed that case. A one-minute value was considered and rejected,
- because it would clamp both waits to one minute and the measured evidence
- does not support that. `PT5M` matches the settled buffer
- (`SECONDARY_QUIET_WINDOW_SETTLED_BUFFER_MINUTES`), so one value sets both
- waits to five minutes. The weekly merged-pull-request feedback sweep
- (issue `#4166`, `.github/workflows/merged-pr-feedback-sweep.yml`,
- scheduled Mondays at 06:00 UTC) is the safety net for late reviews that a
- shorter window lets through, and it is already on `main` when this value
- lands.
- - **New-CI-job dispatch-first rollout**: `idd-pr-submit.instructions.md`'s
- D2 "Adding a new CI job" guidance (distributed via `idd-template/`, not
- itself local) requires landing a new CI job `workflow_dispatch`-first.
- This source repository also records, as a local IDD dogfooding policy
- (applies only to `kurone-kito/idd-skill`), the motivation for that
- guidance: this repository's own `copilot_code_review` ruleset, whose
- Copilot/Codex review cost tracks push count roughly 1:1 regardless of
- which CI jobs a push touches -- landing a new job
- `workflow_dispatch`-first does not reduce that review-cost line item
- by itself, but avoids wasted CI Actions-minutes and false-failure
- noise from an unproven job auto-running on every unrelated push. See
- that guidance (and its linked rationale entry) for the mechanics
- rather than duplicating them here. Refs #2892 (non-blocking).
- - **Critique-loop telemetry hook**: This source repository also
- records `critiqueLoop.telemetryHook.command:
- "idd-critique-telemetry"` as a local IDD dogfooding policy (applies
- only to `kurone-kito/idd-skill`). Roadmap #2677 and its children
- issues #2678-#2680 built the `critiqueLoop.telemetryHook` mechanism
- as a distributed, opt-in per-operator feature, but that roadmap's
- own scope stopped at the mechanism and never configured it for this
- repository. Observed 2026-09-14, issue #3001: an in-repo audit found
- `critiqueLoop.delegate` already configured and in genuine, frequent
- use, while C1's own effectiveness at mitigating E-phase Copilot
- review cost -- the purpose `docs/idd-design-rationale.md` documents
- for the critique loop -- had zero observability. The configured
- command is the bare name `idd-critique-telemetry`, not a hardcoded
- absolute path, because this file is committed to a public repository
- and a personal `/home/<user>/...` path would silently fail for any
- other operator or a remote/cloud agent that never reads this
- operator's `$HOME` (preventive; no observed incident yet).
- `idd-critique-telemetry` itself is expected to come from an
- operator's own external tooling (this repository ships the
- `idd-critique-telemetry-hook` resolver that invokes it, never the
- collector binary itself), mirroring how `critiqueLoop.delegate`'s
- configured command already points at an external, not-shipped-in-repo
- binary. Per
- [docs/idd-workflow.md](docs/idd-workflow.md#repository-configurable-critique-telemetry-hook)'s
- fire-and-forget contract, an operator or remote/cloud agent without
- that binary on `PATH` gets a silent no-op, the same as leaving the
- hook unconfigured, rather than a failure.
- - **Gist-retrospective field-feedback label**: this repository applies
- the `feedback:idd-core` label to every "IDD loop field-feedback
- intake" gist-retrospective roadmap (title beginning with `roadmap:
- IDD loop field-feedback intake`) and every child issue linked from
- its `## Tracks` list, at authoring time alongside the normal
- `status:authoring` hold label. The label is visibility-only -- it
- lets a maintainer find and review these issues with extra scrutiny,
- since they originate from second-hand narrative gist material about
- another repository rather than a locally reproduced observation --
- and it must never gate Discover, Claim, or any other autopilot
- phase. It is a distinct axis from the adopter-side
- `status:upstream-candidate` label (roadmap `#2700`): that label
- stays local to each adopter repository and is never applied in
- `kurone-kito/idd-skill` itself; `feedback:idd-core` is the
- source-repo-side counterpart applied once the maintainer has already
- decided to report the observed problem here.
- - **Adopt-now urgency defer**: This source repository also records
- `critiqueLoop.deferByUrgency: "severity-tiered"` as a local IDD
- dogfooding policy (applies only to `kurone-kito/idd-skill`).
- `low` and `low-and-medium` still never defer High.
- `severity-tiered` scores urgency `very-low` < `low` < `medium` <
- `high` and, below both the first threshold and the
- review-count cap, defers High only at `very-low` (issue `#3589`).
- At review count 3, below the first threshold 4 but at the cap, the
- cap defers otherwise-unblocked High findings at every urgency;
- safety-class findings and other block reasons retain their verdicts.
- The gradient acts only when
- `deferByUrgency` is `severity-tiered`. This repository opts in
- with `critiqueLoop.deferRelaxAtRounds: [4, 7]`. Over the 100
- merged pull requests numbered #3561 to #3781 (merged 2026-09-27
- to 2026-10-05), the median PR-wide Copilot review count was 2,
- and 30 reached a 4th review, 25 a 5th, 14 a 7th and 10 a 9th, so
- the first threshold leaves a typical pull request unchanged and
- the second acts only on the long tail. With the cap at 3, these
- thresholds act only through the converged extra step at review counts
- 1 and 2. A follow-up filed by the
- gradient carries the existing `review-fix-loop-cutoff` marker.
- The motivating observation is
- [kurone-kito/setup.ubuntu#201](https://github.com/kurone-kito/setup.ubuntu/issues/201).
- The earlier opt-in was `low-and-medium` (issue `#3222`): a 60-PR
- baseline (`#3089`-`#3210`) found all 11 Low-only reviews and 25
- Medium-highest reviews followed by another Copilot review wave.
- As of the 2026-09-24 observation,
- `critiqueLoop.deferAfterRounds` (this repository's own local
- `5`) had never fired because most review waves happened well
- before that round threshold. A later count over the same #3561
- to #3781 range found that 25 of 100 pull requests reached a 5th
- Copilot review, and none of the 7 deferral replies in that range
- carries a `round <r>/5` clause. See
- [docs/idd-design-rationale.md](docs/idd-design-rationale.md#e4e5-adopt-now-urgency-defer)
- for the baseline and the severity-tiered matrix.
- - **Review-count cap**: This source repository sets
- `critiqueLoop.deferAllAfterRounds: 3` only for
- `kurone-kito/idd-skill`; `idd-template/` leaves the field unset (cap
- off). Under `critiqueLoop.deferByUrgency: "severity-tiered"` and
- outside Lite, a scored PATH A finding at or above the PR-wide
- Copilot review-count cap defers at every urgency unless it is
- safety-class or another documented block reason applies; adopt-now
- condition (d) does not turn the verdict into `keep`. The cap acts
- regardless of whether `deferRelaxAtRounds` is configured. See the
- [Review-count cap paragraph](docs/idd-review-policy-profiles.md#wave-gradient-urgency-defer).
- Evidence measured 2026-10-27 across at least 1,777 Copilot reviews
- on 464 pull requests (only the first 100 reviews per pull request,
- so review counts are lower bounds): caps 2, 3, 4, and 5 would have
- removed at most 1,004, 806, 659, and 547 counted reviews
- (56.5%, 45.4%, 37.1%, and 30.8% of reviews; 73.4%, 62.8%, 53.1%,
- and 44.7% weighted by changed lines). Those shares are upper bounds
- over the lower-bound counts, assuming no review after each cap.
- With `deferRelaxAtRounds: [4, 7]`, at counts 3 and above findings
- either defer through the cap or remain kept by an existing block,
- so the relax steps change no verdict. The thresholds act only
- through the converged extra step at counts 1 and 2.
- `deferAfterRounds: 5` still acts on Lite-profile claims because the
- cap is off there. With `triageRecord: "enforce"`, an Accepted reply
- whose otherwise-unblocked verdict is `defer` needs
- `--override "<reason>"`; existing block reasons retain their verdict
- and do not need an override. The weekly audit records a reply with the
- override as an override. Remove `critiqueLoop.deferAllAfterRounds`
- to opt out.
- - **Triage record opt-in**: This source repository sets
- `critiqueLoop.triageRecord` to `"enforce"` as a local IDD dogfooding
- policy (applies only to `kurone-kito/idd-skill`), switched under issue
- `#4208` from the `"record"` value set by pull request `#4508` (issue
- `#4461`), merged 2026-10-18; `idd-template/` keeps the distributed
- default `"off"`, so adopters are unchanged. The opt-in was first
- deferred because `advisory-convergence` printed
- `resolve-review-thread --apply` pointers without the `--tier` and
- `--urgency` flags that `record` requires for an Accepted or Rejected
- reply, so `resolve-review-thread` refused those pointers. Observed
- 2026-10-16 on pull request `#4405` (Copilot discussion `r4288841711`).
- Pull request `#4500` (issue `#4481`), merged 2026-10-18, made
- `advisory-convergence` add both flags to those pointers when the value
- is `record` or `enforce`, which unblocked the opt-in. With `record` or
- `enforce`, `resolve-review-thread` requires `--tier` and `--urgency` on each
- applied Accepted or Rejected PATH A reply, except a `--path-b` reply or
- a `**Rejection confirmed by maintainer**` reply. The helper writes a
- `Triage:` line for
- each reply that carries both flags, in any mode. The reason for the
- switch: `record` posts an Accepted reply whose verdict is `defer`, and
- the weekly review-policy audit counts each one as a recorded triage
- contradiction. The scheduled run of 2026-10-26 (
- [run `40284373227`](https://github.com/kurone-kito/idd-skill/actions/runs/40284373227))
- failed with `5 recorded triage contradiction(s)`. The scheduled run of
- 2026-10-19 (
- [run `39214309218`](https://github.com/kurone-kito/idd-skill/actions/runs/39214309218))
- failed on parser drift that pull request `#4543` fixed, so it does not
- count toward the switch. With `"enforce"`, an applied (`--apply`)
- Accepted reply whose verdict is `defer` is refused by
- `resolve-review-thread` unless `--override "<reason>"` gives a reason.
- Replies posted without the helper are not covered. This applies here
- because `critiqueLoop.deferByUrgency` is
- `"severity-tiered"`; under any other mode the helper treats `enforce`
- as `record`. To opt out, set the field back to `"record"` or `"off"`,
- or remove it. Evidence for the `record` opt-in: among the 100
- pull requests that were merged at or before 2026-10-13T06:58:55Z and
- are numbered `#3936` to `#4158`, six
- deferral-form replies appeared on four pull requests, and one of 535
- review-thread replies that begin with `**Accepted**` or `**Rejected**`
- recorded an urgency. Two conversation replies, on `#3966` and `#4044`,
- also recorded urgencies, outside that count (item 2 of the subsection).
- See the
- [review-loop audit (2026-10-13)](docs/idd-design-rationale.md#review-loop-audit-2026-10-13)
- subsection of the design rationale.
- - **E10 converged-review opt-in**: This source repository sets
- `critiqueLoop.e10SkipOnAdvisoryConvergence` to `true` as a local IDD
- dogfooding policy (applies only to `kurone-kito/idd-skill`, opted in on
- 2026-10-27; issue `#4761`). `idd-template/` keeps the distributed default
- `false`, so adopters are unchanged. On the standard profile, a review-fix
- batch whose Accepted PATH A items all come from `advisoryBotLogins` bots
- other than the primary advisory bot skips E10 once advisory-convergence has
- converged on the pushed head. The lite profile always runs E10. Evidence,
- from the pull requests that received Copilot reviews from 2026-10-01 to
- 2026-10-26 and measured on 2026-10-27 (lower bounds, because at most 100
- reviews per pull request were read): of at least 1,311 Copilot re-reviews
- of a new head, 112 followed a Copilot review with no inline comment and a
- Codex or CodeRabbit review of that same earlier head, and in 103 of those
- the Codex or CodeRabbit review had an inline comment. The trade-off
- (preventive; no observed incident yet): a defect that E10 would have found
- before the push is found after it, by Copilot or by E2, and its fix costs
- another push. Turn the opt-in off when a Copilot or other advisory bot
- finding on a later head points at a fix commit of a skipped batch. Find
- that batch through the `E10 critique skipped` sentence in its E13 replies.
- E2 findings stay in the session and are not posted, so they are not a
- signal. Removing the field or setting it to `false` restores E10 for every
- batch.
- - **Effort L refusal opt-in**: This source repository also records
- `autopilotSuitability.effortL: "refuse"` as a local IDD dogfooding
- policy (applies only to `kurone-kito/idd-skill`); `idd-template/` keeps
- the distributed default `"allow"`, so adopters are unchanged. With
- `refuse`, `audit-authored-issue` fails an orphan or child body whose
- effort is `L` (check `effort-l-ready`) unless it is routed to a human
- bucket, and autopilot Discover routes an effort `L` orphan to a human.
- To turn this off, remove the field or set it to `"allow"`. Evidence: in
- the same 100-pull-request cohort as the bullet above, 6 of the 8 pull
- requests whose issue has effort `L` reached 7 or more Copilot reviews,
- against 2 of the 33 pull requests with effort `S`. The `L` group is only
- 8 pull requests. The subsection does not separate pull request size from
- effort: changed lines and Copilot review count have a Spearman correlation
- of 0.57 over the cohort, and the 20 pull requests with 7 or more reviews
- have a median of 967.5 changed lines, against 122.5 for the 64 with at
- most 3 (item 5). Item 7 gives the effort groups. See the
- [review-loop audit (2026-10-13)](docs/idd-design-rationale.md#review-loop-audit-2026-10-13)
- subsection of the design rationale.
- - **GitHub API load control**: This source repository also records
- `githubApi.loadControl: { enabled: true, maxConcurrent: 4 }` in
- `.github/idd/config.json` as a local IDD dogfooding policy (applies
- only to `kurone-kito/idd-skill`); `idd-template/` keeps the distributed
- default off, so adopters are unchanged. Roadmap `#3583` dogfoods each
- delivered capability here first, and this repository runs many
- concurrent sessions as one OS user, the case the host-local admission
- layer is for (motivating episode: the 2026-09-27 GraphQL rate-limit
- report in issue `#3560`; most of the failing commands it lists were
- typed by an agent, which load control does not cover). The value was
- measured, not guessed (issue `#3702`, 2026-10-01): four parallel
- `discover-roadmap-graph --all-roadmaps --with-claim-state
- --with-readiness --with-progress --no-cache` scans (each at its own
- `--concurrency` of 8) against a fresh state directory per row took, at
- `maxConcurrent` 8, 4, 2 and 1, a slowest scan of 9.9, 14.5, 23.1 and
- 43.7 seconds, all sixteen scans exited 0 and none reported a `deadline`
- interruption. The smallest value within twice the 8 row (19.8
- seconds) is 4, so that is the cap; the full table is in the PR that
- enabled it. Exposure: a write or unclassified request that meets a
- full slot is refused at once with nothing sent, and a read that waits
- out `maxWait` (`PT30S` by default) with every slot held is refused
- too, which a scan reports as a `deadline` interruption; a standard
- Discover scan, which passes no `--with-progress`, surfaces that
- refusal as an error instead of a recovery result. To turn it off,
- remove the `loadControl` entry or set `enabled` to `false`; a refused
- request (`notDispatched`) in a real session is the signal to do so
- (preventive; no observed incident yet).
- See [docs/idd-helper-scripts.md](docs/idd-helper-scripts.md#github-api-load-control)
- for the mechanism.
- - **Local validation admission**: On non-Windows hosts, this repository uses
- the Pueue group `idd-skill-validate` with a cap of `2` when the daemon is
- available. The helper creates a missing group with that cap and warns while
- preserving an existing group with a different cap. If Pueue is unavailable,
- it falls back to serial `flock`. On Windows, the helper keeps its existing
- direct-run behavior. While Pueue is available, this repository's Pueue group
- is separate from the shared `flock` admission domain used by other
- repositories. If Pueue is unavailable, this repository's fallback joins
- that shared `flock` domain. This repository-only choice adds no daemon start
- or shutdown and no group resizing. It follows the lock inheritance fix for
- issue `#5036` in PR `#5038`.
+ This section records source-repository dogfood policies that extend the
+ distributed defaults. Supporting context and measurements are in
+ [Repository policy evidence](docs/repository-policy-evidence.md).
+ `## Branch strategy` and `## Commit rules` below cover those rule sets in
+ full.
- - **Orchestrator worker cap**: This source repository also records
- `orchestrator.maxWorkers: 4` in `.github/idd/config.json` as a local IDD
- dogfooding policy (applies only to `kurone-kito/idd-skill`);
- `idd-template/` keeps the distributed default of 2, so adopters are
- unchanged. The value is measured, not guessed: over the 100 pull requests
- merged from 2026-09-29 to 2026-10-07 (`#3608` to `#3815`), the number of
- pull requests open at once had a median of 2, a 90th percentile of 4, and a
- maximum of 9. The cap is per orchestrator session, so concurrent
- orchestrator sessions multiply it, and only the host and GitHub API checks
- in `idd-worker-budget` (load, memory, and REST or GraphQL rate-limit
- headroom) limit the total. To opt out, remove the
- `orchestrator` field and the `orchestrator-worker-cap-dogfood` rule together,
- because the rule pins the value to exactly 4 and the field alone is not
- enough (refs `#3839`).
- - **Live status digest**: This source repository does not use a live
- status digest. This is the operator's recorded choice (option 2,
- decided in an issue-authoring hearing outside this repository; see
- issue `#4736`). The recorded choice overrides the auto-detection in
- the [Live Status Digest Contract](docs/idd-comment-minimization.md#live-status-digest-contract),
- which applies only when neither the operator nor the repository has
- chosen. The per-run summary is no longer posted, and the A5 claims on
- issues `#4468`, `#4502`, and `#4721` already ran without a digest
- (checked 2026-10-28). Existing digests are not edited, and the digest
- helper stays available for explicit use. This bullet replaces the
- earlier digest-use statement from PR `#4527`. `idd-template/` is
- unchanged, so adopters keep the distributed behavior.
- - **Provisional decision opt-in**: This source repository sets
- `dangerouslyAutoDecide: true` in `.github/idd/config.json` as a local
- IDD dogfooding policy (applies only to `kurone-kito/idd-skill`).
- `idd-template/` leaves the field unset, so adopters keep the default
- `false`. PR `#4897` set the flag, merged 2026-11-01. At a hearing the
- same day, recorded in roadmap `#4955`, the operator chose to keep it
- and to use the feature actively for dogfooding. As of 2026-11-03 no
- code reads the flag for behavior; the execution children of
- roadmap `#4528` (issues `#4533`, `#4535`, `#4538`, and `#4539`) and
- its transition helper (roadmap `#4722`) will. Roadmap `#4955` adds a
- repository-only switch for each class of stop. Once those switches
- exist, the flag alone starts no new provisional work, because a class
- acts only when its own switch is also `true`. The gates that
- roadmap `#4528` lists stay in force: the flag supplies no credential,
- permission, approval, or scope expansion, and waives no CI, review,
- standing reviewer, claim or ownership, security, destructive-operation,
- branch, effort, or authoring-release gate. The only exceptions are the
- two that roadmap `#4528` records for the worktree-remnant and
- B1-leftover classes: while that class's own switch is on, it may act
- on a claim, ownership, or destructive-operation stop, and only through
- a remedy that first saves everything (a stash, a backup ref, or a
- preserve directory) before it removes anything. This repository
- departs on purpose from the adopter advice in
- [Provisional Decision Opt-in](docs/customization.md#provisional-decision-opt-in),
- which says to keep the flag absent or false until the complete
- lifecycle is available and the repository has opted in; that advice
- stays for adopters. To opt out, set `dangerouslyAutoDecide` to `false`
- in `.github/idd/config.json`, or remove the field, which then defaults
- to `false`.
- The five auto-decide classes of roadmap `#4955` are on as well, under
- `autoDecide` in `.github/idd/config.json`: `decisionIssue`, `runtimeQuestion`,
- `authoringChoice`, `worktreeRemnant`, and `b1Leftover`. The four classes other
- than `decisionIssue` file a confirmation issue labeled
- `status:needs-confirmation` for the operator to review afterward.
- `decisionIssue` confirms its pickup choices on the needs-decision source issue
- instead. No other auto-decide class is defined, so none stays disabled. The
- cap and the quiet window keep their defaults. The hearing left these stops in
- force: safety and ownership stops (claim conflict or loss, wrong base branch);
- authority stops (a CODEOWNER or required reviewer, `human_merge`, credentials,
- authoring release); quality gates (CI, review threads, advisory convergence);
- waits (rate limits, quiet windows); and scope or suitability rejections. The
- worktree-remnant and B1-leftover classes replace two fail-closed defaults once
- their consumers land: the §LWR operator attestation and the B1 manual-cleanup
- stop. Each saves the data before it removes anything, to the stash tagged
- `idd-lwr <claim-id>`, the backup refs `refs/idd-lwr/<branch>` and
- `refs/idd-b1/`, `<state>/idd-skill/lwr-preserved/`, or
- `<state>/idd-skill/b1-preserved/` (preventive; no observed incident yet). Turn
- a class off when a confirmation issue is answered with a different choice, or
- when a removed worktree turns out to be in use. To opt out, set a class's
- `enabled` to `false` or remove `autoDecide`. The hearing was held on
- 2026-11-01 and is recorded in roadmap `#4955`.
+ - **Merge policy**: Autonomous merging is enabled only after all normal
+ claim, freshness, CI, advisory, review, and unresolved-thread gates pass;
+ see [evidence](docs/repository-policy-evidence.md).
+ - **Discover concurrency**: A4 Step 2 selection spreads across a same-score
+ tie band with `discover.selectionDesync: session-offset`; see
+ [evidence](docs/repository-policy-evidence.md).
+ - **Advisory-convergence waiver backstop**: A trusted maintainer may issue
+ a short-lived waiver for genuinely stuck convergence after the configured
+ deadline; it does not replace review. See
+ [evidence](docs/repository-policy-evidence.md).
+ - **Self-referential bootstrap waiver**: A narrow bootstrap-only waiver may
+ mark readiness immediately without Copilot review when trigger files, but
+ no decision-rule files, change. See
+ [evidence](docs/repository-policy-evidence.md).
+ - **ciGate F2 bootstrap**: New `ciGate.*` keys use the preload-first
+ procedure; do not generalize the self-referential waiver. See
+ [evidence](docs/repository-policy-evidence.md).
+ - **Advisory-convergence deadline**: This repository sets the maintainer-
+ authorized waiver deadline to `PT9H`; the distributed default is
+ `PT24H`. See [evidence](docs/repository-policy-evidence.md).
+ - **Secondary-bot quiet window**: Wait `PT5M` after last substantive
+ activity; a current-head CodeRabbit review uses the fixed `PT5M` settled
+ buffer, and a definitive decline ends the wait immediately. See
+ [evidence](docs/repository-policy-evidence.md).
+ - **New CI job rollout**: Land new CI jobs with `workflow_dispatch` first
+ to avoid running unproven jobs on unrelated pushes. See
+ [evidence](docs/repository-policy-evidence.md).
+ - **Critique telemetry hook**: The configured `idd-critique-telemetry`
+ hook is fire-and-forget; absent external tooling is a silent no-op. See
+ [evidence](docs/repository-policy-evidence.md).
+ - **Gist-retrospective feedback label**: Apply `feedback:idd-core` to
+ qualifying roadmaps and tracked children for visibility only; it never
+ gates phases, and `status:upstream-candidate` remains adopter-side. See
+ [evidence](docs/repository-policy-evidence.md).
+ - **Adopt-now urgency defer**: With `severity-tiered` and relax rounds
+ `[4, 7]`, otherwise-unblocked High findings defer only at `very-low`
+ urgency below the cap and first threshold; safety and other blocks remain.
+ See [evidence](docs/repository-policy-evidence.md).
+ - **Review-count cap**: Standard-profile PATH A findings defer at every
+ urgency at or above `critiqueLoop.deferAllAfterRounds: 3`, unless a
+ safety or other block reason applies; Lite keeps `deferAfterRounds: 5`.
+ See [evidence](docs/repository-policy-evidence.md).
+ - **Triage record**: With `severity-tiered`, an applied Accepted reply
+ whose otherwise-unblocked verdict is `defer` needs `--override`. See
+ [evidence](docs/repository-policy-evidence.md).
+ - **E10 converged-review opt-in**: A converged standard-profile batch
+ accepted only from non-primary advisory bots may skip E10; Lite always
+ runs it. See [evidence](docs/repository-policy-evidence.md).
+ - **Effort-L refusal**: Autopilot routes effort-L orphans and authored
+ effort-L issues to humans; roadmap children are not demoted. See
+ [evidence](docs/repository-policy-evidence.md).
+ - **GitHub API load control**: This repository sets
+ `githubApi.loadControl.maxConcurrent: 4`; a real `notDispatched` refusal
+ is the signal to opt out. See
+ [evidence](docs/repository-policy-evidence.md).
+ - **Local validation admission**: Use the `idd-skill-validate` Pueue
+ group at cap 2 when available, otherwise serial `flock`; Windows runs
+ directly. This repository does not manage the daemon or resize groups.
+ See [evidence](docs/repository-policy-evidence.md).
+ - **Orchestrator worker cap**: This repository sets
+ `orchestrator.maxWorkers: 4` per session; remove both the setting and
+ enforcing dogfood rule to opt out. See
+ [evidence](docs/repository-policy-evidence.md).
+ - **Live status digest**: This repository does not use live status digests;
+ leave existing digests untouched and use the helper only by explicit
+ request. See [evidence](docs/repository-policy-evidence.md).
+ - **Provisional decision opt-in**: `dangerouslyAutoDecide` and all five
+ classes are enabled. Only `worktreeRemnant` and `b1Leftover` may resolve
+ claim, ownership, or destructive-operation stops after saving state;
+ every other safety, authority, quality, wait, scope, branch, effort, and
+ authoring-release gate remains. See
+ [evidence](docs/repository-policy-evidence.md).
## Branch strategy
This project follows
[GitHub Flow](https://docs.github.com/en/get-started/using-git/github-flow):
`main` is the only long-lived branch and every change reaches `main`
through a pull request.
### Rules
- **Never push directly to `main`** — all changes must go through a
pull request. Branch protection is enforced on GitHub.
- **Rebase onto `main` before publication** — before the first D-phase
push of a PR branch, rebase onto `main` as needed. Fetch first so the
local `main` is not stale, e.g.
`git fetch origin && git rebase origin/main`
(or `git pull --rebase origin main`). Do not create merge commits
inside unpublished feature branches.
- **Treat pushed PR branches as published review history** — after the
first D-phase push, branch-state checks stay read-only until a later
phase decides an update is required.
- **Default post-push sync: merge `main` into the PR branch** — before each
E12 review-fix push, E11 merges `main` when behind so the sync rides
with that push; E11 does not make a standalone push (#4759). Esync can
still push its standalone sync when branch protection or policy
requires an up-to-date head; that push goes through normal CI and
review gates.
Do not rebase or force-push merely because the PR is `BEHIND`. This
active branch-policy contract is enforced end to end by
`idd-review-triage.instructions.md`'s E-phase branch-sync check
(`Esync`), which uses the `branch-conflict-state` helper when helper
runtime is enabled.
- **Force-push exceptions stay narrow** — use rebase and
`--force-with-lease` after publication only when repository policy
explicitly permits it and merge-based recovery cannot safely fix the
branch, or when an already-started rebase must be completed or
aborted during recovery.
- **Rebase between unpublished feature branches** — if one unpublished
feature branch needs changes from another, use rebase, not merge.
- **Merge commits at PR boundary** — pull requests into `main` are
merged with a merge commit (squash-merge and rebase-merge are
disabled in the repository settings).
- **fixup + autosquash for unpublished in-branch fixes** — when a later
commit in an unpublished feature branch fixes an earlier one, prefer
`git commit --fixup=<sha>` followed by
`git rebase -i --autosquash` to fold the fix into its target.
- **Avoid giant commits** — if squashing would produce an
unreasonably large commit, keep the fix commit separate or
re-split the history so each commit remains reviewable.
## Commit rules
This project follows
[Conventional Commits](https://www.conventionalcommits.org/).
A `.gitmessage` template is available at the repository root for
guidance when writing commit messages. Git does not use it
automatically, so contributors who want the template prefilled in
their editor should opt in once per clone:
```sh
git config commit.template .gitmessage
```
### Format
```txt
<type>[optional scope]: <user-facing description>
<body: address purpose, context, and what changed>
[optional footer(s)]
```
### Subject line
- Use the format: `<type>[optional scope]: <description>`
- Write from the **user's perspective** — briefly state what this
commit solves or improves for the end user or developer
- Write in **lowercase**, imperative mood (e.g., "add", not "added")
- Keep the subject line under **72 characters**
- Do **not** end with a period
### Types
Common types: `feat`, `fix`, `docs`, `style`, `refactor`, `test`,
`chore`, `ci`, `build`, `perf`
### Scopes
- Optional, in parentheses: `feat(ci):`, `fix(lint):`, `docs(readme):`
- Keep scopes **lowercase**, short, and consistent
- Use the directory or component name that best describes the area
### Body (line 3+)
The body should address three aspects:
- **Why** — the purpose or motivation behind the change
- **Context** — what was needed, the situation or constraint
- **What changed** — the concrete action taken
Prefer the **why → context → change** order when practical.
Write these as **natural prose** — weave the aspects into
coherent sentences rather than using labeled sections. Labeled
sections (`Why:` / `Context:` / `Change:`) are acceptable only
when explicit paragraph separation improves clarity.
Omit any aspect whose information **cannot be reliably inferred**.
If the subject line is self-explanatory, the body may be omitted
entirely. **Breaking changes must always include a body.**
Wrap body lines at **72 characters**.
- **Avoid a bare `token:` line start**: a body line must not begin
with a single (optionally hyphenated) token immediately followed by
a colon and a space — for example a line starting `bullet: ...` or
`Step-1: ...`. `@commitlint/config-conventional`'s footer/trailer
parser misreads that shape as the start of a footer section, even
though it is ordinary prose deep in the body, and emits a spurious
`footer-leading-blank` warning — a **warning** under this
repository's current `.commitlintrc.yml`, not a blocking failure,
but still worth avoiding. This does not conflict with the `Why:` /
`Context:` / `Change:` labels above: each one only ever opens a
fresh, blank-line-separated paragraph, so the blank line already
required before it also satisfies `footer-leading-blank`; the trap
here is the same shape appearing **without** a preceding blank
line, buried mid-paragraph. Reword instead: lead with an article or
an extra word (for example "the bullet: ..." or "in step 1: ...")
so the line no longer opens with a bare token before the colon.
Observed 2026-09-12, live against this repository's own
`.commitlintrc.yml`, in commit
`bae5e0f1e43b54713f936af6f677773b684dd81e` (PR `#2942`, issue
`#2943`).
### Breaking changes
- Append `!` after the type/scope: `feat!: remove deprecated endpoint`
- Add a `BREAKING CHANGE:` trailer in the footer with a detailed
explanation of what breaks and migration steps
### Footers / trailers
- `Closes #<issue>` / `Refs #<issue>` — link to issues
- `Co-authored-by: Name <email>` — credit co-authors
- `BREAKING CHANGE: <description>` — detail the breaking change
### Atomic commits
Keep each commit as **small and focused** as possible:
- **One logical change per commit** — if the subject line needs "and",
consider splitting
- **Separate refactoring** from behavior changes
- **Separate formatting/style** changes from logic changes
- **Separate dependency updates** from code changes
- When in doubt, prefer smaller commits that are easy to review,
revert, and bisect
### Examples
#### Good — single-line (trivial change)
```txt
fix: correct typo in feature request template
```
#### Good — prose body
```txt
feat(ci): add concurrency settings to lint workflow
Parallel lint runs on the same branch waste resources and
cause race conditions in status checks. GitHub Actions
supports concurrency groups that automatically cancel
redundant runs, so add a concurrency group keyed on branch
name with cancel-in-progress enabled.
Refs #42
```
#### Good — breaking change
```txt
feat!: require node 20 as minimum version
Node 18 reached end-of-life in April 2025 and no longer
receives security updates, while the project now standardizes
on the active Node 20 LTS baseline. All production
environments have already been upgraded to node 20+, so
update the engines field and CI matrix to require node >= 20.
BREAKING CHANGE: drop support for node 16 and 18. Users
must upgrade to node 20 or later.
Closes #108
```
#### Bad — vague, developer-centric
```txt
fix: update code
```
#### Bad — too large / non-atomic
```txt
feat: add auth system and refactor database layer and update docs
```
## Local Linux CI with nektos/act
`pnpm run ci:act` runs three of this repository's Linux pull-request CI
jobs locally through [nektos/act](https://github.com/nektos/act), so a
problem can be caught before a push. It is opt-in and repository-local:
it is not part of `commands.pre-push-validate` or any other command set,
and it is not distributed through `idd-template/`.
```sh
pnpm run ci:act
```
Run it from a clone or from a linked worktree. The script tests the
working tree as it stands: act copies the tree into the container, so
uncommitted changes and untracked files that are not ignored are tested
too, not only the commit.
Prerequisites:
- act (tested with act 0.2.89) and a running Docker daemon.
- A clone whose git common directory is owned by uid and gid 1000:1000.
The script checks this and stops with a message otherwise. The jobs run
as the image's `node` user, which has a writable HOME. The script uses
GNU `stat -c`, so it needs Linux or WSL.
- Network access when the image is absent locally, to pull it, and when
an action is not yet cached, to fetch it. The two `pnpm-boundary` jobs
install pnpm and Node at run time, so they need network on every run.
- A warm pnpm store or network access for the config-dependency install
that the first `pnpm run` in a fresh clone or worktree performs.
- A local `origin/main` ref. `node scripts/audit-docs.mjs` diffs against
it, because act's default event carries no base. Fetch it first with
`git fetch origin main`.
Each job runs in the image `node:24.21.0-trixie`, selected by tag rather
than by digest. `--pull=false` pulls only when the tag is absent locally;
a local copy with the tag is used as it is. The full tag is used rather
than the `-slim` variant, because the slim image has no `git`; a
local 2026-10-27 check found `git` missing from the slim image and present
in the full tag. The script runs these jobs in order and stops at the first
failure:
- `lint`: the bare-Node lane, which runs the audits and the protocol
tests with no dependency installed.
- `pnpm-boundary`: the aggregate job (issue `#4993`). act runs the jobs it
needs first. In this repository they are the four `pnpm-boundary-group`
shards (`lint`, `typecheck`, `test`, and `distribution`). Each shard runs
`pnpm install --frozen-lockfile --prefer-offline` with `HUSKY=0`, then
its own `pnpm run check` groups, and the `distribution` shard also runs
`node scripts/check-pnpm-boundary.mjs`. When act does not resolve the
repository as `kurone-kito/idd-skill`, the `pnpm-boundary-full` job runs
the whole suite instead. Neither path has been replayed under act yet.
- `pnpm-boundary-node22-floor`: the same reusable workflow on the Node
version set by its `node-version` input. It is the only one of the three
jobs that covers Node 22.
Compared with `commands.pre-push-validate`, the script adds the
bare-Node run with no installed dependency, the frozen-lockfile install
with the pnpm boundary check, and the Node 22 floor run. The pre-push
command set performs none of those.
The lint job's protocol-tests step can fail when the host is under heavy
load, because some tests use wall-clock limits: a 2000 ms limit in
`tests/resume-route-selection.test.mts` and a 700 ms read budget in
`tests/provider-outage-park-read-runtime.test.mts`. Local act runs of this
change on 2026-10-27 hit this failure, as recorded in pull request `#4773`.
Rerun the job on a quieter host before treating such a failure as a code
defect.
A linked worktree mounts the git common directory read-only at the same
path, so the checkout inside the container can read the worktree's git
metadata. The 2026-10-27 probe recorded in issue `#4756` found that the
worktree's git directory path is absent in the container without the
mount. A clone needs no extra mount. The job uid matches the owner of the
common directory, so git accepts the mounted repository without a
`safe.directory` setting. For a linked worktree, the common directory's
path must contain no spaces or colons, because the mount is passed to act
and docker inside an option string.
The container runs with `--init`. Without an init process, the container
that act starts keeps a killed child process as a zombie, so a liveness
check still sees the process. On 2026-10-27, in local runs of this change
recorded in pull request `#4773`, two tests in
`tests/idd-critique-telemetry-hook.test.mts` failed in two runs without the
flag: one waits for a hung hook to be killed, the other for a backgrounded
descendant to be killed. They passed in a third run with the flag. A
container whose PID 1 was a plain `tail -f` process reproduced the same two
failures on the same day, and `--init` cleared them.
The jobs the script does not run, and why:
- `idd-doctor`: its checkout pins the commit under test. A 2026-10-27
probe showed act downloading that commit from GitHub, so the job checks
the pushed commit, not the local tree. `commands.pre-push-validate`
runs the same check on the local tree through `pnpm run doctor:github`.
- `lint-windows`: act's Docker containers cannot provide a Windows
runner (preventive; no observed incident yet).
- `analyze`: CodeQL uploads its results to code scanning with
`security-events: write` (preventive; no observed incident yet).
- `idd-advisory-convergence` and the workflows that review, comment,
label, or merge: they read or write GitHub state, so
a local run would act on that state (preventive; no observed incident
yet).
The image sets no user, so a container would run the jobs as root, and
root ignores the POSIX permission bits that some tests rely on. The
script therefore passes `--user 1000:1000`. In the 2026-10-27 probe, the
grok test in `tests/token-cost-adapter-grok.test.mts`, which reads a file
with mode `000`, failed as root in `node:24.21.0-trixie-slim` with
`2 !== 1`, and passed as uid 1000. Other test files, such as
`tests/idd-config.test.mts` and
`tests/token-cost-event.test.mts`, depend on the same bits. Some of them
skip rather than fail as root, so a root run would lose their coverage
without any failure. The uid is part of the design, not a convenience.
## For IDD work
Open `.github/instructions/idd-overview-core.instructions.md` and the
relevant phase file before starting work. See
[docs/idd-workflow.md](docs/idd-workflow.md) for the cross-agent
entry path and phase routing. See
[Model capability expectations](docs/idd-workflow.md#model-capability-expectations)
before running this loop on a lightweight local or compact cloud model.
## Dogfood: token-cost events
This source repository records IDD phase-boundary timestamps as a local
dogfooding measurement (`docs/token-cost.md`). Source-repo only — never
add this call to `idd-template/` or `.github/instructions/` phase files,
which distribute to adopters with no token-cost data to record.
When running the IDD loop in this repository, call
```sh
node scripts/token-cost-event.mjs --stage <id> --enter --vendor <v> --issue <n>
```
when a listed stage starts, and the same with `--exit` when it ends,
using `--vendor codex` for Codex CLI or `--vendor grok` for Grok Build.
Include `--issue <n>` on every call from `claim` onward, once an issue
is claimed — omit it only for `discover`, which precedes any claim. A
call with no `--issue` is unusable for per-issue attribution (#2418):
the harvester can only join it back to an issue when the number is
recorded on the event itself. Also include `--claim-id <claim-id>` —
the active IDD `{claim-id}` — on every call from `claim` onward: it is
the positive-evidence signal a later harvest uses to merge a genuine
cross-session handoff/resume of the same claim lineage instead of
undercounting it (#2432). OpenCode and Cursor CLI have no matching
`vendor` value in `schemas/token-cost-event.schema.json` yet — skip
this call rather than pass a mismatched vendor. Stage ids: `discover`,
`claim`, `work`, `submit-pr`, `review`, `merge`, `cleanup`. Ignore any
failure from this command — it must never block or slow the IDD loop.
## Issue-authoring skill (dogfooded)
The canonical issue-authoring skill bundle lives at
`skills/issue-authoring/`. Edit the canonical bundle, never a
generated copy: `node scripts/sync-docs.mjs --apply` regenerates
derived copies and `node scripts/audit-docs.mjs --check` fails on
drift. The `idd-spec-audit` skill bundle at `skills/idd-spec-audit/`
follows the same rule: `.claude/skills/idd-spec-audit/` is likewise a
generated mirror and must never be edited directly.
## Codex issue-authoring route
For Codex CLI, read the canonical issue-authoring bundle explicitly from
`skills/issue-authoring/`, or install one selected copy under
`.agents/skills/issue-authoring/` when the target runtime supports native
skill discovery there. The existing `.claude/skills/issue-authoring/` copy is
the dogfood route for Claude Code, OpenCode, Grok Build, and Cursor CLI
compatibility; it is not the
canonical source. Do not add checked-in `.agents/skills/`,
`.cursor/skills/`, or `.opencode/skills/` mirrors by default
(preventive; no observed incident yet),
and do not assume the source path is automatically discovered by Codex.
The rule against checked-in `.agents/skills/` mirrors covers repository files
only. An operator's user-global install under `~/.agents/skills/` (see
[User-global installation](docs/user-global-install.md)) lives outside every
repository, so it is not a mirror and this rule does not apply to it.