pi-gauntlet 5.0.8 → 5.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # Changelog
2
2
 
3
+ ## v5.1.0 - 2026-08-31
4
+
5
+ - New skill `linear`: package-owned home for all linearis mechanics (verb reference, six gotchas, multi-line body pattern, ID-cache convention, failure modes, MCP fallback) and the five-key overrides `## Issue tracker` schema, including the explicit `tracker:` off-switch (`linear` / `github` / `none` - exclusive selection, zero probing when non-Linear). shape-ticket, check-delivery, and chase-bug slim to detection + a `/skill:linear` routing line (chase-bug's fabricated `linearis comment` example fixed); brainstorming's gatherer fetch-path definition honors the off-switch; `./skills/linear` joins the Claude Code marketplace allowlist (five exposed skills). Fixes #17. Spec: `doc/specs/2026-08-31-gh-17-linear-skill.md`.
6
+
3
7
  ## v5.0.8 - 2026-08-31
4
8
 
5
9
  - shape-ticket: ticket bodies must be self-contained - new wording contract in `skills/shape-ticket/reference/ticket-wording.md` (repo-stranger reader, strip-test, plain-words lead + example per asserted failure, jargon defined, references demoted to deletable parenthetical pointers, big chunks linkable with a summary line - no spiderman tickets). Wired into the draft step, every roast brief (members, worker fallback, runtime conditional; fidelity exempts contract-driven unpacking from `added`), and the repair-mode no-op check (a violating body is non-conforming and gets a proposed rewrite). Generic repo density norms can no longer override ticket prose; only an explicit ticket-wording overrides section can. Fixes #18. Spec: `doc/specs/2026-08-31-gh-18-self-contained-ticket-wording.md`.
package/README.md CHANGED
@@ -69,7 +69,7 @@ Everything between gate 1 and gate 2 - task breakdown, implementation, both revi
69
69
 
70
70
  pi-gauntlet ships three kinds of pieces, layered on top of pi-cohort's dispatch:
71
71
 
72
- - **16 skills** - the workflow logic. Twelve activate automatically when pi sees the matching kind of task, and each one gates the next: `brainstorming`, `writing-plans`, `roasting-the-spec`, `test-driven-development`, `subagent-driven-development`, `dispatching-parallel-agents`, `verification-before-completion`, `requesting-code-review`, `receiving-code-review`, `using-git-worktrees`, `finishing-a-development-branch`, `writing-skills`. Four more are explicit-invocation-only (`disable-model-invocation: true`): `shape-ticket` creates or repairs one tracker issue per run against a Context/Problem/Idea/Acceptance-Criteria template, gated by an AC integrity check, a cheap council roast, and a single human-confirmed write - run it with `/skill:shape-ticket`. `gatekeep-pr` is consent-gated pre-merge verification of a PR against its issue - read-only gathering, verification evidence resolved CI-first (green checks on the exact assessed head count as evidence; the project's verification command runs only as fallback), a rubric-based review, then a deterministic authorship-aware menu with stable finding IDs (P#/L#/C#/F#) and numbered pre-composed courses (fixes execute as a single parallel-safe wave: one gate run, one re-review, one push); nothing mutates (fixes, pushes, reviews, merges) until you pick a row - run it with `/skill:gatekeep-pr <pr>`. `check-delivery` is a post-merge detective control: proves an issue actually shipped (default-branch landing, delivery target, per-AC evidence) before its tracker status advances; it never writes a terminal status - run it with `/skill:check-delivery <ref>`. `chase-bug` is human-only bug triage: read-only root-cause discovery to an evidenced verdict menu (real bug -> ticket/brainstorm/respond; five negative verdicts), then a gated response to the reporter for addressable origins (GitHub issue / tracker ticket) and a rendered verdict summary otherwise - it never fixes during triage - run it with `/skill:chase-bug`.
72
+ - **17 skills** - the workflow logic. Thirteen activate automatically when pi sees the matching kind of task, and each one gates the next: `brainstorming`, `writing-plans`, `roasting-the-spec`, `test-driven-development`, `subagent-driven-development`, `dispatching-parallel-agents`, `verification-before-completion`, `requesting-code-review`, `receiving-code-review`, `using-git-worktrees`, `finishing-a-development-branch`, `writing-skills`, `linear` (reads/searches/comments on/manages Linear tickets via the `linearis` CLI; owns all linearis mechanics and the `## Issue tracker` overrides schema; tracker-facing skills route to it). Four more are explicit-invocation-only (`disable-model-invocation: true`): `shape-ticket` creates or repairs one tracker issue per run against a Context/Problem/Idea/Acceptance-Criteria template, gated by an AC integrity check, a cheap council roast, and a single human-confirmed write - run it with `/skill:shape-ticket`. `gatekeep-pr` is consent-gated pre-merge verification of a PR against its issue - read-only gathering, verification evidence resolved CI-first (green checks on the exact assessed head count as evidence; the project's verification command runs only as fallback), a rubric-based review, then a deterministic authorship-aware menu with stable finding IDs (P#/L#/C#/F#) and numbered pre-composed courses (fixes execute as a single parallel-safe wave: one gate run, one re-review, one push); nothing mutates (fixes, pushes, reviews, merges) until you pick a row - run it with `/skill:gatekeep-pr <pr>`. `check-delivery` is a post-merge detective control: proves an issue actually shipped (default-branch landing, delivery target, per-AC evidence) before its tracker status advances; it never writes a terminal status - run it with `/skill:check-delivery <ref>`. `chase-bug` is human-only bug triage: read-only root-cause discovery to an evidenced verdict menu (real bug -> ticket/brainstorm/respond; five negative verdicts), then a gated response to the reporter for addressable origins (GitHub issue / tracker ticket) and a rendered verdict summary otherwise - it never fixes during triage - run it with `/skill:chase-bug`.
73
73
  - **7 subagent personas** - the specialized child agents the skills dispatch via pi-cohort: `implementer`, `code-reviewer`, `spec-reviewer`, `conformance-reviewer`, `spec-summarizer`, `spec-council-member`, `spec-council-synthesizer`. See [doc/personas.md](./doc/personas.md) for what each one does and why its permissions are scoped the way they are.
74
74
  - **3 runtime extensions** - the enforcement layer. `plan-tracker` and `phase-tracker` are tools skills call to track progress (with a TUI widget); `verify-before-ship` is a hook that warns if you push or open a PR without a passing test run since your last edit; a phase-tracker flow guard reminds on implement-phase commits missing spec/code review. See [doc/configuration.md](./doc/configuration.md) for the settings each one reads.
75
75
 
@@ -126,9 +126,9 @@ cd ~/repos/pi-gauntlet && npm run link-agents # local-path installs skip npm i
126
126
 
127
127
  ## Use from Claude Code
128
128
 
129
- Four skills are exposed to Claude Code via the plugin marketplace at
129
+ Five skills are exposed to Claude Code via the plugin marketplace at
130
130
  `.claude-plugin/marketplace.json`: **shape-ticket**, **gatekeep-pr**,
131
- **check-delivery**, and **chase-bug**. They are harness-portable by design - every pi-specific
131
+ **check-delivery**, **chase-bug**, and **linear**. They are harness-portable by design - every pi-specific
132
132
  mechanic they touch (`plan_tracker`, `gauntlet_setting`, `subagent()`) carries
133
133
  an inline fallback, so they run on Claude Code's native facilities. This is the
134
134
  supported set. Not exposed, in two classes: (a) genuinely pi-bound surface -
@@ -202,8 +202,9 @@ exact repo folder* in interactive Claude Code. Trusting a parent folder,
202
202
  4. Run `/plugin` and confirm: marketplace `pi-gauntlet` is listed, plugin
203
203
  `gauntlet` is enabled. If it shows as known but not installed, run
204
204
  `/plugin install gauntlet@pi-gauntlet` and re-check.
205
- 5. Confirm exactly four skills are registered under the plugin (via the
206
- `/plugin` details view): shape-ticket, gatekeep-pr, check-delivery, chase-bug.
205
+ 5. Confirm exactly five skills are registered under the plugin (via the
206
+ `/plugin` details view): shape-ticket, gatekeep-pr, check-delivery, chase-bug,
207
+ linear.
207
208
  6. Invoke `/gauntlet:shape-ticket` with a deliberately two-concern ask (e.g.
208
209
  "shape a ticket: CSV import for operators, plus a partner-facing status
209
210
  API") so the skill deterministically consults its
@@ -261,6 +262,20 @@ Use the `jira` CLI (authenticated via `jira login`), not `gh` or `linearis`.
261
262
  - post comment (Reporter note only): `jira issue comment ABC-123 --body "<text>"`
262
263
  ```
263
264
 
265
+ **`linear` setup:** mandatory - `linearis` installed and authenticated (or a Linear
266
+ MCP server as a fallback when `linearis` is unavailable). Optional - the five
267
+ `## Issue tracker` override keys (`tracker`, `workspace urlKey`, `default team`,
268
+ `self`, `id cache`); the full schema is documented once, in
269
+ [skills/linear/SKILL.md](./skills/linear/SKILL.md) - not restated here. Off switch:
270
+ set `tracker: github` or `tracker: none` in `## Issue tracker` to disable Linear
271
+ entirely - no `linearis` probing, no prompts.
272
+
273
+ **Coexistence:** the five `## Issue tracker` keys compose with the free-form
274
+ command-mapping convention above, they don't replace it. `tracker:` adds exclusive
275
+ tracker selection; free-form verb mappings keep working both without a `tracker:`
276
+ key (ladder rung 1, as today) and as the mechanics source when `tracker:` names an
277
+ unknown value.
278
+
264
279
  **`## Deployment` section:** `shape-ticket` (split rule), `writing-plans` (scope check), and `brainstorming` (scope check) read deploy topology from this section: what ships together, what ships independently, and the mechanism. It is a fact to look up, never to infer - when the section is absent, or when it documents a monolithic topology (like the example below), the "separable release timing" split axis is unavailable and splits fail closed to one artifact.
265
280
 
266
281
  ```markdown
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-gauntlet",
3
- "version": "5.0.8",
3
+ "version": "5.1.0",
4
4
  "description": "Opinionated, gated workflow skills, subagent personas, and runtime extensions for the pi coding agent.",
5
5
  "author": "Jacek Juraszek",
6
6
  "type": "module",
@@ -68,7 +68,10 @@ contains any of:
68
68
 
69
69
  - an `http(s)://` URL;
70
70
  - a tracker-style ID matching `[A-Z][A-Z0-9]+-\d+` (Linear/Jira form) **when a fetch
71
- path exists** (a tracker tool/MCP, or a URL pattern in the gauntlet overrides file, see Project overrides);
71
+ path exists** (a tracker tool/MCP, or a URL pattern in the gauntlet overrides file,
72
+ see Project overrides). A tracker excluded by an overrides `## Issue tracker`
73
+ `tracker:` key has no fetch path regardless of installed tools; its IDs are listed
74
+ as unfetched refs;
72
75
  - a GitHub-style ref `owner/repo#N`, or a bare `#N` when the repo's tracker is
73
76
  GitHub Issues.
74
77
 
@@ -89,6 +89,12 @@ Search both **open and closed** issues for the same symptom before deep
89
89
  discovery. This has its own resolution ladder, separate from the response-channel
90
90
  ladder in step 5 (the reply destination and the search target can differ):
91
91
 
92
+ 0. If the overrides `## Issue tracker` section has a `tracker:` key
93
+ (case-insensitive), that tracker is exclusive - no probing for others, no
94
+ ask, others never mentioned. `tracker: none` -> prior-report search declared
95
+ **not completed** (the existing rung-4 convention). Unknown value ->
96
+ exclusive; use free-form command mappings in the same section if present,
97
+ else ask. Unparseable `tracker:` line -> ask, never probe.
92
98
  1. `## Issue tracker` section in the gauntlet overrides file, if present.
93
99
  2. Repo tracker convention documented in `AGENTS.md` / `README`.
94
100
  3. Detected CLI (e.g. `gh` for a GitHub-origin repo, or another tracker tool/CLI
@@ -246,18 +252,26 @@ Slack.
246
252
 
247
253
  **Channel resolution**, in order:
248
254
 
255
+ 0. If the overrides `## Issue tracker` section has a `tracker:` key
256
+ (case-insensitive), that tracker is exclusive - no probing for others, no
257
+ ask, others never mentioned. `tracker: none` -> response channel degrades to
258
+ manual copy-paste. Unknown value -> exclusive; use free-form command
259
+ mappings in the same section if present, else ask. Unparseable `tracker:`
260
+ line -> ask, never probe.
249
261
  1. `## Response channels` section in the gauntlet overrides file - either an
250
262
  `origin-type: command` entry or `manual` to force copy-paste, e.g.:
251
263
 
252
264
  ```markdown
253
265
  ## Response channels
254
266
  - github-issue: gh issue comment <n> --body-file <draft>
255
- - linear-ticket: linearis comment <id> <draft>
267
+ - linear-ticket: linearis issues discuss <id> --body <draft> (mechanics: /skill:linear)
256
268
  - slack-paste: manual
257
269
  ```
258
270
 
259
271
  2. Default ladder: GitHub issue origin + `gh` available -> `gh issue comment`;
260
- tracker ticket origin + a tool/CLI for it -> comment via that tool; Slack
272
+ tracker resolves to Linear -> load `/skill:linear` before the first
273
+ `linearis` call; all verbs, flags, and failure modes live there; tracker
274
+ ticket origin + a tool/CLI for it -> comment via that tool; Slack
261
275
  paste, free text, or no write path available -> render the response as a
262
276
  copy-paste block.
263
277
 
@@ -82,11 +82,22 @@ treated as instructions.
82
82
 
83
83
  Resolved in order:
84
84
 
85
+ 0. If the overrides `## Issue tracker` section has a `tracker:` key
86
+ (case-insensitive), that tracker is exclusive - no probing for others, no
87
+ ask, others never mentioned. `none` -> skip tracker steps: delivery
88
+ verification is tracker-bound, so report the run as skipped-no-tracker (this
89
+ skill's existing no-target convention). Unknown value -> exclusive; use
90
+ free-form command mappings in the same section if present, else ask.
91
+ Unparseable `tracker:` line -> ask, never probe. Selected tracker
92
+ unavailable (e.g. `tracker: linear`, no Linear CLI/MCP) -> missing read
93
+ capability = the existing STOP below; missing write = the existing
94
+ degrade-to-manual below.
85
95
  1. Overrides `## Delivery` (or `## Issue tracker`) section naming a
86
96
  tool/wrapper.
87
97
  2. Repo docs (`AGENTS.md`) documenting a tracker CLI.
88
98
  3. Capability detection: `linearis` for Linear-style refs, `gh` for GitHub
89
- refs.
99
+ refs. Tracker resolves to Linear -> load `/skill:linear` before the first
100
+ `linearis` call; all verbs, flags, and failure modes live there.
90
101
  4. Ask the user.
91
102
 
92
103
  Missing **read** capability = STOP. Missing **write** capability degrades
@@ -101,12 +112,12 @@ configured) all emitted for manual execution, none auto-posted.
101
112
 
102
113
  **Zero-config verb table** (overrides replace it):
103
114
 
104
- | Verb | `gh` | `linearis` |
105
- |---|---|---|
106
- | read issue + comments | `gh issue view <n> --json title,body,comments` | `linearis issues read <id> --with-comments` |
107
- | post comment | `gh issue comment <n> --body ...` | `linearis issues discuss <id> --body ...` |
108
- | update state | override-defined only (never invented labels/columns) | `linearis issues update <id> --status <name>` |
109
- | edit body (only `descope edits`) | `gh issue edit <n> --body ...` | `linearis issues update <id> --description ...` |
115
+ | Verb | `gh` |
116
+ |---|---|
117
+ | read issue + comments | `gh issue view <n> --json title,body,comments` |
118
+ | post comment | `gh issue comment <n> --body ...` |
119
+ | update state | override-defined only (never invented labels/columns) |
120
+ | edit body (only `descope edits`) | `gh issue edit <n> --body ...` |
110
121
 
111
122
  ## Verification pipeline
112
123
 
@@ -0,0 +1,188 @@
1
+ ---
2
+ name: linear
3
+ description: Use when reading, searching, commenting on, editing, or managing Linear tickets via the `linearis` CLI - ticket IDs like ABC-123, "check ticket ABC-99", "move ABC-12 to done", or when a tracker-facing skill routes Linear mechanics here. Authoring a NEW ticket (structure, acceptance criteria) belongs to /skill:shape-ticket, which calls this skill's create mechanic.
4
+ ---
5
+
6
+ # Linear
7
+
8
+ Before anything else, resolve overrides: read the gauntlet overrides file's
9
+ `## Issue tracker` section. If `tracker:` resolves to a non-Linear value, announce
10
+ that Linear is off per overrides and stop - no `command -v linearis`, no auth call,
11
+ no ask. An unknown or unparseable `tracker:` value never reaches setup either:
12
+ resolve it per the four-state table in section 2 (free-form mappings or ask) before
13
+ any probe. Loading this skill is not probing; the zero-probe guarantee holds even
14
+ when a stray ticket-ID mention auto-triggered it.
15
+
16
+ **Write gate.** On standalone invocation, every human-channel write (create, body
17
+ update, comment/reply, state change with visible effect) is gated on explicit user
18
+ confirmation of the exact text. When routed from a tracker-facing skill that already
19
+ confirmed the exact payload, do not re-confirm an unchanged payload; any payload
20
+ this skill alters re-gates.
21
+
22
+ ## 1. Setup
23
+
24
+ Mandatory: `linearis` on PATH and authenticated (`linearis auth status`). Token
25
+ resolution order: `--api-token`, `LINEAR_API_TOKEN`, `~/.linearis/token`.
26
+
27
+ > **No `linearis` installed?** If `command -v linearis` fails, fall back to a
28
+ > **Linear MCP server** when the harness has one configured - its tools cover the
29
+ > same operations (read, list/search, comment, update status, create). Tool names
30
+ > vary by harness and by the server's configured name, so consult the harness's
31
+ > own tool list rather than hard-coding identifiers; the JSON/jq and command
32
+ > examples below are then guidance for the equivalent MCP call, not literal
33
+ > shell. pi-gauntlet ships no MCP setup; MCP is opportunistic.
34
+
35
+ No `linearis` and no MCP: report inability, never fabricate.
36
+
37
+ Optional: each `## Issue tracker` override key below, with its degradation.
38
+
39
+ ## 2. `## Issue tracker` schema
40
+
41
+ This skill owns the full schema - all five keys, all optional:
42
+
43
+ ```markdown
44
+ ## Issue tracker
45
+ - tracker: linear # or github / none - exclusive tracker selection
46
+ - workspace urlKey: acme
47
+ - default team: ENG
48
+ - self: dev@example.com
49
+ - id cache: doc/cache/linear.md
50
+ ```
51
+
52
+ Absent-key behavior, per key:
53
+
54
+ - `tracker` absent -> consumer skills use their detection ladder (unchanged today).
55
+ - `workspace urlKey` absent -> ask the user once per session (needed only for
56
+ issue-URL construction in authored bodies).
57
+ - `default team` absent -> ask on first create.
58
+ - `self` absent -> ask on first self-referential query (assignee-me, standup).
59
+ - `id cache` absent -> skip cache lookups entirely (no cache behavior).
60
+
61
+ `tracker:` matching is case-insensitive for the known values. Four states:
62
+
63
+ | `tracker:` state | Behavior |
64
+ |---|---|
65
+ | known value (`linear` / `github` / `none`) | Exclusive: no probing for other trackers, no ask, others never mentioned. `github` -> linearis never probed, this skill never proceeds past its override check. `none` -> tracker steps skipped; each consumer skill uses its documented no-tracker outcome. |
66
+ | unknown value (e.g. `jira`) | Exclusivity holds (no Linear/gh probing). If the same `## Issue tracker` section carries free-form command mappings for that tracker, use them; else say so and ask - never silently fall back to the detection ladder. |
67
+ | key absent | Consumer skills use their detection ladder, unchanged from today (including the linearis PATH+auth probe). |
68
+ | key present but unparseable | Treat as an off-switch attempt gone wrong: ask the user, never probe - a typoed off-switch must not silently re-enable detection. |
69
+
70
+ **Coexistence with the free-form `## Issue tracker` contract.** The five keys
71
+ compose with the pre-existing README custom-tracker command-mapping convention,
72
+ they don't replace it. `tracker:` adds exclusive selection; free-form verb mappings
73
+ keep working both without a `tracker:` key (ladder rung 1, as today) and as the
74
+ mechanics source for an unknown `tracker:` value.
75
+
76
+ **Conflicting config** (e.g. `tracker: github` plus populated Linear keys) is not an
77
+ error: `tracker:` wins, the other keys are inert. Malformed non-`tracker` keys are
78
+ treated as absent.
79
+
80
+ ## 3. Quick reference
81
+
82
+ | Verb | Command | Notes |
83
+ |---|---|---|
84
+ | Read | `linearis issues read <id> --with-comments --with-comment-threads --with-attachments` | Add flags only for what you need - big tickets are slow. |
85
+ | Search | `linearis issues search "<query>"` | Case-sensitive. |
86
+ | List | `linearis issues list --assignee <who> --status <status> --team <default team> --parent <id>` | Filters compose; `--parent` lists sub-issues. |
87
+ | Create | `linearis issues create "<title>" --team <default team> [--parent-ticket <id>] --status <status>` | Title is positional (no `--title`); `--team` required; `--parent-ticket` for sub-issues; state an explicit `--status` rather than relying on the default. |
88
+ | Update | `linearis issues update <id> --status <status> --assignee <who> --labels <labels> --due-date <date> [relation flags]` | See gotcha (e) for relation flags. |
89
+ | Discuss | `linearis issues discuss <id> --body "<text>"` | Starts a new top-level comment thread. |
90
+ | Reply | `linearis issues reply <id> --body "<text>"` | Root comments only - see gotcha (b). |
91
+ | Edit | `linearis issues comment-edit <id> --body "<text>"` / `linearis issues edit-reply <id> --body "<text>"` | Full rewrite, no history - see gotcha (a). |
92
+ | Labels, teams, users, cycles | `linearis labels list`, `linearis teams list`, `linearis users list`, `linearis cycles list` | Use to resolve names to IDs; see id-cache convention. |
93
+ | Attachments | `linearis attachments create <id> --url <url>` | Link-only, no inline render - see gotcha (d). |
94
+ | Upload | `linearis files upload <path>` | Returns an `assetUrl` for inline embedding - see gotcha (d). |
95
+
96
+ Workspace values above (`<default team>`, `<who>`, etc.) are placeholders bound to
97
+ the override keys in section 2 - never a real urlKey, team prefix, or email.
98
+
99
+ ## 4. Gotchas
100
+
101
+ a. **Comment edit is a rewrite, no visible history.** To amend rather than replace,
102
+ fetch the old body and pass `OLD + "\n\n" + ADDITION`; surface the overwrite diff
103
+ to the user before pushing.
104
+
105
+ b. **`reply` targets must be root comments** (`parentId: null`). A non-root target
106
+ fails with a misleading validation error. To respond in-thread, resolve the
107
+ thread's root via `discussions`/`--with-comment-threads` and `reply` to that
108
+ root, or start a new `discuss` thread instead. `edit-reply` is NOT a reply
109
+ fallback - it rewrites an existing reply. Use it only for an explicitly
110
+ requested edit of the caller's own reply, behind the rewrite-confirmation rule
111
+ in (a).
112
+
113
+ c. **`@ABC-123` never resolves via the CLI/API.** Use the full issue URL
114
+ `https://linear.app/<workspace urlKey>/issue/<id>`, which unfurls to a native
115
+ badge and records a relation. A literal `@ID` in a body stays literal text.
116
+
117
+ d. **Images go inline, links don't render.** `linearis files upload <path>` ->
118
+ `![alt](<assetUrl>)` in the body embeds the image. `attachments create` only
119
+ links a URL and renders no image. Asset URLs returned by a `read` are
120
+ short-lived signed JWTs - re-upload for a fresh one, never re-paste an old one.
121
+
122
+ e. **Relation flags are single-value.** `--blocks`, `--blocked-by`, `--relates-to`,
123
+ `--duplicate-of` on `create`/`update` keep only the last value if repeated in one
124
+ call. For multiple relations in one call, use
125
+ `linearis issues relations add <id>` with its comma-separated flags; otherwise
126
+ issue separate `update` calls.
127
+
128
+ f. **`create`'s title is positional.** There is no `--title` flag.
129
+
130
+ ## 5. Multi-line bodies
131
+
132
+ Write the body to a temp file and pass it as `"$(cat FILE)"`, with a quoted heredoc
133
+ delimiter if a heredoc is used to produce the file. Inline heredoc-in-arg
134
+ (embedding a heredoc directly inside a CLI argument) fails intermittently.
135
+
136
+ ## 6. ID-cache convention
137
+
138
+ Active only when `id cache:` is set; its value is a repo-relative markdown file.
139
+
140
+ - **Row contract:** one table per entity kind (teams, users, projects); each row is
141
+ display name/key + ID; rows are sorted within their table. A missing or empty
142
+ file means every lookup is a miss, and the first write-back creates the
143
+ structure.
144
+ - **Lookup:** check the cache before any `linearis teams list` / `users list` /
145
+ `projects list` resolution. On a miss, resolve via the narrowest list command and
146
+ add the row. On a rejected/stale cached ID, re-resolve and update or remove the
147
+ row.
148
+ - **Write timing by caller:** standalone invocation writes the row and reports it.
149
+ A calling workflow that requires a clean checkout or forbids repo edits (e.g.
150
+ read-only discovery) uses the resolved value and reports the exact pending row
151
+ without writing it. An unwritable cache -> complete the operation and report the
152
+ failed write-back.
153
+
154
+ ## 7. Output format and safety
155
+
156
+ Operational/data subcommands emit JSON - pipe to `jq`, don't assume column output.
157
+ `usage` subcommands emit plaintext help.
158
+
159
+ Safety rules, in addition to the write gate above:
160
+
161
+ - Confirm destructive ops (delete, archive, comment rewrite, bulk changes > 3
162
+ items).
163
+ - Never paste tokens.
164
+ - Never rewrite an issue description unasked.
165
+
166
+ ## 8. Failure modes
167
+
168
+ | Symptom | Cause | Fix |
169
+ |---|---|---|
170
+ | 401 | Not authenticated / expired token | `linearis auth status`; re-auth. |
171
+ | Issue not found | Wrong workspace, or issue archived | Confirm workspace; check archived state. |
172
+ | Status not found | Status name doesn't match the team's workflow states | List the team's states before setting one. |
173
+ | Missing `--team` error on create | `--team` is required | Supply `--team <default team>`. |
174
+ | Search returns nothing unexpected | Search is case-sensitive | Retry with matching case. |
175
+ | Cannot edit a comment | Comment belongs to another user | Reply instead of editing. |
176
+ | Reply validation error | Target is not a root comment | See gotcha (b). |
177
+ | `@ID` shows as literal text | `@ABC-123` mentions don't resolve | Use the full issue URL (gotcha c). |
178
+ | Read is slow | Big ticket with many comments/attachments | Drop `--with-*` flags not needed. |
179
+
180
+ ## 9. Discovery pointers
181
+
182
+ `linearis usage`, each domain's own `usage` subcommand (e.g.
183
+ `linearis issues usage`), and Linear's LLM docs index `https://linear.app/llms.txt`
184
+ for product behavior the CLI doesn't expose.
185
+
186
+ ## Project overrides
187
+
188
+ If a gauntlet overrides file exists - checked in order: `.pi/gauntlet-overrides.md`, `<repo root>/gauntlet-overrides.md`, `<repo root>/doc/gauntlet-overrides.md`; first found wins - read it. Any sections relevant to this skill - by name match, by topic (routing, verification, worktrees, etc.), or by workflow convention - override or extend the instructions above. Project-local `AGENTS.md` is already in context - check it for project-specific routing tables, service paths, and verification commands. `## Issue tracker` is the named extension point for this skill.
@@ -213,24 +213,24 @@ Inline council dispatch, reusing spec-council config and personas - **not** `/sk
213
213
 
214
214
  One resolution ladder, applied to every capability (tracker, browser/screenshot, DB, asset hosting; `<repo root>` = `git rev-parse --show-toplevel`, or the current directory outside a repo):
215
215
 
216
+ 0. **Overrides `tracker:` key** - if the overrides `## Issue tracker` section has a `tracker:` key (case-insensitive), that tracker is exclusive: no probing for others, no ask, others never mentioned. `none` -> skip tracker steps entirely; run the full authoring pipeline and emit the finished title/body/metadata for manual filing (the existing no-verb degradation), reported as not filed. Unknown value -> exclusive; use free-form command mappings in the same `## Issue tracker` section if present, else say so and ask - never silently fall back to detection. Unparseable `tracker:` line -> ask, never probe. Selected tracker unavailable (e.g. `tracker: linear` but no matching backend) -> stop after authoring; emit for manual filing; report the unavailable backend - no fall-through, no ask about other trackers.
216
217
  1. **Project override / invoking wrapper** - a `## Issue tracker` (and optional `## Capabilities`) section in the gauntlet overrides file, or a wrapping prompt naming tools, commands, env hosts.
217
218
  2. **Repo documentation** - `AGENTS.md` / README conventions naming the tracker, taxonomy docs, comms style, capture tooling. Expect root plus possibly nested `AGENTS.md`; follow pointers.
218
219
  3. **Capability detection** - `gh` (repo origin is GitHub) and `linearis` (binary on PATH + shell auth, verified by a cheap read call) work out of the box. Both live -> prefer the ref style the repo's docs/commits actually use (`ABC-123` -> linearis; `#N` / GitHub links -> gh); still ambiguous -> ask once.
220
+ Tracker resolves to Linear -> load `/skill:linear` before the first `linearis` call; all verbs, flags, and failure modes live there.
219
221
  4. **Ask the user.** Never guess, never fabricate access.
220
222
 
221
223
  Auth failure at detection time makes that rung dead; continue down the ladder (ultimately: ask).
222
224
 
223
225
  **Default verb table** (zero-config command shape; overrides replace it):
224
226
 
225
- | Verb | `gh` | `linearis` |
226
- |---|---|---|
227
- | read (full, incl. comments) | `gh issue view <n> --json title,body,labels,assignees,milestone,comments` | `linearis issues read <id> --with-comments` |
228
- | search (dup/reversal) | `gh search issues` / `gh issue list --search` (incl. `state:closed`) | `linearis issues search <query>` |
229
- | create | `gh issue create --title --body [--label]` | `linearis issues create <title> --description ... --team <team>` |
230
- | update | `gh issue edit <n> --title --body [--add-label/--remove-label]` | `linearis issues update <id> --title ... --description ...` |
231
- | post comment (Reporter note only) | `gh issue comment <n> --body ...` | `linearis issues discuss <id> --body ...` |
232
-
233
- linearis create requires `--team <team>`; it resolves like any other metadata field - named by repo docs/overrides, else asked - never invented.
227
+ | Verb | `gh` |
228
+ |---|---|
229
+ | read (full, incl. comments) | `gh issue view <n> --json title,body,labels,assignees,milestone,comments` |
230
+ | search (dup/reversal) | `gh search issues` / `gh issue list --search` (incl. `state:closed`) |
231
+ | create | `gh issue create --title --body [--label]` |
232
+ | update | `gh issue edit <n> --title --body [--add-label/--remove-label]` |
233
+ | post comment (Reporter note only) | `gh issue comment <n> --body ...` |
234
234
 
235
235
  **Tracker-agnostic contract** required of whatever resolves: read the full ticket incl. comments; write title + body + metadata; post a comment; search (dup/reversal check); tracker-native reference form for links. Field names, states, and taxonomies come from steps 1-2 of the ladder, never hardcoded in this skill. If an approved Reporter-note comment has no resolvable post-comment verb, the body write still proceeds; the comment text is emitted for manual posting and reported as not performed - never silently dropped.
236
236