@skitterbyte/skitterspec-jira 0.0.0-stage → 2.0.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.
Files changed (113) hide show
  1. package/MIGRATION.md +1266 -0
  2. package/README.md +44 -2
  3. package/assets/claude-md-section.md +85 -0
  4. package/assets/commands/allow-main.md +33 -0
  5. package/assets/commands/spec-connect.md +13 -0
  6. package/assets/commands/spec-live.md +14 -0
  7. package/assets/commands/spec-remote-review.md +37 -0
  8. package/assets/commands/spec-skip.md +24 -0
  9. package/assets/core/SETUP.md +192 -0
  10. package/assets/core/env.config.json.example +56 -0
  11. package/assets/core/env.config.md +606 -0
  12. package/assets/core/gating.config.json.example +4 -0
  13. package/assets/core/gating.config.md +81 -0
  14. package/assets/core/jira.config.json.example +18 -0
  15. package/assets/core/jira.config.md +88 -0
  16. package/assets/hooks/main-guard.cjs +162 -0
  17. package/assets/hooks/review-gate.cjs +146 -0
  18. package/assets/review/page.html +3384 -0
  19. package/assets/rules/commit-trailers.md +96 -0
  20. package/assets/rules/negative-checks.md +69 -0
  21. package/assets/rules/offered-unblocks.md +100 -0
  22. package/assets/rules/spec-planning.md +702 -0
  23. package/assets/rules/spec-reports.md +572 -0
  24. package/assets/skills/no-spec/SKILL.md +249 -0
  25. package/assets/skills/spec/SKILL.md +714 -0
  26. package/assets/skills/spec-bug/SKILL.md +585 -0
  27. package/assets/skills/spec-cancel/SKILL.md +261 -0
  28. package/assets/skills/spec-complete/SKILL.md +451 -0
  29. package/assets/skills/spec-diff/SKILL.md +870 -0
  30. package/assets/skills/spec-hotfix/SKILL.md +607 -0
  31. package/assets/skills/spec-init/SKILL.md +178 -0
  32. package/assets/skills/spec-jira-setup/SKILL.md +221 -0
  33. package/assets/skills/spec-list/SKILL.md +173 -0
  34. package/assets/skills/spec-next/SKILL.md +678 -0
  35. package/assets/skills/spec-push/SKILL.md +306 -0
  36. package/assets/skills/spec-review/SKILL.md +256 -0
  37. package/assets/skills/spec-reviewed/SKILL.md +284 -0
  38. package/assets/skills/spec-start/SKILL.md +496 -0
  39. package/assets/skills/spec-status/SKILL.md +114 -0
  40. package/assets/skills/spec-sync/SKILL.md +220 -0
  41. package/assets/skills/spec-to-main/SKILL.md +141 -0
  42. package/bin/skitterspec-jira.js +68 -0
  43. package/package.json +40 -4
  44. package/src/cli.js +5967 -0
  45. package/src/deprecate.js +138 -0
  46. package/src/env/bootstrap.js +188 -0
  47. package/src/env/building.js +143 -0
  48. package/src/env/classify.js +176 -0
  49. package/src/env/commitcmd.js +108 -0
  50. package/src/env/config.js +850 -0
  51. package/src/env/dev.js +63 -0
  52. package/src/env/glob.js +34 -0
  53. package/src/env/hooks.js +226 -0
  54. package/src/env/hotfix.js +413 -0
  55. package/src/env/hotfixland.js +302 -0
  56. package/src/env/integrate.js +167 -0
  57. package/src/env/live.js +479 -0
  58. package/src/env/mainguard.js +299 -0
  59. package/src/env/provision.js +466 -0
  60. package/src/env/proxy.js +225 -0
  61. package/src/env/prune.js +119 -0
  62. package/src/env/registry.js +159 -0
  63. package/src/env/render.js +17 -0
  64. package/src/env/resolve.js +716 -0
  65. package/src/env/review.js +2622 -0
  66. package/src/env/reviewers/coderabbit.js +228 -0
  67. package/src/env/reviewers.js +517 -0
  68. package/src/env/serve.js +1044 -0
  69. package/src/env/supervise.js +157 -0
  70. package/src/env/teardown.js +248 -0
  71. package/src/env/trust.js +87 -0
  72. package/src/gating.js +155 -0
  73. package/src/init.js +1150 -0
  74. package/src/lines-diff.js +114 -0
  75. package/src/prompts.js +129 -0
  76. package/src/vendor/jira/adf.js +414 -0
  77. package/src/vendor/jira/api.js +295 -0
  78. package/src/vendor/jira/cli-sync.js +1252 -0
  79. package/src/vendor/jira/commands.js +44 -0
  80. package/src/vendor/jira/config.js +286 -0
  81. package/src/vendor/jira/credentials.js +108 -0
  82. package/src/vendor/jira/dialect.js +45 -0
  83. package/src/vendor/jira/mcp.js +129 -0
  84. package/src/vendor/provider-kit/index.js +41 -0
  85. package/src/vendor/provider-kit/src/adapter.js +23 -0
  86. package/src/vendor/provider-kit/src/apply.js +207 -0
  87. package/src/vendor/provider-kit/src/args.js +68 -0
  88. package/src/vendor/provider-kit/src/assignment.js +277 -0
  89. package/src/vendor/provider-kit/src/config.js +251 -0
  90. package/src/vendor/provider-kit/src/credentials.js +404 -0
  91. package/src/vendor/provider-kit/src/doctor.js +35 -0
  92. package/src/vendor/provider-kit/src/http.js +63 -0
  93. package/src/vendor/provider-kit/src/identity.js +93 -0
  94. package/src/vendor/provider-kit/src/list-assignee.js +71 -0
  95. package/src/vendor/provider-kit/src/list-rows.js +35 -0
  96. package/src/vendor/provider-kit/src/md-compare.js +39 -0
  97. package/src/vendor/provider-kit/src/md-tables.js +94 -0
  98. package/src/vendor/provider-kit/src/prompt.js +50 -0
  99. package/src/vendor/provider-kit/src/released.js +219 -0
  100. package/src/vendor/provider-kit/src/specs.js +248 -0
  101. package/src/vendor/provider-kit/src/transport.js +22 -0
  102. package/src/vendor/sync-core/index.js +92 -0
  103. package/src/vendor/sync-core/src/base.js +81 -0
  104. package/src/vendor/sync-core/src/compare.js +338 -0
  105. package/src/vendor/sync-core/src/dialect.js +51 -0
  106. package/src/vendor/sync-core/src/fields.js +36 -0
  107. package/src/vendor/sync-core/src/legacy.js +100 -0
  108. package/src/vendor/sync-core/src/normalize.js +971 -0
  109. package/src/vendor/sync-core/src/push.js +85 -0
  110. package/src/vendor/sync-core/src/retarget.js +278 -0
  111. package/src/vendor/sync-core/src/task-block.js +308 -0
  112. package/src/vendor/sync-core/src/verify.js +67 -0
  113. package/src/vendor/sync-core/src/write.js +191 -0
@@ -0,0 +1,178 @@
1
+ ---
2
+ name: spec-init
3
+ description: Bootstrap the spec-driven-development workflow in the current project — create the specs/ lifecycle folders and .core, wire version-control so specs are tracked, verify the spec skills are installed, and add the spec workflow to CLAUDE.md and .claude/rules. Idempotent and safe to re-run. Use when setting up a new project for specs or repairing the setup, or when the user says "/spec-init", "set up specs here", "initialise the spec process".
4
+ ---
5
+
6
+ # /spec-init — set up the spec-driven-development workflow
7
+
8
+ > Stay silent while this runs — speak only to ask something you cannot answer
9
+ > yourself, or to report a failure at the moment it happens. Read
10
+ > `.claude/rules/spec-reports.md` before reporting; it defines the block this
11
+ > skill ends with.
12
+
13
+ Bootstrap (or repair) everything this project needs to run the spec lifecycle.
14
+ **Idempotent:** detect what already exists, create only what's missing, and never
15
+ clobber customised content. Finish with a summary of created vs already-present.
16
+
17
+ > If `@skitterbyte/skitterspec` is installed, `npx @skitterbyte/skitterspec init` does
18
+ > all of the below mechanically. This skill is the manual/repair path and is
19
+ > useful when the package isn't available or you only need to fix part of the
20
+ > setup.
21
+ >
22
+ > **Re-running on an already-set-up repo is safe.** `init` detects the existing
23
+ > setup (via the committed `specs/.core/.skitterspec-manifest.json` of installed
24
+ > file hashes) and, interactively, offers three paths — **Resync** (update managed
25
+ > skills/rules to the latest but keep files you've edited), **Start again** (reset
26
+ > the managed scaffolding fresh — never your specs or config, with a confirm), or
27
+ > **Leave alone**. Non-interactively it only adds what's missing; `--resync` /
28
+ > `--reset` (reset needs `--yes`) drive the stronger actions.
29
+
30
+ The system is **thirteen skills**: `spec` (feature), `spec-bug` (bug),
31
+ `spec-hotfix` (a bug fixed on a released tag),
32
+ `no-spec` (work that genuinely has none — off the base branch all the same),
33
+ `spec-review`, `spec-start`,
34
+ `spec-next`, `spec-diff` (read a spec's diff as a page),
35
+ `spec-reviewed` (pick up a review you approved on that page), `spec-to-main`,
36
+ `spec-complete`, `spec-cancel`, and this `spec-init`. The lifecycle is `backlog → in-progress → complete / cancelled`,
37
+ with `.core` holding always-apply project rules.
38
+
39
+ ## 0. Workspace mode (only when adopting isolation)
40
+
41
+ If this project is adopting per-spec isolation, ask which `mode` belongs in
42
+ `specs/.core/env.config.json` — `worktree` (default; a checkout per spec, several
43
+ at once, one terminal session each) or `checkout` (the branch is built in the
44
+ checkout you are already in; one spec at a time, no hand-off). It is a question
45
+ about how the operator works, not about what the repo contains, so ask rather
46
+ than infer it from whether dev servers or Docker are configured.
47
+
48
+ ## 0b. Release gating (optional, and separate)
49
+
50
+ Ask whether specs should record a **release-gating** decision — does this change
51
+ ship behind a feature flag, or land live? Adopting it copies
52
+ `specs/.core/gating.config.json.example` → `gating.config.json` and sets
53
+ `guidance` to wherever this project documents its flags.
54
+
55
+ It is **orthogonal to isolation**: a project can adopt either, both, or neither.
56
+ Skitterspec never learns how the flags work — it asks the question, cites that
57
+ path, and records the answer on each spec. Leave it off and nothing appears:
58
+ no question, no header, no check. Off is a perfectly good answer for a project
59
+ that does not use flags.
60
+
61
+ ## 1. Folders
62
+
63
+ Create any that are missing; drop a `.gitkeep` into ones that would otherwise be
64
+ empty so git keeps them:
65
+
66
+ - `specs/.core/` — project rules (always apply; never moved)
67
+ - `specs/backlog/` `specs/in-progress/` `specs/complete/` `specs/cancelled/`
68
+
69
+ ## 2. Version control — keep specs tracked
70
+
71
+ The whole lifecycle lives in git — **everything under `specs/` is tracked**, so
72
+ the default is simply *no ignore rule excluding it*. Ensure `.gitignore` has no
73
+ `/specs/*` (or similar) entry that would hide spec folders; if one exists and the
74
+ project wants everything tracked, remove it. Confirm with
75
+ `git check-ignore -v specs/.core/<any-file>` — it should print nothing (tracked).
76
+
77
+ - **`.core` dotfile caveat:** only relevant if a `/specs/*` ignore is
78
+ (re)introduced — `*` matches dotfiles, so `.core` would need an explicit
79
+ `!/specs/.core/` negation. With no ignore rule, it's tracked automatically.
80
+ - If the project uses a formatter/linter ignore glob that excludes `specs/**`,
81
+ decide whether spec markdown should be formatted/linted and adjust accordingly.
82
+ - If a project later wants to **stop** versioning work-in-progress specs, that's
83
+ a deliberate opt-out (e.g. `/specs/*` + `!/specs/.core/`) — ask first; the
84
+ default is track-everything.
85
+
86
+ ## 3. Verify the skills are installed
87
+
88
+ Check each of the ten skills resolves — `.claude/skills/<name>/SKILL.md`
89
+ (project) or `~/.claude/skills/<name>/` (global). List any missing. This skill
90
+ scaffolds the project; it does **not** regenerate skill bodies — missing skills
91
+ must be copied in (e.g. `npx @skitterbyte/skitterspec init`) from a global install
92
+ or a sibling project. If most/all are global, just confirm availability.
93
+
94
+ ## 4. Governing rule (`.claude/rules/spec-planning.md`)
95
+
96
+ Ensure it exists. If missing, create it documenting:
97
+
98
+ - the lifecycle skills with their **status** and **folder** (table);
99
+ - the **type** convention — header `> **Type:** Feature|Bug` + filename prefix
100
+ `feat-`/`bug-` (never `[BUG]` brackets — glob hazard);
101
+ - the **Author** / **Developer** header fields;
102
+ - the **State log** audit table (folder/status transitions), kept separate from
103
+ the **Changelog** (decisions);
104
+ - the project's concrete typecheck/test commands, and the rule that
105
+ **every phase ends with creating + running tests**.
106
+
107
+ Read a sibling spec skill (e.g. `spec`, `spec-next`) for the canonical shapes
108
+ rather than inventing them. If the rule already exists, leave it unless stale.
109
+
110
+ ## 4a. The review-gate hook (`.claude/hooks/review-gate.cjs`)
111
+
112
+ `skitterspec init` **and `skitterspec update`** install the hook script and
113
+ register it in the project's **committed** `.claude/settings.json` as a
114
+ `PreToolUse` hook on `Bash`. It runs one engine call per Bash tool call and
115
+ refuses a `git commit` in a worktree whose phase is still awaiting a verdict.
116
+
117
+ **Both commands, and that is not a detail.** Copying the script and registering
118
+ it are one operation, and they were once split across two code paths — so
119
+ `update` landed the file, reported `created:`, and wired nothing, on every
120
+ project that upgraded. Landing the script is not installing the hook.
121
+
122
+ **`.cjs`, and the extension is load-bearing.** The script lands inside the
123
+ target project, where *that* project's `package.json` decides how node parses a
124
+ `.js` — so CommonJS shipped as `.js` crashes in any `"type": "module"` project,
125
+ on every Bash tool call. `.cjs` settles it at the file. A registration left over
126
+ from the release that named `.js` is rewritten in place, keeping any wrapping
127
+ the operator added, rather than gaining a second entry beside it.
128
+
129
+ **Committed, not machine-local**, and the difference is the point: the trusted
130
+ worktree root is one machine's absolute path, while *a phase that ended owes an
131
+ answer* is the project's policy and should reach everyone who clones it. The
132
+ command is written with `${CLAUDE_PROJECT_DIR}`, so it holds in worktrees too.
133
+
134
+ **Say it is there, once.** A hook that blocks a commit with the operator not
135
+ knowing a hook exists reads as a broken git, so name it in the report when it is
136
+ newly registered — and say what turns it off (`review.required: false` in
137
+ `env.config.json`, which the hook defers to entirely).
138
+
139
+ **Never fatal, and never rewritten.** A settings file that is not parseable JSON
140
+ is reported and left exactly as it is — it is the operator's config, and
141
+ everything else in it would be lost. A settings file that already names this
142
+ script, however it was wrapped, is left alone rather than gaining a second copy.
143
+
144
+ ## 5. CLAUDE.md
145
+
146
+ Ensure a `## Spec workflow` section exists. If absent, add one with the
147
+ skill table (`Skill | Action | Status | Folder`), the Feature/Bug type note,
148
+ and a pointer to `.claude/rules/spec-planning.md`. Also update the `specs/` entry
149
+ in any project-structure tree to show `.core/` + the four lifecycle folders. If
150
+ the section exists, refresh only stale folder/skill names — don't rewrite it.
151
+
152
+ ## 6. Report
153
+
154
+ Do **not** `git commit` unless the user asks.
155
+
156
+ End with the block defined in `.claude/rules/spec-reports.md`. That file carries
157
+ the shape; this section carries only what is specific here.
158
+
159
+ **Verdicts**
160
+
161
+ - `✅` — every area is in place.
162
+ - `⚠️` — bootstrapped, with something worth knowing: a skill that could not be
163
+ installed, a CLAUDE.md that was left alone, a `.core` that is still ignored.
164
+ - `❌` — it wrote some areas and failed on another. Name which, so the re-run is
165
+ informed; this skill is idempotent and re-running it is the fix.
166
+ - `⏸` — not a git repo, or nothing it could safely write into.
167
+
168
+ **Fields:** `Built` · `Follow-ups` · `Next`
169
+
170
+ **`Built` is per area, one line each** — folders, `.gitignore` lines,
171
+ tooling-ignore negations, skills (present/missing), rule files, CLAUDE.md
172
+ section — as created / updated / already-present, plus the `git check-ignore`
173
+ result for `.core`. This is the one skill whose `Built` is a list rather than a
174
+ clause, because "what is now true of this project" is the entire answer it
175
+ exists to give.
176
+
177
+ **There is no spec to name**, so the verdict line drops that segment:
178
+ `✅ /spec-init · every area in place`.
@@ -0,0 +1,221 @@
1
+ ---
2
+ name: spec-jira-setup
3
+ description: Configure Jira sync for this repo by interview rather than by hand — asks for the site, the project and the workflow statuses, validates the answers against Jira, then writes specs/.core/jira.config.json. Safe to re-run; an existing config is reviewed, never overwritten without consent. Use when the user says "/spec-jira-setup", "set up Jira sync", "connect this repo to Jira", "configure jira.config.json", or "check my Jira setup".
4
+ ---
5
+
6
+ # /spec-jira-setup — configure Jira sync by interview
7
+
8
+ > Stay silent while this runs — speak only to ask something you cannot answer
9
+ > yourself, or to report a failure at the moment it happens. Read
10
+ > `.claude/rules/spec-reports.md` before reporting; it defines the block this
11
+ > skill ends with.
12
+
13
+ Writes `specs/.core/jira.config.json`, the file that switches one-way Jira
14
+ sync on for this repo. You **interview**; the engine
15
+ (`spec-sync init-config`) **validates and writes**. Keep that split: composing
16
+ the JSON yourself is how a malformed config gets committed, and the engine
17
+ already rejects everything the loader would later reject.
18
+
19
+ The gap this closes is not "I can't remember my site URL" — it's that nothing
20
+ ever asks which project this repo's work files into and which statuses its
21
+ lifecycle maps to, so the config ends up describing a shape nobody confirmed.
22
+ Ask about structure first; the values fall out of the answers.
23
+
24
+ ## 1. Check what already exists
25
+
26
+ Read `specs/.core/jira.config.json`.
27
+
28
+ - **Absent** — this is a first-time setup. Carry on.
29
+ - **Present** — say so and default to **reviewing** it, not replacing it: run
30
+ the checks in steps 2 and 5 and report where the live config disagrees with
31
+ the site (a project key that no longer resolves, a status that was renamed).
32
+ That is the most useful thing a re-run can do. Only write when the user asks
33
+ for it, and then pass `--force`.
34
+
35
+ ## 2. Credentials first
36
+
37
+ The interview validates its answers against Jira, so settle authentication
38
+ before asking anything:
39
+
40
+ ```
41
+ skitterspec spec-sync credentials status
42
+ ```
43
+
44
+ If nothing is set, tell the user to run this **themselves**, in their own
45
+ terminal:
46
+
47
+ ```
48
+ skitterspec spec-sync credentials set
49
+ ```
50
+
51
+ It prompts for **both halves** of the pair: the Atlassian account email
52
+ (visible) and an API token (hidden), created at
53
+ https://id.atlassian.com/manage-profile/security/api-tokens.
54
+
55
+ **Do not ask the user to paste an email or token into this conversation, and do not offer to store one for them.**
56
+ A credential pasted into a chat enters the transcript, is sent to the model,
57
+ and may be logged — moving where it is stored is pointless if it travels
58
+ through the conversation to get there. Your job is to confirm the setup is
59
+ ready and name the command; the values are theirs alone.
60
+
61
+ **Degrade, never block:** with no credentials and no MCP connection the answers
62
+ cannot be validated. Say so in one line —
63
+ *"Jira not reachable — can't validate the answers"* — point at the manual path
64
+ (`jira.config.md`, the field reference beside the example config), and
65
+ **stop without writing anything**. A half-written config is worse than none:
66
+ every other command switches on the moment the file exists.
67
+
68
+ ## 3. Which site, and which project?
69
+
70
+ - **Site URL** — `https://<site>.atlassian.net`. It also keys the
71
+ credentials-store entry, so it must be the same site `credentials set` was
72
+ given.
73
+ - **Project key** — the identifier prefix (`PROJ` in `PROJ-123`).
74
+
75
+ **This config pins exactly one project for the whole repo**, and every spec
76
+ issue lands there **by construction** — there is no per-spec picker. Say that
77
+ plainly, because it reframes the question: it isn't "which project do you
78
+ like", it's *"which product's work does this repo hold"*. If the repo genuinely
79
+ spans two projects, sync can't express that today: say so, and offer the two
80
+ honest options — pick the project that owns most of the work, or split the
81
+ repo's specs across two checkouts. Don't invent a workaround.
82
+
83
+ ## 4. Which issue types?
84
+
85
+ - **`jira.issueType`** — the type a spec mints as. Default **Task**; take the
86
+ default unless the project files this kind of work as something else
87
+ (`Story`, say).
88
+ - **`jira.subtaskType`** — the type a phase mints as. Default **Subtask**, and
89
+ it must be a subtask type in this project.
90
+
91
+ Offer the defaults and take yes for an answer — this is a confirmation, not an
92
+ interrogation.
93
+
94
+ ## 5. Check the status names
95
+
96
+ ```
97
+ skitterspec spec-sync states --json
98
+ ```
99
+
100
+ It prints the project's status names, exactly as Jira spells them — and
101
+ reaching them is the setup's first real end-to-end check: a wrong site URL,
102
+ project key or credential fails here, while the user is still in the setup
103
+ conversation. Relay a failure with its fix rather than pressing on.
104
+
105
+ Then settle the four bucket→status names against that list:
106
+
107
+ - `backlog` → `To Do` · `in-progress` → `In Progress` · `complete` → `Done` by
108
+ default, and `cancelled` → `Done` too, because default Jira workflows carry
109
+ no Cancelled status.
110
+ - **Validate every non-default answer against the `states` output** before
111
+ writing. A status moves by **workflow transition**: a name the project lacks
112
+ can never be reached, and the engine refuses loudly at push time rather than
113
+ path-finding — catching a renamed `Done` here is the whole reason this step
114
+ exists.
115
+ - Where a configured or offered name is not in the list, show the real names
116
+ and ask which one means that bucket here — the mapping is the user's call,
117
+ never a guess.
118
+
119
+ Each answer that differs from the defaults becomes a `--state <bucket>=<name>`
120
+ flag in step 6.
121
+
122
+ ## 6. Write it
123
+
124
+ ```
125
+ skitterspec spec-sync init-config \
126
+ --site-url https://<site>.atlassian.net --project-key PROJ \
127
+ [--issue-type Task] [--subtask-type Subtask] \
128
+ [--state <bucket>=<name> …] [--force] [--json]
129
+ ```
130
+
131
+ The engine writes **only the keys that differ from the defaults**, so the file
132
+ shows this repo's choices and keeps inheriting everything else. `--force` is
133
+ required to replace an existing config — never pass it without the user having
134
+ asked for a rewrite in step 1.
135
+
136
+ **Relay the engine's report as printed.** It names the site, the project key,
137
+ the issue types and the state mapping it wrote — that report is the evidence
138
+ the setup is right, so don't paraphrase it into "done".
139
+
140
+ ## 6b. Let `/spec-start` commit the snapshot with its spec
141
+
142
+ **Only when `specs/.core/env.config.json` exists** (per-spec isolation is on).
143
+ If it is absent, skip this — there is nothing to configure.
144
+
145
+ **Check before you write — a fresh install may already have this.** When this
146
+ superset's `init --isolation` wrote the `env.config.json`, both keys below are
147
+ seeded; this step is the **retrofit** for a project that adopted isolation
148
+ before installing the Jira provider, or ran `/spec-jira-setup` before adopting
149
+ it.
150
+
151
+ `/spec-start` commits an uncommitted spec for you, but only the paths it can
152
+ prove belong to that spec. Its own folder always does; this repo's per-spec
153
+ Jira snapshot (`sync.baseDir`, `specs/.core/jira-base/<ID>.base.json`) does
154
+ not, because the base engine is deliberately tracker-free and cannot know that
155
+ path exists. Declare it once, in `env.config.json`:
156
+
157
+ ```json
158
+ "spec": {
159
+ "companionPaths": ["specs/.core/jira-base/{identifier}.base.json"]
160
+ }
161
+ ```
162
+
163
+ `{identifier}` resolves through `branch.identifierField`, so **set that too** if
164
+ it is still empty — `"jira_identifier"` is the field `/spec` stamps. Without
165
+ it the pattern expands to nothing and the snapshot is treated as another spec's
166
+ file: `/spec-start` then refuses the tree instead of committing it, which is the
167
+ safe failure but a needless one.
168
+
169
+ Leave both alone if the user has already set them.
170
+
171
+ ## 7. Report and hand off
172
+
173
+ **Finish by checking, not by describing.** Run:
174
+
175
+ ```
176
+ skitterspec spec-sync doctor
177
+ ```
178
+
179
+ and relay its table. That is the difference between a summary of what setup
180
+ *meant* to do and a check of what is actually true — including the layers this
181
+ skill never touched (the scaffold, isolation). Every row that needs attention
182
+ names its own fix, so there is nothing to paraphrase.
183
+
184
+ It exits non-zero only when a layer is **broken** — configured but wrong. A
185
+ `missing` row is an opt-in nobody took, which is fine; report it, don't treat
186
+ it as a failure.
187
+
188
+ Then name the next step:
189
+
190
+ - `/spec` — write a spec; with Jira configured it creates the linked issue in
191
+ the configured project and stamps the key.
192
+ - `/spec-status` — read-only report of what would push, the safe way to prove
193
+ the link works.
194
+ - `/spec-push` — send a spec up.
195
+
196
+ Mention what setup did **not** configure, so the defaults aren't mistaken for
197
+ decisions: phase mapping (`mapping.phases` — subtask per phase by default) and
198
+ field ownership. Point at `jira.config.md` for those. Assignment sync is not
199
+ yet supported by the Jira provider, so there is no identity to settle here.
200
+
201
+ End with the block defined in `.claude/rules/spec-reports.md`. That file carries
202
+ the shape; this section carries only what is specific here.
203
+
204
+ **The `doctor` table goes above the block, verbatim.** It is a check rather than
205
+ a summary, and every row that needs attention names its own fix — paraphrasing
206
+ it into fields would lose exactly that.
207
+
208
+ **Verdicts**
209
+
210
+ - `✅` — every layer `doctor` checked is configured and working.
211
+ - `⚠️` — configured, with a `missing` row: an opt-in nobody took, which is fine.
212
+ Report it; do not treat it as a failure.
213
+ - `❌` — a `broken` row: configured but wrong. Relay the row and its fix.
214
+ - `⏸` — an existing config was reviewed and left alone, or Jira could not be
215
+ reached. Nothing was written.
216
+
217
+ **Fields:** `Built` · `Follow-ups` · `Next`
218
+
219
+ `Built` is the config written or reviewed, plus what was deliberately left
220
+ unset. **The credentials are never a field** — `doctor` already reports whether
221
+ they are set, masked, and the values are the user's alone.
@@ -0,0 +1,173 @@
1
+ ---
2
+ name: spec-list
3
+ description: List every spec Jira holds — key, title, status, and the local spec folder name to paste into /spec-start. Read-only, and it starts nothing. Falls back to the repo's own listing when Jira is unreachable. Opt-in — needs specs/.core/jira.config.json. Use when the user says "/spec-list", "what specs are there", "what is in the backlog", or "list specs from Jira".
4
+ disable-model-invocation: true
5
+ ---
6
+
7
+ # /spec-list — every spec Jira holds
8
+
9
+ > Stay silent while this runs — speak only to ask something you cannot answer
10
+ > yourself, or to report a failure at the moment it happens. Read
11
+ > `.claude/rules/spec-reports.md` before reporting; it defines the block this
12
+ > skill ends with.
13
+
14
+ Read-only. It answers a question and writes nothing — no branch, no folder move,
15
+ no Jira write.
16
+
17
+ Why ask Jira rather than `ls specs/`? Because `/spec-start` moves a spec to
18
+ `specs/in-progress/` **on that spec's own branch**. On the base branch an
19
+ in-flight spec still reads `backlog`, and a teammate's unlanded spec is not on
20
+ disk at all. Jira knows what is actually in progress; the repo knows what each
21
+ issue is **called on disk**. The listing joins the two.
22
+
23
+ **Opt-in**: only runs when `specs/.core/jira.config.json` exists. If absent,
24
+ tell the user how to enable Jira sync (`/spec-jira-setup`) and stop.
25
+
26
+ ## 1. Turn the question into flags
27
+
28
+ The user asks in plain language; the engine takes flags. Map, then run:
29
+
30
+ | They ask | Flags |
31
+ |----------|-------|
32
+ | "what specs are there", "/spec-list" | *(none — the live default)* |
33
+ | "what's done", "everything" | `--all` |
34
+ | "what's cancelled", a named status | `--state "<name>"` (repeatable) |
35
+
36
+ The default scope is **live** — whatever `config.states` maps `backlog` and
37
+ `in-progress` to. It is deliberately not everything: in a project with any
38
+ history, Done dwarfs the rows anyone wanted.
39
+
40
+ `--state` and `--all` are **alternatives**, and the engine refuses the pair
41
+ rather than letting one win silently.
42
+
43
+ The Linear provider's `--mine`, `--by` and `--next` filters are
44
+ **not yet shipped for the Jira provider** — assignee filtering and backlog
45
+ ordering wait on identity support. Say so when one is asked for, rather than approximating it.
46
+
47
+ ## 2. Run the engine
48
+
49
+ ```
50
+ skitterspec spec-sync list [--state <name> …|--all] [--json]
51
+ ```
52
+
53
+ - **`transport = api`** (credentials resolve) → it queried Jira and printed the
54
+ listing. **Relay its output verbatim** and stop. Do not re-format it and do not
55
+ make Jira calls of your own — the engine already joined the local spec
56
+ folders on.
57
+ - **`transport = mcp`** → the engine made no call. Go to step 3.
58
+ - Anything else it prints on one `spec-sync list:` line is a **degradation**, not
59
+ a crash — go to step 4.
60
+
61
+ ## 3. The MCP path
62
+
63
+ Only when the engine said `transport = mcp`. Discover the issue **search** tool
64
+ at runtime the way `/spec-push` describes (`searchJiraIssuesUsingJql`). If Jira
65
+ isn't connected or the tool is missing, go to step 4 — do not stop with nothing.
66
+
67
+ Then build one JQL query per run:
68
+
69
+ - **Scope by status.** The live default is
70
+ `project = <jira.projectKey> AND status IN ("<backlog>", "<in-progress>")`
71
+ with the names from `config.states`; `--state` substitutes the named
72
+ status(es); `--all` drops the status clause entirely.
73
+ - **Filter out phase subtasks in the query** — add
74
+ `AND issuetype NOT IN subtaskIssueTypes()`. A spec is a standard issue; a
75
+ phase is a subtask, and a listing that includes them buries the specs.
76
+ - **Ask for the fields you print** — `summary` and `status`; the key rides on
77
+ every result, and the browse url is `<siteUrl>/browse/<key>`.
78
+ - **Page, and never cap silently.** Follow the tool's pagination until it runs
79
+ out. If you stop early, say so on its own line and say what you stopped at.
80
+
81
+ **The current phase, on in-progress rows only.** For each row whose status is
82
+ the in-progress one, search again with `parent = <key>` and the same fields.
83
+ Order the children by **key**, numerically — subtasks are minted in phase
84
+ order, so the key carries it. Print the live one as `2/5 — <title>`. Three
85
+ shapes, none of them guessed at:
86
+
87
+ - **No child in progress** — print nothing extra. A spec sits between phases all
88
+ the time; that is not a missing phase.
89
+ - **More than one** — print the lowest-numbered, then append
90
+ `(+N more in progress)`. Two people on one spec is real, not an error.
91
+ - **`mapping.phases` is `inline` for this spec's bucket** — skip the call
92
+ entirely. Those phases live in the spec issue's own description, so there are
93
+ no subtasks, and asking would report "no phase in progress" for a spec that is
94
+ mid-build.
95
+
96
+ Do **not** make this call for backlog, done or cancelled rows — one lookup per
97
+ in-progress row is the budget, and there are rarely many.
98
+
99
+ Then join locally — no second Jira call:
100
+
101
+ ```
102
+ skitterspec spec-sync linked --json
103
+ ```
104
+
105
+ That is `[{ spec, bucket, identifier }]`. Key it by `identifier` and attach each
106
+ issue's local `spec` folder name. Format the rows exactly as the API path does
107
+ (step 5), including the `showing N of M` count.
108
+
109
+ ## 4. Degrade — never leave them with nothing
110
+
111
+ Jira unreachable, no credential, no MCP tool, a Jira error: **do not stop**.
112
+ Print the local listing instead:
113
+
114
+ ```
115
+ skitterspec spec-sync linked --json
116
+ ```
117
+
118
+ Show `spec`, `bucket` and `identifier`, under a one-line banner naming what is
119
+ missing and why it may be wrong:
120
+
121
+ ```
122
+ Jira unreachable (<reason>) — this is the repo's own listing.
123
+ Buckets are this branch's; a spec someone else has started still reads "backlog" here.
124
+ ```
125
+
126
+ That caveat is the point of the banner. A local bucket is not evidence of a
127
+ spec's real state — it is evidence of what this branch knows, which is exactly
128
+ what the command exists to go beyond. A query command that fails closed is one
129
+ people stop typing.
130
+
131
+ ## 5. Report
132
+
133
+ Relay the listing. Whatever the path, three things must survive into what the
134
+ user reads:
135
+
136
+ - **The count, as `showing N of M`.** If they are not the same number, say what
137
+ was left out and how to see it.
138
+ - **The phase, on in-progress rows** — `2/5 — <title>`, after the status.
139
+ - **A row with no local match stays in**, marked `— (not linked here)`. It is not
140
+ noise: a teammate's unlanded spec, or one authored inside another spec's
141
+ worktree, is precisely what the repo could not have told them.
142
+
143
+ Finish with the hand-off, because every row carries the folder name for it —
144
+ as a sentence, not a fenced block: say that `/spec-start <name>` starts any of
145
+ them, with the name copied from a row.
146
+
147
+ **Never start it yourself.** `/spec-start` provisions a branch, moves a folder
148
+ and commits, and it has dirty-tree refusals this skill does not reproduce.
149
+ Offering the name is the whole job.
150
+
151
+ End with the block defined in `.claude/rules/spec-reports.md`. That file carries
152
+ the shape; this section carries only what is specific here.
153
+
154
+ **The listing goes above the block, unflattened.** It is rows of other people's
155
+ work; the block is the verdict on this run of the query. Do not fold the listing
156
+ into fields, and do not repeat it there.
157
+
158
+ **Verdicts**
159
+
160
+ - `✅` — the listing is Jira's, joined to the local folder names.
161
+ - `⚠️` — listed, with a caveat that changes how the rows read: a paging cap you
162
+ stopped at, or the local fallback listing under its banner.
163
+ - `⏸` — refused before acting: no config, so there is nothing to list against.
164
+ - `❌` — the query was wrong: `--state` and `--all` together, or a status name
165
+ Jira rejects.
166
+
167
+ **Fields:** `Follow-ups` · `Next`
168
+
169
+ **No `Tracker` row.** This skill names many specs and owns none, so an id row
170
+ would have to pick one. The counts — `showing N of M` — belong to the listing
171
+ above, where the engine already prints them.
172
+
173
+ `Next` is the hand-off: `/spec-start <name>`, with a name copied from a row.