@gallopsystems/agent-skills 1.29.0 → 1.30.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.
@@ -1,104 +1,48 @@
1
1
  ---
2
2
  name: linear
3
- description: Create, triage, and manage Linear issues at Gallop Systems following the team's workflow conventions — cycle placement, issue templates, project/milestone hierarchy, and project refresh / cycle rebalance procedures. Use whenever the user asks for Linear work (creating issues, planning cycles, refreshing projects) on a Gallop client.
3
+ description: Create, triage, and manage Linear issues at Gallop Systems following the team's workflow conventions — issue status, issue templates, and the project/milestone hierarchy. Use whenever the user asks for Linear work (creating or updating issues, placing work in projects and milestones) on a Gallop client.
4
4
  ---
5
5
 
6
- # Linear Project Management — Team Workflow & CLI Guide
6
+ # Linear — Gallop Team Workflow
7
7
 
8
- ## The CLI
9
-
10
- The fallback tooling is a single zero-dependency Node script, `bin/linear.mjs`. It runs on bare `node` (v18.3+ — no `npm install`, no `tsx`, no build step) and uses symbolic names instead of raw UUIDs (`--state todo`, `--assignee frontend`, `--labels bug,frontend`, `--cycle current`).
11
-
12
- Invoke it as `node <skill>/bin/linear.mjs <command> [args] [--flags]`. Examples below write `node linear.mjs` for brevity — use the full path to the file, or `cd` into the skill's `bin/` directory first. Run `node linear.mjs help` for the full command list.
13
-
14
- ## First-time Setup (run once per user)
15
-
16
- ### Check 1 — Workspace bootstrap config exists
17
-
18
- Before running any `linear.mjs` command, verify that the per-user workspace config exists at `~/.config/linctl/workspace.json` (override path with `$LINCTL_WORKSPACE_FILE`). This file holds **every team** in the workspace (each with its own UUID plus its workflow-state and label UUIDs — states differ per team), an optional `defaultTeam`, and the Linear member UUIDs that play the Frontend/PM and Backend roles. Without it, every command that needs the team, members, states, or labels will refuse to run.
8
+ ## Linear Tooling — MCP First, `linear.mjs` as Fallback
19
9
 
20
- > **Multi-team workspaces:** `workspace.json` registers all teams, but `states`/`labels` are per-team (each team's `Todo` is a distinct UUID). Which team a command targets is resolved in this order: the **`--team <key|name|uuid>`** flag → the **`LINCTL_DEFAULT_TEAM`** env var (a per-repo default — set it via direnv/`.envrc` or your shell so every command in a repo targets that team) → the **`defaultTeam`** field in `workspace.json`. If none resolve, `--team` is **required** on team-scoped commands; workspace-wide commands (e.g. `list-initiatives`) work without a team. A legacy config (predating per-team support, i.e. with no `defaultTeam` key and top-level `states`/`labels`) still works — it falls back to the first registered team — but re-run `init` to migrate it to the per-team schema.
10
+ **Default to the Linear MCP server (`mcp__linear__*` tools)** for all standard operations: creating/updating issues, listing projects/milestones/cycles/initiatives/labels/users, comments, etc. The MCP tools take strings directly — pass real markdown with real newlines, no JSON-escaping.
21
11
 
22
- ```bash
23
- [ -f "${LINCTL_WORKSPACE_FILE:-$HOME/.config/linctl/workspace.json}" ] && echo "ok" || echo "missing"
24
- ```
12
+ **Use `linear.mjs` only for things MCP doesn't expose:**
13
+ - `batch-move-to-milestone` — rate-limit-aware bulk moves
14
+ - `add-initiative-link` — adding external links to initiatives
15
+ - `api` — raw GraphQL escape hatch
25
16
 
26
- **If missing,** instruct the user to run:
17
+ For those, read [`cli.md`](cli.md) — it covers the CLI's one-time setup (workspace config, `LINEAR_API_KEY`) and every command's syntax.
27
18
 
28
- ```bash
29
- node linear.mjs init
30
- ```
19
+ **Verify every MCP write.** `mcp__linear__save_issue` has been seen returning success without applying `labels` or the milestone — and its response echo can omit fields it did apply. After each create/update, re-read the issue with `mcp__linear__get_issue` and confirm labels, project, and milestone are all set. Pass UUIDs rather than names for those fields; if one still won't stick, set it with `linear.mjs api` (`issueUpdate` with `labelIds` / `projectMilestoneId`). Don't report the issue as done until it verifies.
31
20
 
32
- `init` calls Linear's GraphQL API, lists the workspace's members, and prompts the user to designate (1) the Frontend/PM lead and (2) the Backend lead by number, then (3) an optional default team key (blank = no default, so `--team` is required on each team-scoped call). It registers **all** teams with their per-team states/labels and writes `~/.config/linctl/workspace.json`. The config is read fresh on every invocation — no re-sourcing needed.
21
+ **Write serially.** Linear can drop rapid-fire mutations and still return success. Make MCP writes one at a time — never in parallel — and verify as above.
33
22
 
34
- ### Check 2 — Linear MCP server installed and authorized
23
+ ### MCP setup check
35
24
 
36
- This skill routes most operations through `mcp__linear-server__*` tools. Before doing any Linear work, verify the MCP server is available:
25
+ This skill routes most operations through `mcp__linear__*` tools. Before doing any Linear work, verify the MCP server is available:
37
26
 
38
- - **Not installed:** if no `mcp__linear-server__*` tools appear in your toolset, stop and tell the user: *"This skill needs Linear's MCP server. Install it with `claude mcp add --transport sse linear https://mcp.linear.app/sse`, restart Claude Code, then tell me to continue."* Don't try to fall back to `linear.mjs` for everything — the CLI only covers a small subset of operations.
39
- - **Installed but not authorized:** if a `mcp__linear-server__*` call returns an auth/OAuth error, tell the user: *"The Linear MCP server is installed but not authorized. The next call will open a browser to sign in — please complete OAuth, then tell me to continue."*
27
+ - **Not installed:** if no `mcp__linear__*` tools appear in your toolset, stop and tell the user: *"This skill needs Linear's MCP server. Install it with `claude mcp add --transport sse linear https://mcp.linear.app/sse`, restart Claude Code, then tell me to continue."* Don't try to fall back to `linear.mjs` for everything — the CLI only covers a small subset of operations.
28
+ - **Installed but not authorized:** if a `mcp__linear__*` call returns an auth/OAuth error, tell the user: *"The Linear MCP server is installed but not authorized. The next call will open a browser to sign in — please complete OAuth, then tell me to continue."*
40
29
 
41
30
  Don't silently skip these checks. A user who hits an MCP error mid-task without context will be confused.
42
31
 
43
- ### Check 3 — `LINEAR_API_KEY` for the CLI
44
-
45
- `linear.mjs` reads `LINEAR_API_KEY` from the environment. Before using any command, check whether it's set:
46
-
47
- ```bash
48
- [ -n "$LINEAR_API_KEY" ] && echo "set" || echo "missing"
49
- ```
50
-
51
- **If missing, onboard the user:**
52
-
53
- 1. Tell them: *"I need a Linear personal API key to run the CLI. Create one at https://linear.app/settings/account/security (click 'New API key', name it 'Claude Code', copy the `lin_api_...` token), then paste it here in chat."*
54
- 2. When they paste the key, install it into `~/.zshenv` so every future shell — including the ones Claude Code spawns — picks it up automatically:
55
- ```bash
56
- echo 'export LINEAR_API_KEY=lin_api_THEIR_KEY_HERE' >> ~/.zshenv
57
- ```
58
- (Use `~/.bashrc` instead if the user is on bash.)
59
- 3. Export it in the current shell too so the next tool call works without restart:
60
- ```bash
61
- export LINEAR_API_KEY=lin_api_THEIR_KEY_HERE
62
- ```
63
- 4. Verify with a harmless call: `node linear.mjs list-members`.
64
-
65
- **Never commit the key, never write it into `.env` or any project file** — `~/.zshenv` is the single source of truth.
66
-
67
- ---
68
-
69
- ## Team Overview
70
-
71
- - **Workspace Team Key:** `GAL`
72
- - **Team Size:** 2 members
73
- - **Sprint Cycle:** 2 weeks
74
- - **Stack:** Nuxt 4 (Vue frontend + Nitro backend)
75
- - **Work Type:** Client/agency projects
76
-
77
- ### Team Roles
78
-
79
- | Role | Responsibilities |
80
- |------|-----------------|
81
- | **Frontend/PM Lead** | Frontend development, requirement gathering, project design, client communication, light backend (e.g., adding endpoints), issue triage, client IT coordination (DNS, infrastructure requests) |
82
- | **Backend Lead** | Data modeling, database design, backend architecture, API logic |
83
-
84
- The Frontend/PM lead triages incoming client requests and translates them into Linear issues.
85
-
86
- On first run, `node linear.mjs init` binds these roles to specific Linear members; Claude reads `~/.config/linctl/workspace.json` to know who they are. Pass `--assignee frontend` or `--assignee backend` and the CLI resolves it to the corresponding Linear user UUID.
87
-
88
32
  ---
89
33
 
90
34
  ## Workflow Statuses
91
35
 
92
- | Status | Meaning |
93
- |--------|---------|
94
- | **Backlog** | Captured but not yet planned for a cycle |
95
- | **Todo** | Committed to the current or next cycle |
96
- | **In Progress** | Actively being worked on |
97
- | **In Review** | Code complete, awaiting review or client feedback |
98
- | **Done** | Shipped and verified |
99
- | **Canceled** | Dropped or no longer relevant |
100
-
101
- > **Note:** "In Review" is a recommended addition to the default Linear statuses. It provides a clear handoff point for code review between the two team members and for client sign-off.
36
+ | Status | Meaning | Move here when |
37
+ |--------|---------|----------------|
38
+ | **Triage** | Raw incoming request, not yet shaped into a real issue | Client-portal submissions land here automatically — work them with the `linear-triage` skill |
39
+ | **Backlog** | Captured, being fleshed out, not yet ready for work | Default for every issue an agent creates |
40
+ | **Todo** | Fully fleshed out and ready for work | Only when the user says so — never on the agent's own judgement |
41
+ | **In Progress** | Actively being worked on | Work on it starts |
42
+ | **In Review** | Code complete, awaiting review or client feedback | A PR is open for review, or the change is waiting on client sign-off |
43
+ | **Done** | Shipped and verified | Merged/deployed and verified |
44
+ | **Canceled** | Dropped or no longer relevant | The work is no longer wanted |
45
+ | **Duplicate** | Same work as another issue | Another issue already covers it — mark it a duplicate of that issue rather than canceling |
102
46
 
103
47
  ---
104
48
 
@@ -107,353 +51,142 @@ On first run, `node linear.mjs init` binds these roles to specific Linear member
107
51
  | Priority | When to Use |
108
52
  |----------|-------------|
109
53
  | **Urgent** | Production issues, client-blocking bugs, deadline-critical items |
110
- | **High** | Current sprint commitments, important client deliverables |
54
+ | **High** | Important client deliverables, work that should be picked up next |
111
55
  | **Medium** | Planned work, non-blocking improvements |
112
56
  | **Low** | Nice-to-haves, tech debt, internal tooling |
113
57
 
114
- ---
115
-
116
- ## Labels (Recommended)
117
-
118
- ### By Type
119
- - `bug` — Something is broken
120
- - `feature` — New functionality
121
- - `improvement` — Enhancement to existing functionality
122
- - `chore` — Maintenance, config, devops, dependencies
123
- - `spike` — Research or investigation task
124
-
125
- ### By Domain
126
- - `frontend` — UI/UX, Vue components, pages, styling
127
- - `backend` — API, database, data modeling, server logic
128
- - `fullstack` — Touches both frontend and backend
58
+ The MCP server and the CLI take priority as a number: `0` none, `1` Urgent, `2` High, `3` Medium, `4` Low.
129
59
 
130
60
  ---
131
61
 
132
- ## Estimation (T-Shirt Sizes)
133
-
134
- | Size | Meaning | Rough Effort |
135
- |------|---------|-------------|
136
- | **S** | Small, well-understood task | A few hours |
137
- | **M** | Medium complexity, clear scope | Half a day to a full day |
138
- | **L** | Large, may span multiple days | 2–3 days |
139
- | **XL** | Very large — consider breaking down | 3+ days, likely needs subtasks |
62
+ ## Labels
140
63
 
141
- If an issue is XL, break it into smaller sub-issues before starting work.
64
+ These are the labels that exist in the workspace — use only these; don't invent new ones. All are workspace-level, so every team has the same set with the same UUIDs.
142
65
 
143
- ---
66
+ ### By Type (pick one)
67
+ - `Bug` — Something is broken
68
+ - `Feature` — New functionality
69
+ - `Improvement` — Enhancement to existing functionality
70
+ - `Tech Debt` — Maintenance, refactors, test/CI gaps, dependencies, config — work with no user-facing change
71
+ - `Discovery` — Research, investigation, or a decision to be made before building (what other teams call a spike)
144
72
 
145
- ## Sprint Cycle Process
73
+ ### By Domain (apply every one the issue touches)
74
+ - `Frontend` — UI/UX, Vue components, pages, styling
75
+ - `Backend` — API handlers, server logic, integrations
76
+ - `DB` — Schema changes, migrations, data modeling
146
77
 
147
- ### Cycle Start (Every 2 Weeks)
148
- 1. Review **Backlog** — pull items into **Todo** for the cycle
149
- 2. Assign issues to the appropriate team member based on domain (backend vs. frontend)
150
- 3. Ensure each issue has: priority, estimate, label(s), and assignee
151
- 4. Keep cycle scope realistic — a 2-person team should commit to what's achievable
78
+ There is no `fullstack` label — an issue that touches several layers carries each of them (e.g. `Backend`, `Frontend`, `DB`).
152
79
 
153
- ### During the Cycle
154
- - Move issues to **In Progress** when you start working on them
155
- - Move to **In Review** when code is ready for review or client feedback
156
- - Move to **Done** when merged/deployed and verified
157
- - If scope changes, add new issues to **Backlog** unless they're urgent
158
-
159
- ### Cycle End
160
- - Review what got done vs. what was planned
161
- - Move incomplete **Todo** / **In Progress** items to the next cycle or back to **Backlog**
162
- - Archive the completed cycle
80
+ ### Status Flags (add alongside type + domain)
81
+ - `client-request` — Originated from the client (e.g. a client-portal submission) rather than from us
82
+ - `Needs Clarification` — Open questions for the client/requester must be answered before the work can be finished
83
+ - `agent blocked` — An AI agent working the issue hit something it can't resolve and needs a human
163
84
 
164
85
  ---
165
86
 
166
- ## Linear Tooling — MCP First, `linear.mjs` as Fallback
167
-
168
- **Default to the Linear MCP server (`mcp__linear__*` tools)** for all standard operations: creating/updating issues, listing projects/milestones/cycles/initiatives/labels/users, comments, etc. The MCP tools take strings directly — pass real markdown with real newlines, no JSON-escaping.
169
-
170
- **Use `linear.mjs` only for things MCP doesn't expose:**
171
- - `cycle-capacity` — velocity-based capacity % (used in cycle placement & rebalancing)
172
- - `batch-move-to-cycle` / `batch-move-to-milestone` — rate-limit-aware bulk moves
173
- - `add-dependency` / `remove-dependency` / `list-dependencies` — issue relations
174
- - `add-initiative-link` — adding external links to initiatives
175
- - `api` — raw GraphQL escape hatch
176
-
177
- **Mapping** of common CLI → MCP equivalents lives in `MEMORY.md`. The sections below document the CLI for the fallback paths and for reference; prefer the MCP tool whenever one exists.
178
-
179
- ### The CLI
180
-
181
- `bin/linear.mjs` wraps the Linear GraphQL API. It runs on bare `node` (v18.3+, no install) and reads `LINEAR_API_KEY` from the environment plus the workspace config from `~/.config/linctl/workspace.json`. There is nothing to source — every invocation loads config fresh.
182
-
183
- ```bash
184
- node linear.mjs help # full command list
185
- ```
186
-
187
- ### Symbolic names (no UUIDs needed)
188
-
189
- The CLI resolves friendly names against `workspace.json`, so you rarely need raw UUIDs:
87
+ ## Estimation (T-Shirt Sizes)
190
88
 
191
- ```
192
- --team ACME | "Acme Corp" (team key or name) (or a UUID)
193
- --state todo | backlog | "in progress" | "in review" | done | canceled (or a UUID)
194
- --assignee frontend | backend (or a UUID)
195
- --labels bug,frontend,feature (comma-separated label names) (or UUIDs)
196
- --priority 0-4 or none | urgent | high | medium | low
197
- --cycle current (the active cycle) (or a UUID)
198
- ```
89
+ | Size | Value | Meaning | Rough Effort |
90
+ |------|-------|---------|-------------|
91
+ | **No estimate** | `null` | Not yet sized | — |
92
+ | **-** | `0` | Trivial — effectively no effort (a config flip, a copy change) | Minutes |
93
+ | **XS** | `1` | Tiny, obvious change | Under an hour or two |
94
+ | **S** | `2` | Small, well-understood task | A few hours |
95
+ | **M** | `3` | Medium complexity, clear scope | Half a day to a full day |
96
+ | **L** | `5` | Large, may span multiple days | 2–3 days |
97
+ | **XL** | `8` | Very large — consider breaking down | 3+ days, likely needs subtasks |
199
98
 
200
- `--team` selects which team a team-scoped command runs against, and `--state`/`--labels` then resolve against **that team's** states and labels. When `--team` is omitted it falls back to `$LINCTL_DEFAULT_TEAM` (a per-repo default) and then to `workspace.json`'s `defaultTeam`; if none are set you'll get an error listing the registered team keys. Workspace-wide commands (initiatives) don't need a team. Any value that's already a UUID is passed through untouched. Project and milestone IDs are still UUIDs (pass them with `--project` / `--milestone`).
201
-
202
- ### Creating Issues
203
-
204
- > **Important:** When assigning an issue to a cycle, always set `--state todo`. Issues default to Backlog, which doesn't work with cycles — they must be in Todo status.
205
- >
206
- > **Required placement rule:** Never create an issue without both `--project` and `--milestone`. **The project must already exist** — place the issue in the initiative's existing `M` project for the milestone it falls under, and never conjure a project to hold it (see "Never invent a project"). Creating a project is only correct for a confirmed out-of-scope revision. If the project exists but the right milestone does not, create the milestone first. Do not leave issues unscoped or unmilestoned.
207
- >
208
- > **Never target a completed milestone.** New work never belongs in a milestone that is already done — it distorts the completed phase and hides the issue from the team's current view. Only place an issue in an **open** milestone. If no open milestone matches the issue, create a new one and use that; do not reopen or reuse a completed milestone.
209
- >
210
- > **Confirm decisions with the requester — don't punt them into the issue.** When the person asking you to create the issue is right there in the conversation, ask the open decisions (scope, mechanism, data source, ownership, who/where it should land) *before* writing the issue — e.g. via a structured question prompt — and bake the confirmed answers into the body. Do **not** write an "Open questions" section full of decisions you could have just asked, and do **not** use that manufactured uncertainty as a rationale to leave the issue in Backlog or unassigned. Only genuinely external unknowns (something that needs a meeting, a client, or a spike to resolve) belong as open questions; everything the requester can answer on the spot should already be a confirmed decision with the issue placed and assigned accordingly.
211
-
212
- ```bash
213
- # --state todo is required when using --cycle
214
- # --project and --milestone are always required
215
- node linear.mjs create-issue \
216
- --title 'Add user profile page' \
217
- --description 'Create /profile page with user info and settings' \
218
- --priority high \
219
- --state todo \
220
- --assignee frontend \
221
- --labels feature,frontend \
222
- --estimate 3 \
223
- --project 'project-uuid-here' \
224
- --milestone 'milestone-uuid-here' \
225
- --cycle current
226
-
227
- # Create a bug report
228
- node linear.mjs create-issue \
229
- --title 'Fix: login redirect fails on Safari' \
230
- --description 'Users on Safari not redirected after login. Reproduced on Safari 17.' \
231
- --priority urgent \
232
- --state todo \
233
- --assignee frontend \
234
- --labels bug,frontend \
235
- --project 'project-uuid-here' \
236
- --milestone 'milestone-uuid-here' \
237
- --cycle current
238
-
239
- # Long descriptions: pass a file instead of inline text (no shell-escaping)
240
- node linear.mjs create-issue --title 'Investigate perf issue' --state todo \
241
- --description-file ./issue-body.md \
242
- --project 'project-uuid' --milestone 'milestone-uuid'
243
-
244
- # Find the existing M project for the milestone this work falls under — do not create one.
245
- # (Prefer the MCP `get_initiative` with includeProjects; this lists them via the CLI.)
246
- node linear.mjs list-projects # copy the [KEY] M<n> project's UUID
247
- PROJECT_ID='project-uuid-here'
248
- # Only the milestone may be created as part of intake
249
- MILESTONE_ID="$(node linear.mjs create-milestone "$PROJECT_ID" 'Phase 1' | node -e "process.stdin.once('data',d=>{const n=JSON.parse(d).data.projectMilestoneCreate.projectMilestone;console.log(n.id)})")"
250
- node linear.mjs create-issue --title 'Investigate performance issue' --state todo \
251
- --project "$PROJECT_ID" --milestone "$MILESTONE_ID" --cycle current
252
- ```
99
+ The MCP server and the CLI's `--estimate` both take the numeric **Value**, not the letter (e.g. `3` for M). If an issue is XL, break it into smaller sub-issues before starting work.
253
100
 
254
- ### Priority Values
255
- - `0` = No priority
256
- - `1` = Urgent
257
- - `2` = High
258
- - `3` = Medium
259
- - `4` = Low
101
+ ---
260
102
 
261
- ### Listing & Filtering Issues
262
- ```bash
263
- # List all issues (pretty table by default)
264
- node linear.mjs list-issues
103
+ ## Creating Issues
265
104
 
266
- # Filter by state type: backlog, unstarted, started, completed, canceled
267
- node linear.mjs list-issues started
105
+ **Create in Backlog, then ask about Todo.** Every issue an agent creates goes to **Backlog** — don't assign a cycle. After creating it, show the user the issue (link plus a short summary) and ask whether it's ready for **Todo**; move it only if they say yes.
268
106
 
269
- # List issues in current cycle
270
- node linear.mjs list-cycle-issues
107
+ **Required placement rule:** Never create an issue without both a project and a milestone. **The project must already exist** — place the issue in the initiative's existing `M` project for the milestone it falls under, and never conjure a project to hold it (see "Never invent a project"). Creating a project is only correct for a confirmed out-of-scope revision. The milestones in an `M` project are the proposal's deliverables and are fixed too — place the issue in the deliverable it falls under; if none fits, say so and ask whether it's a revision rather than creating a milestone. Do not leave issues unscoped or unmilestoned.
271
108
 
272
- # Raw JSON output (for piping) — add --json to any list command
273
- node linear.mjs list-issues --json
274
- node linear.mjs list-issues started --json
275
- ```
109
+ **Work under a completed deliverable → ask.** If the work falls under a milestone that's already completed, don't place it silently and don't create a new milestone to dodge it. Tell the requester the deliverable is done and ask whether this is within its signed scope (place it in that milestone) or a revision (it goes to an `R` project).
276
110
 
277
- ### Updating Issues
278
- ```bash
279
- # Move issue by status name
280
- node linear.mjs move-issue "issue-uuid" "In Progress"
281
- node linear.mjs move-issue "issue-uuid" "Done"
111
+ **Check for duplicates first.** Before creating an issue, search the team's open and recently completed issues for the same or overlapping work. If one exists, show the user its title, status, assignee, and link, and ask whether to skip, update/comment on the existing issue, or create the new one anyway because the scope differs. Never silently create a duplicate.
282
112
 
283
- # Assign to a team member by role
284
- node linear.mjs assign-issue "issue-uuid" frontend
285
- node linear.mjs assign-issue "issue-uuid" backend
113
+ **Closing a duplicate.** Comment on the duplicate explaining why and linking the original, then mark it with `duplicateOf` (MCP `save_issue`) — that moves it to the **Duplicate** status. Don't just cancel it.
286
114
 
287
- # General update — symbolic flags
288
- node linear.mjs update-issue "issue-uuid" --priority urgent --state todo
115
+ **Fill in everything you can.** Set priority, estimate, one type label plus every domain label it touches (see **Labels**), and an assignee (see **Assignment Guidelines**) as a best-effort draft — the user adjusts them while fleshing the issue out.
289
116
 
290
- # Or merge arbitrary raw JSON input with --raw
291
- node linear.mjs update-issue "issue-uuid" --raw '{"priority":1}'
292
- ```
117
+ **Confirm decisions with the requester — don't punt them into the issue.** When the person asking you to create the issue is right there in the conversation, ask the open decisions (scope, mechanism, data source, ownership, who/where it should land) *before* writing the issue — e.g. via a structured question prompt — and bake the confirmed answers into the body. Do **not** write an "Open questions" section full of decisions you could have just asked, and do **not** use that manufactured uncertainty as a rationale to leave fields blank or the issue unassigned. Only list something as an open question when the requester tells you it's an open question — never decide on your own that it needs a meeting, the client, or more investigation. Ask everything; whatever they answer becomes a confirmed decision, with the issue placed and assigned accordingly. Answers are folded into the issue body itself, not appended as a log of decisions — see "The body is the current spec" under **Issue Body Conventions**.
293
118
 
294
119
  ### Issue Dependencies
295
- ```bash
296
- # Create a "blocks" dependency (backend blocks frontend)
297
- node linear.mjs add-dependency "$BLOCKER_ISSUE_ID" "$BLOCKED_ISSUE_ID"
298
120
 
299
- # List all dependencies for an issue (both directions)
300
- node linear.mjs list-dependencies "$ISSUE_ID"
301
-
302
- # Remove a dependency by relation UUID (get UUID from list-dependencies)
303
- node linear.mjs remove-dependency "$RELATION_ID"
304
- ```
121
+ Use the MCP server for issue relations:
122
+ - **Add:** `mcp__linear__save_issue` with `blocks` / `blockedBy` (issue identifiers, e.g. `["ACME-12"]`). Append-only — existing relations are kept.
123
+ - **Remove:** `mcp__linear__save_issue` with `removeBlocks` / `removeBlockedBy`.
124
+ - **List:** `mcp__linear__get_issue` with `includeRelations: true` — returns `blocks`, `blockedBy`, `relatedTo`, and `duplicateOf`.
305
125
 
306
126
  ### Comments
307
- ```bash
308
- # Add a comment to an issue
309
- node linear.mjs add-comment "$ISSUE_ID" --body "Comment body text here"
310
-
311
- # Long comment from a file (no shell-escaping)
312
- node linear.mjs add-comment "$ISSUE_ID" --body-file ./comment.md
313
- ```
314
127
 
315
- > **Note:** Always use `@` mentions when referring to team members in comments. Use the Linear `@` mention syntax with the team member's display name from `workspace.json`'s `roles` (e.g., `@<Frontend Lead Name>`, `@<Backend Lead Name>`) so they get properly notified.
128
+ Always use `@` mentions when referring to team members in comments. Use the Linear `@` mention syntax with the team member's display name from `workspace.json`'s `roles` (e.g., `@<Frontend Lead Name>`, `@<Backend Lead Name>`) so they get properly notified.
316
129
 
317
- ### Searching
318
- ```bash
319
- node linear.mjs search-issues "login bug"
320
- ```
321
-
322
- ### Projects & Milestones
323
- ```bash
324
- # Create a new project (linked to an initiative)
325
- # Projects mirror the signed proposal's milestones ([KEY] M<n>) or a confirmed revision ([KEY] R<n>).
326
- # Never create one to hold work you couldn't place — see "Never invent a project".
327
- node linear.mjs create-project --name "[KEY] M1 — Milestone Name" --initiative "$INITIATIVE_ID" --description "Short description"
328
-
329
- # List all projects (pretty table with initiative, state, progress)
330
- node linear.mjs list-projects
331
-
332
- # List milestones within a project
333
- node linear.mjs list-milestones "$PROJECT_ID"
334
-
335
- # List issues grouped by milestone within a project
336
- node linear.mjs list-project-issues "$PROJECT_ID"
337
-
338
- # Raw JSON variants (for piping) — add --json
339
- node linear.mjs list-projects --json
340
- node linear.mjs list-milestones "$PROJECT_ID" --json
341
- node linear.mjs list-project-issues "$PROJECT_ID" --limit 200 --json
342
-
343
- # Create issue within a project/milestone
344
- node linear.mjs create-issue \
345
- --title 'Add feature X' \
346
- --project 'project-uuid' \
347
- --milestone 'milestone-uuid' \
348
- --priority high \
349
- --assignee frontend \
350
- --labels feature
351
- ```
130
+ ---
352
131
 
353
- ### Initiatives
354
- ```bash
355
- # Create a new initiative (= a newly signed proposal; a repeat client gets another one)
356
- node linear.mjs create-initiative --name "ClientName" --description "Short description"
132
+ ## Writing Issues
357
133
 
358
- # List all initiatives (pretty table with ID, status, description)
359
- node linear.mjs list-initiatives
134
+ > **Tech stack context:** All projects use Nuxt 4 + Nitro + Kysely + PostgreSQL + PrimeVue/Volt + Tailwind CSS v4. See `tech-stack.md` for full details.
360
135
 
361
- # Get full initiative detail by name (case-insensitive)
362
- node linear.mjs get-initiative-by-name "Northwind"
136
+ Read the examples before writing an issue — they show the voice and level of detail better than any rule:
363
137
 
364
- # Get full initiative detail by ID
365
- node linear.mjs get-initiative "$INITIATIVE_ID"
138
+ - [backend-feature.md](./examples/backend-feature.md) - Backend feature: behavior, business rules, explicit out-of-scope
139
+ - [backend-data-model.md](./examples/backend-data-model.md) - Data-model change described as rules, not columns
140
+ - [frontend-feature.md](./examples/frontend-feature.md) - Frontend feature with repo-verified UI Notes
141
+ - [small-improvement.md](./examples/small-improvement.md) - A small change kept small
142
+ - [discovery.md](./examples/discovery.md) - An open question with options and trade-offs
143
+ - [bug.md](./examples/bug.md) - Bug with a code-grounded root cause
144
+ - [right-and-wrong.md](./examples/right-and-wrong.md) - ❌/✅ pairs for the mistakes agents make most
366
145
 
367
- # Update initiative content (markdown) or description
368
- node linear.mjs update-initiative "$INITIATIVE_ID" --content-file ./initiative-notes.md
369
- node linear.mjs update-initiative "$INITIATIVE_ID" --description "Short description"
146
+ ### Voice
370
147
 
371
- # Add an external link (e.g., repo) as a resource on the initiative
372
- node linear.mjs add-initiative-link "$INITIATIVE_ID" "https://github.com/org/repo" "GitHub Repo"
148
+ - **Frame around intent, not the solution.** Open with whose problem this is and what they're trying to get done. The framing never describes the fix — that's what the rest of the issue is for.
149
+ - **Write like a person.** Plain words, the way you'd explain it to a teammate — "we", "right now", contractions are fine. Avoid abstract, stiff phrasing like "technicians stop being entities a visit points at"; say "instead of linking a visit to a technician record, the visit stores the name".
150
+ - **Describe things literally.** Documents, code, and systems don't speak, know, want, or ignore anything. Say what they do or contain: "the generated document doesn't include the tax line", not "the generated document is silent on tax"; "the list total doesn't include credits", not "the list ignores credits".
151
+ - **Never make up the reason.** The intent comes from the requester. If they didn't say why, ask them — don't guess, and don't pad it with benefits nobody mentioned ("will improve customer satisfaction").
152
+ - **Never make up what users do today.** If the app doesn't support something yet, don't guess at how people get by without it ("there's nowhere in the app to enter notes, so managers hand-write them on the printed copy"). Describe the current workaround only if the requester told you about it. Otherwise just say what's missing, or ask.
153
+ - **Terse.** A short framing, then the substance. No paragraphs of background.
154
+ - **Behavior and rules, not implementation.** State what has to be true, the business rules, and the edge cases. For backend work never prescribe tables, columns, types, indexes, constraints, endpoint shapes, or enum values — the Backend lead designs those. Naming *existing* code is fine.
155
+ - **Grounded in `main`.** Describe what the code does today, verified in the repo. Never point at a wireframe branch or scratch file (paste the substance instead), and never frame an issue around another issue's plan.
156
+ - **Explicit scope.** Say what's out of scope and whether existing data is converted ("Greenfield: no conversion of existing …").
373
157
 
374
- # Raw JSON of all initiatives
375
- node linear.mjs list-initiatives --json
376
- ```
158
+ ### Titles
377
159
 
378
- ### Info Commands
379
- ```bash
380
- node linear.mjs list-states # Workflow states
381
- node linear.mjs list-members # Team members
382
- node linear.mjs list-labels # Labels
383
- node linear.mjs list-cycles # All cycles
384
- node linear.mjs current-cycle-id # Current active cycle UUID
385
- ```
160
+ A plain, sentence-case statement of the outcome — "Send a quote by email from the platform", "Invoices list total doesn't include credits". **No prefixes of any kind**: no client key, no domain (`UI:`, `API:`), no `Fix:` / `Chore:` / `Spike:`. The team identifies the client; labels show type and domain.
386
161
 
387
- ---
162
+ ### Body layout
388
163
 
389
- ## Issue Templates
164
+ 1. **Doc header** — if the project has its project docs (see the `project-docs` skill) ("Our thinking", "How they operate"), always open with a line linking the sections this issue relies on, then `---`:
165
+ `**Context:** [Our thinking — <section>](url) · [How they operate — <section>](url)`
166
+ Attach the same links to the issue (`links` on `save_issue`).
167
+ 2. **`## Context`** — a few sentences on the intent: who's affected, what they're trying to do, and what gets in their way today. Not the solution.
168
+ 3. **The type's sections** (below).
169
+ 4. **`## Acceptance criteria`** — checkboxes describing observable outcomes; end with `Tests written` for any code work.
390
170
 
391
- > **Tech stack context:** All projects use Nuxt 4 + Nitro + Kysely + PostgreSQL + PrimeVue/Volt + Tailwind CSS v4. See `tech-stack.md` for full details.
171
+ | Type | Sections after Context |
172
+ |------|------------------------|
173
+ | **Backend** (incl. data model) | `## Functionality` — bullets of behavior, rules, edge cases, out-of-scope |
174
+ | **Frontend** | `## Requirements` (checkboxes) · `## UI Notes` — repo-verified pages/components, Volt components, "Follow DESIGN_LANGUAGE.md". If the repo can't be checked, leave paths out — no "To Determine" / TBD section. |
175
+ | **Bug** | `## Bug` (what happens vs. what should) · `## Root cause` · `## Steps to reproduce` · `## Likely location` — replaces Context |
176
+ | **Discovery** | `## Open question` — the options, each with its trade-off. AC: settled with the client, recorded in "Our thinking", dependent issues updated. |
177
+ | **Tech Debt** | `## Requirements` · optional `## Files affected` |
392
178
 
393
- ### Issue Title Conventions
179
+ ### Links
394
180
 
395
- - **No client prefix** (e.g., ~~[GBX]~~) — the project name already identifies the client.
396
- - **No domain prefix** (e.g., ~~UI:~~, ~~API:~~) — labels (`frontend`, `backend`) already cover this.
397
- - Titles should be concise and describe the feature/fix directly (e.g., "Add provider create form", "Fix login redirect on Safari").
181
+ - Link an issue **inline, by identifier, where the body first mentions the thing it owns** (`…the scheduler shows a warning when they don't match (KEY-92)…`) — once per target.
182
+ - Never narrate lineage or dependencies ("upstream capture lives in KEY-14…") — that's what relations are for.
183
+ - Any project, issue, or doc named in the body is a clickable link.
398
184
 
399
- ### Issue Body Conventions
185
+ ### Body Conventions
400
186
 
401
- - **Do NOT list or link an issue's sub-issues in the parent body** (no "Sub-issues" section, no bulleted child links). Linear renders an issue's children natively — a manual list just clutters the description and goes stale as children are added or removed. A parent body should carry the objective, any single-source-of-truth pointer, and acceptance criteria — nothing that restates the hierarchy.
187
+ - **Do NOT list or link an issue's sub-issues in the parent body** (no "Sub-issues" section, no bulleted child links). Linear renders an issue's children natively — a manual list just clutters the description and goes stale as children are added or removed. A parent body should include the objective, any single-source-of-truth pointer, and acceptance criteria — nothing that restates the hierarchy.
402
188
  - **No timestamped or dated section headers** (e.g. `## Data model — corrected (2025-05-01)`). State the current spec cleanly; issue history already records the "when." Dated "correction" sections accumulate as noise.
403
-
404
- ### Client Feature Request — Frontend
405
-
406
- > **Important:** Do NOT guess which pages/components need updating. Check the client's repo (`app/pages/`, `app/components/`) to identify the correct files and routes. If the repo is not accessible, add a **## To Determine** section listing what needs to be verified before work begins (e.g., "Which page renders the jobs list? Check repo.").
407
-
408
- ```
409
- Title: Feature description
410
- Priority: High (2) or Medium (3)
411
- Labels: feature, frontend
412
- Estimate: S/M/L/XL
413
- Description:
414
- ## Context
415
- [Why does the client need this?]
416
-
417
- ## Requirements
418
- - [ ] Requirement 1
419
- - [ ] Requirement 2
420
-
421
- ## UI Notes
422
- - Page/route: `/path` ← verified from repo, NOT guessed
423
- - Components: [Which Volt components are relevant — VoltCard, VoltDataTable, etc.]
424
- - Follow DESIGN_LANGUAGE.md (zinc palette, no decorative shadows)
425
-
426
- ## To Determine (if repo not checked)
427
- - [ ] Which page/route handles this feature?
428
- - [ ] Which existing components need modification?
429
-
430
- ## Acceptance Criteria
431
- - [ ] What "done" looks like
432
- ```
433
-
434
- ### Client Feature Request — Backend / API
435
-
436
- > **Note:** Backend issues should describe *what* functionality is needed, not *how* to implement it. The Backend lead knows which endpoints to create, how to structure handlers, and what validation to add. Focus the description on the functionality the backend needs to support and any business rules or constraints.
437
-
438
- ```
439
- Title: Feature description
440
- Priority: High (2) or Medium (3)
441
- Labels: feature, backend
442
- Estimate: S/M/L/XL
443
- Description:
444
- ## Context
445
- [Why does the client need this? What problem does it solve for the client?]
446
-
447
- ## Functionality
448
- - [What the backend needs to support — describe the behavior, not the implementation]
449
- - [Business rules, constraints, edge cases]
450
- - [What data needs to be stored, returned, or transformed]
451
- - [Auth considerations if non-standard (e.g., public access, webhook)]
452
-
453
- ## Acceptance Criteria
454
- - [ ] What "done" looks like from a functionality perspective
455
- - [ ] Tests written
456
- ```
189
+ - **The body is the current spec, not a decision log.** When a clarifying answer or any later change alters the issue, rewrite the affected parts of the body so it reads as if it had always said that. Don't append a "Decisions" / "Clarifications" / "Update" section, and don't leave superseded text in place (struck through or otherwise) — anything superseded gets rewritten or removed.
457
190
 
458
191
  ### Fullstack Features — Split Into Separate Issues
459
192
 
@@ -464,88 +197,23 @@ When a feature requires both backend and frontend work, **always create separate
464
197
  This keeps issues focused, enables parallel assignment (the Backend lead on backend, the Frontend/PM lead on frontend), and makes progress tracking clearer. Using Linear dependencies (rather than just mentioning the dependency in the description) makes the blocking relationship visible in the UI, prevents the frontend issue from accidentally being started too early, and keeps the dependency machine-readable.
465
198
 
466
199
  **Steps:**
467
- 1. Create the **backend issue** using the "Client Feature Request — Backend / API" template above (labels: `feature`, `backend`)
468
- 2. Create the **frontend issue** using the "Client Feature Request — Frontend" template above (labels: `feature`, `frontend`)
469
- 3. **Create the Linear dependency:** use `add-dependency` so the backend issue blocks the frontend issue
470
-
471
- ```bash
472
- # After creating both issues, link them:
473
- node linear.mjs add-dependency "$BACKEND_ISSUE_ID" "$FRONTEND_ISSUE_ID"
474
- # Result: backend blocks frontend (frontend is blocked by backend)
475
- ```
200
+ 1. Create the **backend issue** using the **Backend** layout (labels: `Feature`, `Backend`, plus `DB` if it changes the schema)
201
+ 2. Create the **frontend issue** using the **Frontend** layout (labels: `Feature`, `Frontend`)
202
+ 3. **Create the Linear dependency:** update the frontend issue with `mcp__linear__save_issue` `blockedBy: ["<backend issue identifier>"]` (or pass it on create), so the backend issue blocks the frontend issue
476
203
 
477
204
  **Example:** "Add admin button to complete all job tasks"
478
205
  - **Backend issue:** Support marking all tasks for a job as complete in a single operation; admin-only, should be atomic
479
206
  - **Frontend issue:** Admin-only button on job page, confirmation dialog, API call, toast
480
- - **Dependency:** `node linear.mjs add-dependency "$BACKEND_ID" "$FRONTEND_ID"`
207
+ - **Dependency:** frontend issue `blockedBy` the backend issue
481
208
 
482
209
  > **Note:** If the feature is simple enough that the backend is trivial (e.g., a single straightforward CRUD endpoint), it's acceptable to create one combined issue assigned to the person doing both. Use your judgement.
483
210
 
484
- ### Bug Report
485
- ```
486
- Title: Fix: brief description of the bug
487
- Priority: Urgent (1) or High (2)
488
- Labels: bug, frontend|backend
489
- Description:
490
- ## Bug
491
- [What's happening vs. what should happen]
492
-
493
- ## Steps to Reproduce
494
- 1. Step 1
495
- 2. Step 2
496
-
497
- ## Environment
498
- [Browser, OS, user account, etc.]
499
-
500
- ## Likely Location
501
- - [File path if known, e.g., server/api/users/[id].get.ts or app/pages/users.vue]
502
- ```
503
-
504
- ### Backend / Data Modeling Task
505
-
506
- > **Note:** Focus on *what* data needs to be modeled and *why*, not on prescribing specific schema details or endpoint structures. Include business context and constraints so the Backend lead can make the right design decisions.
507
-
508
- ```
509
- Title: Description of the task
510
- Priority: as appropriate
511
- Labels: backend
512
- Estimate: S/M/L/XL
513
- Description:
514
- ## Objective
515
- [What data model or API change is needed and why]
516
-
517
- ## Requirements
518
- - [What data needs to be stored/tracked]
519
- - [Relationships to existing data (e.g., "each job has many tasks")]
520
- - [Business rules and constraints]
521
- - [Any existing data that needs migrating]
522
-
523
- ## Acceptance Criteria
524
- - [ ] What "done" looks like
525
- - [ ] Tests written
526
- ```
527
-
528
- ### Chore / Maintenance
529
- ```
530
- Title: Chore: description
531
- Priority: Medium (3) or Low (4)
532
- Labels: chore, frontend|backend
533
- Estimate: S/M/L
534
- Description:
535
- ## What
536
- [What needs to be done]
537
-
538
- ## Why
539
- [Why it matters — tech debt, performance, DX, etc.]
540
-
541
- ## Files Affected
542
- - [List key files/directories]
543
- ```
544
-
545
211
  ---
546
212
 
547
213
  ## Assignment Guidelines
548
214
 
215
+ Issues are assigned by role: the **Frontend/PM lead** or the **Backend lead**. The CLI's `init` binds each role to a Linear member in `~/.config/linctl/workspace.json` — read it to know who they are.
216
+
549
217
  | Issue Type | Default Assignee |
550
218
  |-----------|-----------------|
551
219
  | Kysely migrations, schema design, complex DB queries | Backend lead |
@@ -561,7 +229,7 @@ Description:
561
229
 
562
230
  ## Post-Organization: Update Initiative in Linear
563
231
 
564
- **After organizing issues for a client (creating, triaging, updating statuses, or completing a sprint review), always update the corresponding initiative's `content` field in Linear.**
232
+ **After organizing issues for a client (creating, triaging, or updating statuses), always update the corresponding initiative's `content` field in Linear.**
565
233
 
566
234
  ### What to Update
567
235
 
@@ -579,26 +247,12 @@ The initiative `content` field stores **client-level context only** — NOT data
579
247
 
580
248
  - After creating a batch of new issues for a client
581
249
  - After triaging/re-prioritizing a client's backlog
582
- - After a sprint review or cycle close
583
250
  - After marking significant issues as Done or Canceled
584
251
  - Any time the initiative's content would be stale after your changes
585
252
 
586
253
  ### How to Get Current Data
587
254
 
588
- Use the Linear CLI to query the initiative and pull fresh issue data:
589
- ```bash
590
- # Get the initiative's current content
591
- node linear.mjs get-initiative-by-name "ClientName"
592
- # List all issues to see current statuses
593
- node linear.mjs list-issues
594
- # Or check cycle-specific progress
595
- node linear.mjs list-cycle-issues
596
- ```
597
-
598
- Then update the initiative's content in Linear (use a file for the markdown body):
599
- ```bash
600
- node linear.mjs update-initiative "$INITIATIVE_ID" --content-file ./initiative-notes.md
601
- ```
255
+ Read the initiative with `mcp__linear__get_initiative` and the client's issues with `mcp__linear__list_issues`, then write the new content with `mcp__linear__save_initiative`. Repo links go on the initiative via the CLI's `add-initiative-link` (see `cli.md`).
602
256
 
603
257
  ---
604
258
 
@@ -612,8 +266,8 @@ An **Initiative** represents **one signed proposal** for a client, not the clien
612
266
 
613
267
  **The current roster is not stored in this repo — fetch it live from Linear.** Initiatives are the source of truth for which engagements exist, their descriptions, and their repo links:
614
268
 
615
- - **List all clients:** `mcp__linear-server__list_initiatives`
616
- - **Read a client's full details (overview, repo structure, domain notes):** `mcp__linear-server__get_initiative` — these live in the initiative's `content` field
269
+ - **List all clients:** `mcp__linear__list_initiatives`
270
+ - **Read a client's full details (overview, repo structure, domain notes):** `mcp__linear__get_initiative` — these live in the initiative's `content` field
617
271
  - **Get a client's repo URL:** read the `links` array on the initiative
618
272
 
619
273
  When you start any task that needs client context, query Linear instead of looking for a hardcoded list. This keeps the skill in sync as clients are added or removed without repo changes.
@@ -641,7 +295,7 @@ attached to the **same initiative**, named with an `R` prefix instead of `M`:
641
295
 
642
296
  `R` numbering is sequential across the whole proposal in the order revisions are
643
297
  taken on, independent of which milestone the revision relates to. Never fold
644
- out-of-scope work into an `M` project — that silently rewrites what was signed.
298
+ out-of-scope work into an `M` project — that changes the signed scope without anyone agreeing to it.
645
299
 
646
300
  #### Never invent a project
647
301
 
@@ -669,31 +323,19 @@ are for), or because the initiative looked empty. If you cannot place the work a
669
323
  the requester is unavailable, leave it unplaced and say so — an invented project is
670
324
  harder to undo than an unplaced issue.
671
325
 
672
- ### Milestone (= Phase / Epic)
326
+ ### Milestone (= One Proposed Deliverable)
673
327
 
674
- A **Milestone** is a phase or epic within a project — a meaningful chunk of progress that can be demoed or shipped incrementally.
328
+ A **Milestone** is **one deliverable the proposal listed under that project's milestone** — the same alignment as projects, one level down. An `M` project's milestones *are* its signed deliverables, so they're fixed by the proposal just like the project row.
675
329
 
676
- A milestone is the level where grouping decisions actually belong — **unlike
677
- projects, milestones may be created freely as part of intake.** If a request needs
678
- a new home inside its `M` project, that home is a milestone, never a new project.
330
+ - **In an `M` project, never create a milestone during intake.** Place the work in the deliverable it falls under. If none fits, that's a signal the work may be out of scope — say so and ask whether it's a revision.
331
+ - **In a confirmed `R` project**, you may create milestones for the revision's deliverables as part of intake.
679
332
 
680
333
  **Examples within `[KEY] M2 — Billing`:**
681
334
  - `Core Billing` — create, edit, send invoices (done)
682
335
  - `Quotes` — quote workflow, create/edit/convert to invoice
683
336
  - `Payments` — payment methods, receipts, balance due display
684
337
 
685
- **Examples within `[KEY] M1 — Scheduling`:**
686
- - `Providers Module` — list, create, edit, deactivate providers
687
- - `Booking Requests` — request creation, accept/reject workflow
688
- - `Scheduling & Calendar` — availability, scheduling UI
689
-
690
- **When to create a milestone:**
691
- - A logical group of 5–15 related issues
692
- - Has a clear "phase complete" definition
693
- - Can be reviewed/demoed as a unit
694
- - Work within it is mostly sequential or tightly coupled
695
-
696
- **Naming convention:** Short, descriptive noun phrase (no client key prefix needed since milestones live inside a project)
338
+ **Naming convention:** The deliverable's name from the proposal (no client key prefix needed since milestones live inside a project).
697
339
 
698
340
  ### Issue (= Task)
699
341
 
@@ -704,7 +346,7 @@ Individual work items live at the bottom of the hierarchy. Every issue belongs t
704
346
  ```
705
347
  Initiative: <Client> — Phase 1 ← one signed proposal
706
348
  ├── Project: [KEY] M1 — Scheduling ← proposal milestone 1
707
- │ ├── Milestone: Providers Module
349
+ │ ├── Milestone: Providers Module ← proposal deliverable
708
350
  │ │ ├── KEY-101: Create providers list page
709
351
  │ │ ├── KEY-102: Add provider create/edit form
710
352
  │ │ └── KEY-103: Provider deactivation support
@@ -718,390 +360,22 @@ Initiative: <Client> — Phase 1 ← one signed proposal
718
360
  ```
719
361
 
720
362
  The project row is fixed by the proposal (`M1`, `M2`) plus whatever revisions have
721
- been agreed (`R1`). New requests land as **issues in a milestone** inside an
722
- existing project — the project row only grows when a revision is confirmed.
363
+ been agreed (`R1`). New requests land as **issues in an existing deliverable milestone** inside an
364
+ existing project — projects and milestones only grow when a revision is confirmed.
723
365
 
724
366
  ### Guidelines for the Team
725
367
 
726
- 1. **Every issue must be placed into a cycle with Todo status.** **Do NOT default to the current/active cycle.** Follow this procedure: (a) Run `cycle-capacity` to see each cycle's capacity % (velocity-based, from last 3 completed cycles). (b) Starting from the earliest (current) cycle, find the first cycle that is **strictly under 100%** capacity. (c) If the current cycle is at or above 100%, **skip it** and use the next cycle with room. Assign the issue there via `--cycle`. **Always set `--state todo`** — issues in Backlog don't work with cycles. **Exception:** High priority or above (priority ≤ 2: Urgent, High) always go into the current active cycle regardless of capacity.
368
+ 1. **Every new issue starts in Backlog, with no cycle.** Ask the user whether it's ready for Todo, and move it only on a yes (see "Create in Backlog, then ask about Todo").
727
369
  2. **Every issue must belong to a project and a milestone.** Never create orphan issues and never leave an issue outside a milestone.
728
370
  3. **Place the issue in an existing project — never invent one.** The initiative's `M` projects are the signed proposal's milestones; find the one the work falls under. A new project is correct *only* for work the requester confirmed is out of scope, and then only as the next `[KEY] R<n> — <Name>` revision project (see "Never invent a project"). Don't park work in a generic team backlog either — if you truly cannot place it, say so rather than manufacturing a home for it.
729
- 4. **If the correct milestone does not exist, create it before creating the issue.** Milestone creation is part of issue intake, not optional cleanup. **Never add an issue to a completed milestone** — only open milestones may receive new issues. If no open milestone matches the issue, create a new one; do not reuse a completed one.
371
+ 4. **Place the issue in the deliverable milestone it falls under.** Never create a milestone in an `M` project; only a confirmed `R` project may get new milestones during intake. If the matching milestone is completed, ask the requester whether the work is in scope or a revision (see "Work under a completed deliverable → ask").
730
372
  5. **Use milestones for sequencing.** Milestones can have target dates, making them useful for communicating delivery phases to clients.
731
- 6. **Track progress in Linear.** After creating/updating projects or milestones, update the initiative's content in Linear to reflect the current structure (see "Post-Organization: Update Initiative in Linear" below).
732
- 7. **When creating issues with the CLI**, use the `--project`, `--milestone`, and `--cycle` flags to place issues correctly in the hierarchy and cycle.
733
-
734
- ### CLI Examples
735
-
736
- ```bash
737
- # List projects for the team
738
- node linear.mjs list-projects
739
-
740
- # List milestones within a project
741
- node linear.mjs list-milestones "$PROJECT_ID"
742
-
743
- # If the milestone is missing, create it inside the EXISTING M project (never a new project)
744
- MILESTONE_ID="$(node linear.mjs create-milestone "$PROJECT_ID" "Phase 1" | node -e "process.stdin.once('data',d=>console.log(JSON.parse(d).data.projectMilestoneCreate.projectMilestone.id))")"
745
-
746
- # Creating a project is only for a CONFIRMED out-of-scope revision — next R<n>, same initiative
747
- node linear.mjs create-project --name "[KEY] R1 — Revision Name" --initiative "$INITIATIVE_ID" --description "Short description"
748
-
749
- # Create an issue within a project and milestone (with cycle)
750
- node linear.mjs create-issue \
751
- --title 'Add provider create form' \
752
- --description '...' \
753
- --priority high \
754
- --state todo \
755
- --assignee frontend \
756
- --labels feature,frontend \
757
- --project 'project-uuid-here' \
758
- --milestone 'milestone-uuid-here' \
759
- --cycle current
760
- ```
761
-
762
- ---
763
-
764
- ## Project Refresh — Milestone Restructuring
765
-
766
- When a project's milestone structure becomes outdated (or was never set up), use the **project refresh** workflow to reorganize milestones without losing or changing any issues.
767
-
768
- ### When to Refresh
769
-
770
- - Project was created without milestones and has grown to 10+ issues
771
- - Milestones were set up early but no longer match the actual work groupings
772
- - A project pivot changed priorities and the old phases don't apply
773
- - Too many issues are in "(No milestone)" and need proper grouping
774
- - Milestones are too broad (30+ issues each) or too granular (1-2 issues each)
775
-
776
- ### Refresh Workflow
777
-
778
- **Step 1: Audit the current state**
779
-
780
- ```bash
781
- # Get the project ID
782
- node linear.mjs list-projects
783
-
784
- # See current milestones
785
- node linear.mjs list-milestones "$PROJECT_ID"
786
-
787
- # See all issues grouped by milestone (includes unmilestoned)
788
- node linear.mjs list-project-issues "$PROJECT_ID" --limit 200
789
-
790
- # Get raw JSON for scripting (includes issue UUIDs and milestone UUIDs)
791
- node linear.mjs list-project-issues "$PROJECT_ID" --limit 200 --json
792
- ```
793
-
794
- Review:
795
- - How many issues per milestone? (ideal: 5–15)
796
- - Are milestones thematically coherent?
797
- - Are there many unmilestoned issues?
798
- - Do completed milestones still have open issues?
799
- - Are milestone names clear and descriptive?
800
-
801
- **Step 2: Propose new milestone structure**
802
-
803
- Present the proposed changes to the user before making any modifications:
804
- - Which milestones to **keep** (unchanged)
805
- - Which milestones to **rename** (same issues, better name) — **never rename milestones with target dates**
806
- - Which milestones to **merge** (combine two sparse milestones)
807
- - Which milestones to **split** (break an overloaded milestone)
808
- - Which milestones to **create** (for unmilestoned issues or new groupings)
809
- - Which milestones to **delete** (empty after reshuffling) — **never delete milestones with target dates**
810
- - For each issue, which milestone it should end up in
811
-
812
- **Present this as a before/after table so the user can approve.**
813
-
814
- **Step 3: Execute the changes (after user approval)**
815
-
816
- Order of operations matters — follow this sequence:
817
-
818
- 1. **Create new milestones** (need their IDs before moving issues)
819
- ```bash
820
- node linear.mjs create-milestone "$PROJECT_ID" "New Milestone Name" --target-date "2025-06-01"
821
- ```
822
-
823
- 2. **Rename existing milestones** (safe, doesn't affect issues)
824
- ```bash
825
- node linear.mjs update-milestone "$MILESTONE_ID" --name "Better Name"
826
- ```
827
-
828
- 3. **Move issues to their new milestones**
829
- ```bash
830
- # One at a time
831
- node linear.mjs set-issue-milestone "$ISSUE_ID" "$NEW_MILESTONE_ID"
832
-
833
- # Or batch move
834
- node linear.mjs batch-move-to-milestone "$NEW_MILESTONE_ID" "$ISSUE_1" "$ISSUE_2" "$ISSUE_3"
835
- ```
836
-
837
- 4. **Delete empty milestones** (only after all issues are moved out)
838
- ```bash
839
- node linear.mjs delete-milestone "$EMPTY_MILESTONE_ID"
840
- ```
841
-
842
- 5. **Verify the result**
843
- ```bash
844
- node linear.mjs list-project-issues "$PROJECT_ID" --limit 200
845
- ```
846
-
847
- **Step 4: Update the initiative in Linear**
848
-
849
- After restructuring, update the initiative's `content` field in Linear to reflect the new milestone structure.
850
-
851
- ### Safety Rules
852
-
853
- - **No issue loss.** Every issue that existed before the refresh must exist after. Verify issue count before and after.
854
- - **No status changes.** Don't change any issue's status, priority, assignee, labels, or estimate during a refresh. Only the milestone assignment changes.
855
- - **No issue deletion.** Never delete or cancel issues as part of a refresh.
856
- - **Delete milestones last.** Only delete a milestone after confirming it has zero issues.
857
- - **Never delete or rename a dated milestone.** Milestones with target dates represent intentional commitments — they must stay intact (name and date unchanged). You may move issues out of them, but the milestone itself must not be deleted or renamed.
858
- - **User approval required.** Always present the proposed restructuring plan and get explicit approval before executing any changes.
859
-
860
- ### CLI Reference (Milestone Operations)
861
-
862
- ```bash
863
- # Create a milestone
864
- node linear.mjs create-milestone "$PROJECT_ID" "Milestone Name" [--target-date YYYY-MM-DD]
865
-
866
- # Rename / update a milestone
867
- node linear.mjs update-milestone "$MILESTONE_ID" --name "New Name"
868
- node linear.mjs update-milestone "$MILESTONE_ID" --target-date "2025-07-01"
869
- node linear.mjs update-milestone "$MILESTONE_ID" --sort-order 5
870
-
871
- # Delete a milestone (must be empty!)
872
- node linear.mjs delete-milestone "$MILESTONE_ID"
873
-
874
- # Move a single issue to a milestone
875
- node linear.mjs set-issue-milestone "$ISSUE_ID" "$MILESTONE_ID"
876
-
877
- # Remove issue from its milestone (set to unmilestoned)
878
- node linear.mjs set-issue-milestone "$ISSUE_ID" none
879
-
880
- # Batch move issues to a milestone
881
- node linear.mjs batch-move-to-milestone "$MILESTONE_ID" "$ISSUE_1" "$ISSUE_2" "$ISSUE_3"
882
-
883
- # Get raw JSON with issue/milestone UUIDs (for scripting)
884
- node linear.mjs list-project-issues "$PROJECT_ID" --limit 200 --json
885
- ```
373
+ 6. **Track progress in Linear.** After creating/updating projects or milestones, update the initiative's content in Linear to reflect the current structure (see "Post-Organization: Update Initiative in Linear").
886
374
 
887
375
  ---
888
376
 
889
- ## Cycle Rebalance — Redistributing Issues Across Cycles
890
-
891
- The **cycle rebalance** workflow redistributes issues so that cycles are filled **front-to-back**: the current cycle should be at **105% capacity**, overflow spills into the next cycle (also up to 105%), and so on. This applies in **both directions** — issues move later when a cycle is overloaded, and issues pull forward from later cycles when the current cycle has room.
892
-
893
- **Capacity** is calculated using `cycle-capacity`: total estimate points in the cycle / average completed estimate points from the last 3 completed cycles (velocity).
894
-
895
- ### When to Rebalance
896
-
897
- - After a cycle ends with incomplete issues that rolled into the next cycle
898
- - When a cycle is over or under capacity
899
- - When the user says "rebalance cycles", "redistribute issues", or similar
900
- - During sprint planning when upcoming cycles look uneven
901
-
902
- ### Rebalance Workflow
903
-
904
- **Step 1: Audit current cycle state**
905
-
906
- ```bash
907
- # Check velocity-based capacity for all cycles
908
- node linear.mjs cycle-capacity
909
-
910
- # Overview: all active/upcoming cycles with issues grouped by project
911
- node linear.mjs rebalance
912
-
913
- # Raw data for analysis
914
- node linear.mjs rebalance --json
915
- ```
916
-
917
- Collect this data and analyze:
918
- - **Velocity:** From `cycle-capacity` output (avg completed pts from last 3 cycles)
919
- - **Capacity per cycle:** Each cycle's estimate points as a % of velocity
920
- - **Target per cycle:** 105% of velocity (e.g., if velocity = 91, target = ~96 pts)
921
- - **Which cycles are under 105%:** These need issues pulled forward from later cycles
922
- - **Which cycles are over 105%:** These need issues pushed to later cycles
923
-
924
- **Step 2: Analyze and plan the redistribution**
925
-
926
- The goal is to **fill cycles front-to-back to 105%**:
927
-
928
- 1. Start with the **current (active) cycle**. Calculate its capacity.
929
- 2. If **under 105%** → pull movable issues forward from the next cycle(s) until at 105% (or no more movable issues exist).
930
- 3. If **over 105%** → push lowest-priority movable issues to the next cycle until at 105%.
931
- 4. Move to the **next cycle** and repeat.
932
- 5. Continue until all cycles are processed. The last cycle absorbs whatever remains.
933
-
934
- **When pulling issues forward**, prefer (in order):
935
- 1. **Urgent/High priority** issues first — get important work done sooner
936
- 2. Issues whose **dependencies are already satisfied** (blocker is Done or in an earlier/same cycle)
937
- 3. Issues from **underrepresented clients** in the target cycle (balance client mix)
938
- 4. Issues in the **same milestone** as other issues already in the target cycle
939
-
940
- **When pushing issues later**, prefer (in order):
941
- 1. **NEVER move High (2) or Urgent (1) priority issues to a later cycle** — they are time-sensitive and must stay in their current cycle or move earlier
942
- 2. **NEVER move issues with a due date** — due dates represent commitments; these issues are pinned to their current cycle (or can move earlier, never later)
943
- 3. **Low (4)** priority issues first — least impactful to delay
944
- 4. **Medium (3)** priority next
945
- 5. Issues with **no downstream dependents** (nothing blocked by them)
946
- 6. Issues from **overrepresented clients** in the current cycle
947
-
948
- Apply these heuristics throughout:
949
-
950
- #### Heuristic 1: Respect status — never move active work
951
- - **Never move** issues that are `In Progress` or `In Review` — they stay in their current cycle
952
- - **Todo** issues are movable (both forward and backward)
953
- - **Backlog** issues in a cycle are movable (but should be set to Todo after moving)
954
-
955
- #### Heuristic 2: Respect dependencies
956
- - **Hard rule: a blocking issue must NEVER be in a later cycle than the issue it blocks.** If issue A blocks issue B, A must be in the same cycle as B or an earlier one. This is inviolable — never move a blocker to a later cycle than its dependent.
957
- - Check dependencies with `node linear.mjs list-dependencies "$ISSUE_ID"` for any issue you plan to move
958
- - When pulling an issue forward, also pull forward any of its blockers that are in a later cycle (or leave both)
959
- - When pushing an issue later, ensure none of the issues it blocks are in the current or an earlier cycle — if they are, you cannot push this issue. Either push the dependent issues too, or leave the blocker in place.
960
-
961
- #### Heuristic 3: Balance client work per cycle
962
- - Each cycle should have a **roughly proportional mix** of client work — avoid "all Globex" or "all Northwind" cycles
963
- - When choosing which issues to pull forward or push later, use client balance as a tiebreaker
964
- - This ensures progress across all clients every sprint
965
-
966
- #### Heuristic 4: Keep milestones together
967
- - Issues in the same milestone should stay in the same cycle when possible — they're often sequentially dependent even if not formally linked
968
- - If a milestone spans cycles, keep the split clean: don't scatter milestone issues across 3+ cycles
969
- - When pulling forward, prefer pulling entire milestone groups together
970
-
971
- #### Heuristic 5: Balance assignee load
972
- - Each cycle should have a reasonable split between the Frontend/PM lead and the Backend lead
973
- - Don't create a cycle where one person has 80% of the work and the other has 20%
974
- - Consider that backend issues (Backend lead) often block frontend issues (Frontend/PM lead) — schedule accordingly
975
-
976
- #### Heuristic 6: Estimate-aware balancing
977
- - Use estimate points (not just issue count) for capacity calculations via `cycle-capacity`
978
- - A cycle with 3 XL issues is heavier than one with 8 S issues
979
- - Unestimated issues don't count toward capacity — note this when presenting the plan
980
-
981
- **Step 3: Present the rebalance plan**
982
-
983
- Present a clear before/after comparison:
984
-
985
- ```
986
- VELOCITY: 91 pts (avg from C1=96, C2=80, C3=96)
987
- TARGET PER CYCLE: ~96 pts (105%)
988
-
989
- BEFORE:
990
- Cycle 4 (active): 67 pts — 74% capacity
991
- Cycle 5: 62 pts — 68% capacity
992
- Cycle 6: 65 pts — 72% capacity
993
-
994
- AFTER:
995
- Cycle 4: 96 pts — 105% capacity (pulled 29 pts forward from C5)
996
- Cycle 5: 96 pts — 105% capacity (lost 29 to C4, pulled 63 from C6)
997
- Cycle 6: 2 pts — 2% capacity (pushed 63 to C5)
998
-
999
- MOVES:
1000
- ← ACME-342 "Build customer profiles list page" (est 3, Northwind) → Cycle 5 → Cycle 4
1001
- ← ACME-441 "Show dependency indicators" (est 3, Globex) → Cycle 5 → Cycle 4
1002
- → ACME-278 "Display audit log" (est 3, Globex) → Cycle 6 → Cycle 5
1003
- ...
1004
- ```
1005
-
1006
- Include:
1007
- - Direction arrow: `←` for pulling forward, `→` for pushing later
1008
- - Which issues move, with identifier, title, priority, estimate, and project
1009
- - Why each issue was chosen to move
1010
- - Client distribution per cycle (before and after)
1011
- - Assignee balance per cycle (before and after)
1012
- - Any issues you considered moving but kept in place, and why
1013
-
1014
- **Get explicit user approval before executing.**
1015
-
1016
- **Step 4: Execute the moves (after approval)**
1017
-
1018
- > **Important: Rate limiting.** The Linear API silently drops rapid-fire mutations. The `batch-move-to-cycle` command already inserts a 0.5s delay between calls and validates each response (reporting `success`/`fail` counts). For large rebalances (50+ moves), still process in groups of ~9 and verify between groups, since responses may report `success: true` while the mutation is silently discarded.
1019
-
1020
- ```bash
1021
- # Use the built-in batch command (includes delays and error reporting):
1022
- node linear.mjs batch-move-to-cycle "$TARGET_CYCLE_ID" "$ISSUE_1" "$ISSUE_2" "$ISSUE_3"
1023
-
1024
- # "current" resolves to the active cycle:
1025
- node linear.mjs batch-move-to-cycle current "$ISSUE_1" "$ISSUE_2"
1026
-
1027
- # For one-off moves:
1028
- node linear.mjs move-issue-to-cycle "$ISSUE_ID" "$CYCLE_ID"
1029
- ```
1030
-
1031
- **Step 5: Verify the result**
1032
-
1033
- ```bash
1034
- # Confirm the new capacity distribution
1035
- node linear.mjs cycle-capacity
1036
-
1037
- # Confirm issue-level details
1038
- node linear.mjs rebalance
1039
- ```
1040
-
1041
- Review the output and confirm:
1042
- - Current cycle is at or near 105% (or as close as possible given movable issues)
1043
- - Each subsequent cycle is filled to 105% before spilling to the next
1044
- - No In Progress/In Review issues were moved
1045
- - Dependencies are still satisfied (blockers before blocked)
1046
- - Client mix is balanced across cycles
1047
-
1048
- **Step 6: Update initiative in Linear if needed**
1049
-
1050
- After rebalancing, update the initiative's content in Linear if cycle assignments or progress notes are tracked there.
1051
-
1052
- ### Safety Rules
1053
-
1054
- - **No status changes.** Only the cycle assignment changes — never touch status, priority, assignee, labels, estimate, milestone, or project.
1055
- - **No issue deletion.** Never delete or cancel issues during a rebalance.
1056
- - **Don't move active work.** Issues in `In Progress` or `In Review` are untouchable.
1057
- - **Never push High or Urgent issues later.** High (priority 2) and Urgent (priority 1) issues must never be moved to a farther-out cycle — they are time-sensitive by definition. They can only stay put or be pulled forward.
1058
- - **Never push due-dated issues later.** Issues with a due date are pinned to their current cycle (or earlier). Due dates represent commitments — never move these to a farther-out cycle.
1059
- - **Respect dependencies.** A blocking issue must NEVER end up in a later cycle than the issue it blocks. Before moving any issue, check its dependencies — if it blocks something in cycle N, it cannot move to cycle N+1 or later.
1060
- - **User approval required.** Always present the full rebalance plan and get explicit approval before executing any moves.
1061
- - **105% target is a soft cap.** It's okay if a cycle lands at 103% or 107% because the next movable issue would overshoot. The goal is "each cycle as close to 105% as possible, filled front-to-back," not mathematical perfection.
1062
-
1063
- ### CLI Reference (Cycle Rebalance Operations)
1064
-
1065
- ```bash
1066
- # Full overview of cycles with issues grouped by project
1067
- node linear.mjs rebalance
1068
-
1069
- # Raw JSON for all active/upcoming cycles with incomplete issues
1070
- node linear.mjs rebalance --json
1071
- # (or: node linear.mjs list-cycle-issues-all)
1072
-
1073
- # Raw JSON for a specific cycle's incomplete issues
1074
- node linear.mjs list-cycle-issues-by-id "$CYCLE_ID"
1075
-
1076
- # Move a single issue to a different cycle
1077
- node linear.mjs move-issue-to-cycle "$ISSUE_ID" "$CYCLE_ID"
1078
-
1079
- # Batch move multiple issues to a cycle (includes 0.5s delay between calls)
1080
- # Reports success/fail counts. Keep batches ≤9 for reliability.
1081
- node linear.mjs batch-move-to-cycle "$CYCLE_ID" "$ISSUE_1" "$ISSUE_2" "$ISSUE_3"
1082
-
1083
- # Check dependencies before moving
1084
- node linear.mjs list-dependencies "$ISSUE_ID"
1085
-
1086
- # Verify after rebalancing
1087
- node linear.mjs rebalance
1088
- ```
1089
-
1090
- > **Rate limit note:** Linear's API can silently discard rapid mutations. The batch function includes a 0.5s delay between calls and validates each response. For large rebalances (50+ moves), process in groups of ~9 and verify between groups.
1091
-
1092
- ---
1093
-
1094
- ## Tips for a 2-Person Team
1095
-
1096
- 1. **Keep issues small.** If it's XL, break it down. Small issues keep momentum and make reviews easier.
1097
- 2. **Daily async check-in.** A quick message about what you're working on and if you're blocked.
1098
- 3. **Use "In Review" status.** It signals to the other person that something needs their eyes.
1099
- 4. **Don't overcommit cycles.** Leave ~20% buffer for bugs, client requests, and interruptions.
1100
- 5. **Projects identify the client.** No need for client prefixes in issue titles or client labels — the project name (e.g., `[GBX] Portal`) already provides that context.
1101
- 6. **Triage first.** New client requests go to Backlog, not straight into the sprint — unless truly urgent.
1102
-
1103
377
  ## Contributing Back
1104
378
 
1105
- This skill grows by capturing what it missed. If you just worked through something in this domain that this skill did not cover — an error you had to figure out, a behavior that contradicts what is documented above, a workflow knot — ask the user: **"Want me to contribute this back to the linear skill?"**
379
+ This skill grows by adding what it doesn't cover yet. If you just worked through something in this domain that this skill did not cover — an error you had to figure out, behavior that doesn't match what's documented above, a workflow knot — ask the user: **"Want me to contribute this back to the linear skill?"**
1106
380
 
1107
381
  If yes, run `/contribute-skill`. If that command is not available, do the equivalent inline: distill the generic lesson (placeholders only — no project names, IDs, domains, or secrets), then branch or fork [gallop-systems/agent-skills](https://github.com/gallop-systems/agent-skills) and open a PR editing this skill.