@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.
- package/package.json +1 -1
- package/plugins/linear/.claude-plugin/plugin.json +1 -1
- package/plugins/linear/skills/linear/SKILL.md +136 -862
- package/plugins/linear/skills/linear/cli.md +249 -0
- package/plugins/linear/skills/linear/examples/backend-data-model.md +31 -0
- package/plugins/linear/skills/linear/examples/backend-feature.md +30 -0
- package/plugins/linear/skills/linear/examples/bug.md +30 -0
- package/plugins/linear/skills/linear/examples/discovery.md +34 -0
- package/plugins/linear/skills/linear/examples/frontend-feature.md +36 -0
- package/plugins/linear/skills/linear/examples/right-and-wrong.md +138 -0
- package/plugins/linear/skills/linear/examples/small-improvement.md +24 -0
- package/plugins/linear/skills/linear/tech-stack.md +1 -1
|
@@ -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 —
|
|
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
|
|
6
|
+
# Linear — Gallop Team Workflow
|
|
7
7
|
|
|
8
|
-
##
|
|
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
|
-
|
|
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
|
-
|
|
23
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
###
|
|
23
|
+
### MCP setup check
|
|
35
24
|
|
|
36
|
-
This skill routes most operations through `
|
|
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 `
|
|
39
|
-
- **Installed but not authorized:** if a `
|
|
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
|
-
| **
|
|
95
|
-
| **
|
|
96
|
-
| **
|
|
97
|
-
| **In
|
|
98
|
-
| **
|
|
99
|
-
| **
|
|
100
|
-
|
|
101
|
-
|
|
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** |
|
|
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
|
-
##
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
###
|
|
154
|
-
-
|
|
155
|
-
-
|
|
156
|
-
-
|
|
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
|
-
##
|
|
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
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
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
|
-
|
|
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
|
-
|
|
255
|
-
- `0` = No priority
|
|
256
|
-
- `1` = Urgent
|
|
257
|
-
- `2` = High
|
|
258
|
-
- `3` = Medium
|
|
259
|
-
- `4` = Low
|
|
101
|
+
---
|
|
260
102
|
|
|
261
|
-
|
|
262
|
-
```bash
|
|
263
|
-
# List all issues (pretty table by default)
|
|
264
|
-
node linear.mjs list-issues
|
|
103
|
+
## Creating Issues
|
|
265
104
|
|
|
266
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
365
|
-
|
|
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
|
-
|
|
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
|
-
|
|
372
|
-
|
|
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
|
-
|
|
375
|
-
node linear.mjs list-initiatives --json
|
|
376
|
-
```
|
|
158
|
+
### Titles
|
|
377
159
|
|
|
378
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
###
|
|
179
|
+
### Links
|
|
394
180
|
|
|
395
|
-
-
|
|
396
|
-
-
|
|
397
|
-
-
|
|
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
|
-
###
|
|
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
|
|
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
|
|
468
|
-
2. Create the **frontend issue** using the
|
|
469
|
-
3. **Create the Linear dependency:**
|
|
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:** `
|
|
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
|
|
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
|
-
|
|
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:** `
|
|
616
|
-
- **Read a client's full details (overview, repo structure, domain notes):** `
|
|
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
|
|
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 (=
|
|
326
|
+
### Milestone (= One Proposed Deliverable)
|
|
673
327
|
|
|
674
|
-
A **Milestone** is
|
|
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
|
-
|
|
677
|
-
|
|
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
|
-
**
|
|
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
|
|
722
|
-
existing project —
|
|
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
|
|
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. **
|
|
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"
|
|
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
|
|
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.
|