team-toon-tack 3.9.0 → 3.9.3

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.
@@ -13,7 +13,7 @@
13
13
  "name": "team-toon-tack",
14
14
  "source": "./",
15
15
  "description": "Linear/Trello task sync & management CLI with commands and skills",
16
- "version": "2.8.5"
16
+ "version": "3.9.1"
17
17
  }
18
18
  ]
19
19
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "team-toon-tack",
3
3
  "description": "Linear/Trello task sync & management CLI for Claude Code - saves tokens vs MCP",
4
- "version": "2.8.5",
4
+ "version": "3.9.1",
5
5
  "author": {
6
6
  "name": "wayne930242",
7
7
  "email": "wayne930242@gmail.com"
@@ -0,0 +1,20 @@
1
+ {
2
+ "name": "team-toon-tack",
3
+ "version": "3.9.1",
4
+ "description": "透過 ttt CLI 同步與管理 Linear、Trello 任務。",
5
+ "author": {
6
+ "name": "wayne930242"
7
+ },
8
+ "repository": "https://github.com/wayne930242/team-toon-tack",
9
+ "license": "MIT",
10
+ "skills": "./skills/",
11
+ "interface": {
12
+ "displayName": "team-toon-tack",
13
+ "shortDescription": "同步與管理 Linear、Trello 任務",
14
+ "longDescription": "透過 ttt CLI 同步任務、查詢狀態、記錄估時,並依使用者要求更新 Linear 與 Trello。",
15
+ "developerName": "wayne930242",
16
+ "category": "Productivity",
17
+ "capabilities": ["Interactive", "Write"],
18
+ "defaultPrompt": ["使用 ttt 同步並列出我的任務。"]
19
+ }
20
+ }
package/README.md CHANGED
@@ -67,9 +67,32 @@ During init, you'll be prompted to select your task source (Linear or Trello) an
67
67
 
68
68
  ```
69
69
  /plugin marketplace add wayne930242/team-toon-tack
70
- /plugin install team-toon-tack@wayne930242
70
+ /plugin install team-toon-tack@ttt-marketplace
71
71
  ```
72
72
 
73
+ ### Codex plugin 安裝(選擇性)
74
+
75
+ 先依上方步驟安裝 `ttt` CLI 並執行 `ttt init`。Plugin 提供任務管理技能,透過 shell 呼叫 CLI。
76
+
77
+ 從 GitHub 安裝:
78
+
79
+ ```bash
80
+ codex plugin marketplace add wayne930242/team-toon-tack
81
+ codex plugin add team-toon-tack@ttt-marketplace
82
+ ```
83
+
84
+ 從本地 checkout 安裝,在此 repository 根目錄執行:
85
+
86
+ ```bash
87
+ codex plugin marketplace add "$PWD"
88
+ codex plugin add team-toon-tack@ttt-marketplace
89
+ ```
90
+
91
+ 若已註冊同名的 GitHub marketplace,先執行 `codex plugin marketplace remove ttt-marketplace`,再加入本地路徑。
92
+ 修改已安裝的同版本內容後,先執行 `codex plugin remove team-toon-tack@ttt-marketplace`,再執行上述 `codex plugin add` 重新安裝。
93
+
94
+ 安裝完成後開啟新的 Codex 對話,使用 `$managing-linear-tasks`,或直接說「使用 ttt 同步並列出我的任務」。Codex 會使用 `ttt sync`、`ttt show` 等 CLI 指令。
95
+
73
96
  ### 3. Daily Workflow
74
97
 
75
98
  In Claude Code (with plugin installed):
@@ -237,7 +260,7 @@ Install the plugin for Claude Code integration:
237
260
 
238
261
  ```
239
262
  /plugin marketplace add wayne930242/team-toon-tack
240
- /plugin install team-toon-tack@wayne930242
263
+ /plugin install team-toon-tack@ttt-marketplace
241
264
  ```
242
265
 
243
266
  ### Available Commands
@@ -253,7 +276,7 @@ Install the plugin for Claude Code integration:
253
276
 
254
277
  ### Auto-Activated Skill
255
278
 
256
- The plugin includes a `linear-task-manager` skill that automatically activates when working with tasks, providing workflow guidance and best practices.
279
+ The plugin includes a `managing-linear-tasks` skill that automatically activates when working with tasks, providing workflow guidance and best practices.
257
280
 
258
281
  ## License
259
282
 
package/README.zh-TW.md CHANGED
@@ -67,9 +67,32 @@ ttt init
67
67
 
68
68
  ```
69
69
  /plugin marketplace add wayne930242/team-toon-tack
70
- /plugin install team-toon-tack@wayne930242
70
+ /plugin install team-toon-tack@ttt-marketplace
71
71
  ```
72
72
 
73
+ ### Codex plugin 安裝(選擇性)
74
+
75
+ 先依上方步驟安裝 `ttt` CLI 並執行 `ttt init`。Plugin 提供任務管理技能,透過 shell 呼叫 CLI。
76
+
77
+ 從 GitHub 安裝:
78
+
79
+ ```bash
80
+ codex plugin marketplace add wayne930242/team-toon-tack
81
+ codex plugin add team-toon-tack@ttt-marketplace
82
+ ```
83
+
84
+ 從本地 checkout 安裝,在此 repository 根目錄執行:
85
+
86
+ ```bash
87
+ codex plugin marketplace add "$PWD"
88
+ codex plugin add team-toon-tack@ttt-marketplace
89
+ ```
90
+
91
+ 若已註冊同名的 GitHub marketplace,先執行 `codex plugin marketplace remove ttt-marketplace`,再加入本地路徑。
92
+ 修改已安裝的同版本內容後,先執行 `codex plugin remove team-toon-tack@ttt-marketplace`,再執行上述 `codex plugin add` 重新安裝。
93
+
94
+ 安裝完成後開啟新的 Codex 對話,使用 `$managing-linear-tasks`,或直接說「使用 ttt 同步並列出我的任務」。Codex 會使用 `ttt sync`、`ttt show` 等 CLI 指令。
95
+
73
96
  ### 3. 每日工作流
74
97
 
75
98
  在 Claude Code 中(安裝 plugin 後):
@@ -237,7 +260,7 @@ your-project/
237
260
 
238
261
  ```
239
262
  /plugin marketplace add wayne930242/team-toon-tack
240
- /plugin install team-toon-tack@wayne930242
263
+ /plugin install team-toon-tack@ttt-marketplace
241
264
  ```
242
265
 
243
266
  ### 可用指令
@@ -253,7 +276,7 @@ your-project/
253
276
 
254
277
  ### 自動啟用技能
255
278
 
256
- Plugin 包含 `linear-task-manager` 技能,在處理任務時會自動啟用,提供工作流程指導和最佳實踐。
279
+ Plugin 包含 `managing-linear-tasks` 技能,在處理任務時會自動啟用,提供工作流程指導和最佳實踐。
257
280
 
258
281
  ## 授權
259
282
 
@@ -5,7 +5,6 @@ arguments:
5
5
  - name: issue-id
6
6
  description: "Issue ID (e.g., MP-624) or 'next' for auto-select. Defaults to 'next'."
7
7
  required: false
8
- default: next
9
8
  - name: dry-run
10
9
  description: Preview selection without changing status
11
10
  required: false
@@ -48,67 +47,21 @@ Options:
48
47
  --dry-run Pick task without changing status (preview only)
49
48
  ```
50
49
 
51
- ## WorkflowPlan Test → Code → Review
50
+ ## After Selection Delegate the Implementation
52
51
 
53
- Follow this loop for every task.
54
- Skipping phases is not "pragmatic", it is debt.
52
+ This command picks the task. The implementation workflow belongs to the user.
55
53
 
56
- ### 1. Branch
54
+ **Use the user's own workflow whenever one exists** — routing or laws in their root `CLAUDE.md`, the project `CLAUDE.md`, or a `work-on` / `start-work` skill. Follow it as written and add nothing.
57
55
 
58
- Check current branch and repo convention first (e.g. recent `git log --oneline -10`, existing branch naming pattern).
59
- If unclear whether to branch or what name to use, ask the user instead of assuming.
56
+ **Only when none exists**, run this minimal loop:
60
57
 
61
- ```bash
62
- git checkout -b <branch-name-matching-user-convention>
63
- ```
64
-
65
- ### 2. Plan
66
-
67
- Scope decides depth.
68
-
69
- - Unclear requirements or 3+ files touched → if your environment has a brainstorming/planning skill, use it; otherwise clarify scope with the user and write a short plan before coding.
70
- - Clear and small (≤2 files, obvious change) → state a 2–3 bullet plan inline before coding.
71
-
72
- Never go straight to code.
73
- Planning collapses ambiguity before implementation.
74
-
75
- ### 3. Test First (TDD)
76
-
77
- Red → Green → Refactor per behavior:
78
-
79
- 1. Write one failing test naming the behavior.
80
- 2. Run test — verify it fails for the expected reason.
81
- 3. Write minimal code to pass.
82
- 4. Run test — verify pass, other tests still green.
83
- 5. Refactor if needed, keep green.
84
-
85
- No production code without a failing test first.
86
-
87
- ### 4. Review (before `/ttt:done`)
88
-
89
- Verify before claiming completion — run and confirm output:
90
-
91
- - Full test suite passes.
92
- - `npm run lint` / `npm run type` clean (or project-specific commands).
93
- - Only requested scope changed — no drive-by edits.
94
- - No debug logs, stubs, TODOs.
95
-
96
- Evidence before assertions.
97
- Do not claim complete without running the commands.
98
-
99
- ### 5. Complete
100
-
101
- ```text
102
- /ttt:done -m "summary"
103
- ```
104
-
105
- A task is NOT complete until `/ttt:done` runs.
106
- This is MANDATORY.
107
-
108
- ## Project-Specific Skill
58
+ - Branch using the repo's existing naming convention.
59
+ - State a short plan before coding; for unclear scope or 3+ files, settle the scope with the user first.
60
+ - Write the failing test first, then the minimal code to pass it.
61
+ - Run lint / type / test and report the real output before claiming completion.
62
+ - Offer `/ttt:write-work-on-skill` to capture this project's commands as a reusable skill.
109
63
 
110
- Check `.claude/skills/work-on/` or `.claude/skills/start-work/` for project-specific lint / type / test commands and conventions.
111
- If missing, suggest `/ttt:write-work-on-skill` — it scaffolds a skill following this same 4-phase structure.
64
+ Either path closes the task with `/ttt:done -m "summary"`.
112
65
 
113
66
  ## Error Handling
114
67
 
package/dist/bin/cli.js CHANGED
@@ -172,7 +172,7 @@ async function main() {
172
172
  break;
173
173
  case "create":
174
174
  process.argv = ["node", "create.js", ...commandArgs];
175
- await importScript("create.js");
175
+ await importScript("create.js").then((module) => module.create());
176
176
  break;
177
177
  case "assign":
178
178
  process.argv = ["node", "assign.js", ...commandArgs];
@@ -70,4 +70,7 @@ Examples:
70
70
  console.log(` Removed from local cycle data.`);
71
71
  }
72
72
  }
73
- cancel().catch(console.error);
73
+ cancel().catch((error) => {
74
+ console.error(error);
75
+ process.exit(1);
76
+ });
@@ -1,2 +1,2 @@
1
1
  #!/usr/bin/env bun
2
- export {};
2
+ export declare function create(args?: string[]): Promise<void>;
@@ -1,4 +1,6 @@
1
1
  #!/usr/bin/env bun
2
+ import path from "node:path";
3
+ import { pathToFileURL } from "node:url";
2
4
  import { input, select } from "@inquirer/prompts";
3
5
  import { createAdapter } from "./lib/adapters/index.js";
4
6
  import { getSourceType, getTeamId, loadConfig, loadCycleData, loadLocalConfig, sourceIssueToTask, upsertTaskInCycleData, } from "./utils.js";
@@ -121,8 +123,7 @@ async function resolveParentSourceId(adapter, parentIdentifier) {
121
123
  }
122
124
  return parent.sourceId;
123
125
  }
124
- async function create() {
125
- const args = process.argv.slice(2);
126
+ export async function create(args = process.argv.slice(2)) {
126
127
  if (args.includes("--help") || args.includes("-h")) {
127
128
  console.log(`Usage: ttt create [options]
128
129
 
@@ -156,6 +157,10 @@ Examples:
156
157
  const labelArg = parsed.label;
157
158
  const statusName = parsed.status;
158
159
  const parentId = parsed.parent;
160
+ if (sourceType === "trello" && parentId) {
161
+ console.error("Parent issues are not supported for Trello cards.");
162
+ process.exit(1);
163
+ }
159
164
  if (!title) {
160
165
  if (!parsed.interactive) {
161
166
  console.error("Title is required when --no-interactive is set.");
@@ -204,8 +209,13 @@ Examples:
204
209
  }
205
210
  console.log("Creating issue...");
206
211
  const adapter = createAdapter(config);
212
+ let cycleData = sourceType === "trello" ? await loadCycleData() : null;
213
+ if (sourceType === "trello" && !cycleData) {
214
+ console.error("No cycle data found. Run ttt sync before creating a card.");
215
+ process.exit(1);
216
+ }
207
217
  const assigneeId = resolveAssigneeId(config, assigneeKey);
208
- const statusId = await resolveStatusId(config, adapter, teamId, statusName);
218
+ const statusId = await resolveStatusId(config, adapter, teamId, sourceType === "trello" && !statusName ? "todo" : statusName);
209
219
  const labelIds = resolveLabelIds(config, labelArg);
210
220
  const parentSourceId = await resolveParentSourceId(adapter, parentId);
211
221
  const currentCycle = await adapter.getCurrentCycle(teamId);
@@ -229,11 +239,19 @@ Examples:
229
239
  console.log(`\n✅ Created ${issue.id}: ${issue.title}`);
230
240
  if (issue.url)
231
241
  console.log(` ${issue.url}`);
232
- const cycleData = await loadCycleData();
242
+ if (sourceType !== "trello")
243
+ cycleData = await loadCycleData();
233
244
  if (cycleData) {
234
245
  const task = sourceIssueToTask(issue, sourceType);
235
246
  await upsertTaskInCycleData(task, cycleData);
236
247
  console.log(` Added to local cycle data.`);
237
248
  }
238
249
  }
239
- create().catch(console.error);
250
+ const entryPath = process.argv[1];
251
+ if (entryPath &&
252
+ import.meta.url === pathToFileURL(path.resolve(entryPath)).href) {
253
+ create().catch((error) => {
254
+ console.error("Failed to create issue:", error instanceof Error ? error.message : error);
255
+ process.exitCode = 1;
256
+ });
257
+ }
@@ -294,18 +294,25 @@ export class LinearAdapter {
294
294
  }
295
295
  async cancelIssue(sourceId) {
296
296
  try {
297
- // Find the "Cancelled" workflow state for this issue's team
297
+ // Resolve by statusType, not display name -- teams name this state
298
+ // "Canceled", "Cancelled", "Done - Cancelled", etc.
298
299
  const issue = await this.client.issue(sourceId);
299
300
  const team = await issue.team;
300
301
  if (!team) {
301
302
  return { success: false, error: "Could not determine issue team" };
302
303
  }
303
304
  const states = await this.client.workflowStates({
304
- filter: { team: { id: { eq: team.id } }, type: { eq: "cancelled" } },
305
+ filter: {
306
+ team: { id: { eq: team.id } },
307
+ type: { in: ["canceled", "cancelled"] },
308
+ },
305
309
  });
306
310
  const cancelledState = states.nodes[0];
307
311
  if (!cancelledState) {
308
- return { success: false, error: "No 'cancelled' workflow state found" };
312
+ return {
313
+ success: false,
314
+ error: `No cancelled-type workflow state found for team ${team.id}`,
315
+ };
309
316
  }
310
317
  const payload = await this.client.updateIssue(sourceId, {
311
318
  stateId: cancelledState.id,
@@ -27,7 +27,7 @@ export declare class TrelloAdapter implements TaskSourceAdapter {
27
27
  error?: string;
28
28
  }>;
29
29
  getInitData(teamId?: string): Promise<InitData>;
30
- createIssue(_options: CreateIssueOptions): Promise<{
30
+ createIssue(options: CreateIssueOptions): Promise<{
31
31
  success: boolean;
32
32
  issue?: SourceIssue;
33
33
  error?: string;
@@ -4,6 +4,12 @@
4
4
  */
5
5
  import { TrelloClient } from "../trello.js";
6
6
  import { detectPriorityFromLabels, } from "./types.js";
7
+ const PRIORITY_NAMES = {
8
+ 1: "urgent",
9
+ 2: "high",
10
+ 3: "medium",
11
+ 4: "low",
12
+ };
7
13
  export class TrelloAdapter {
8
14
  type = "trello";
9
15
  client;
@@ -278,11 +284,85 @@ export class TrelloAdapter {
278
284
  currentCycle: undefined, // Trello has no cycle
279
285
  };
280
286
  }
281
- async createIssue(_options) {
282
- return {
283
- success: false,
284
- error: "createIssue is not yet supported for Trello",
285
- };
287
+ async createIssue(options) {
288
+ try {
289
+ const statuses = await this.getStatuses(options.teamId);
290
+ const targetStatus = options.statusId
291
+ ? statuses.find((status) => status.id === options.statusId)
292
+ : statuses[0];
293
+ if (!targetStatus) {
294
+ return {
295
+ success: false,
296
+ error: options.statusId
297
+ ? `Trello list ${options.statusId} is not open on board ${options.teamId}`
298
+ : `Trello board ${options.teamId} has no open lists`,
299
+ };
300
+ }
301
+ const labelIds = new Set(options.labelIds ?? []);
302
+ let knownLabels = [];
303
+ if (labelIds.size > 0 || (options.priority ?? 0) > 0) {
304
+ knownLabels = await this.getLabels(options.teamId);
305
+ }
306
+ if (options.priority && options.priority > 0) {
307
+ const priorityLabel = knownLabels.find((label) => detectPriorityFromLabels([label.name]) === options.priority);
308
+ if (!priorityLabel) {
309
+ return {
310
+ success: false,
311
+ error: `Trello board ${options.teamId} has no label matching priority "${PRIORITY_NAMES[options.priority]}"`,
312
+ };
313
+ }
314
+ labelIds.add(priorityLabel.id);
315
+ }
316
+ const card = await this.client.createCard({
317
+ name: options.title,
318
+ idList: targetStatus.id,
319
+ desc: options.description,
320
+ idMembers: options.assigneeId ? [options.assigneeId] : undefined,
321
+ idLabels: labelIds.size > 0 ? [...labelIds] : undefined,
322
+ });
323
+ if (!card.id || !card.shortLink || !card.name || !card.idList) {
324
+ return {
325
+ success: false,
326
+ error: "Trello created a card but returned an incomplete response",
327
+ };
328
+ }
329
+ const labelNames = Array.isArray(card.labels)
330
+ ? card.labels.map((label) => label.name).filter(Boolean)
331
+ : knownLabels
332
+ .filter((label) => labelIds.has(label.id))
333
+ .map((label) => label.name);
334
+ const status = statuses.find((candidate) => candidate.id === card.idList)?.name ??
335
+ targetStatus.name;
336
+ const assigneeId = Array.isArray(card.idMembers)
337
+ ? card.idMembers[0]
338
+ : options.assigneeId;
339
+ return {
340
+ success: true,
341
+ issue: {
342
+ id: card.shortLink,
343
+ sourceId: card.id,
344
+ title: card.name,
345
+ description: card.desc || undefined,
346
+ status,
347
+ statusId: card.idList,
348
+ assigneeId,
349
+ assigneeEmail: undefined,
350
+ priority: detectPriorityFromLabels(labelNames),
351
+ labels: labelNames,
352
+ url: card.url,
353
+ parentIssueId: undefined,
354
+ branchName: undefined,
355
+ attachments: undefined,
356
+ comments: undefined,
357
+ },
358
+ };
359
+ }
360
+ catch (error) {
361
+ return {
362
+ success: false,
363
+ error: error instanceof Error ? error.message : "Unknown error",
364
+ };
365
+ }
286
366
  }
287
367
  async updateIssue(_sourceId, _fields) {
288
368
  return {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "team-toon-tack",
3
- "version": "3.9.0",
3
+ "version": "3.9.3",
4
4
  "description": "Linear & Trello task sync & management CLI with TOON format",
5
5
  "type": "module",
6
6
  "bin": {
@@ -14,6 +14,7 @@
14
14
  "files": [
15
15
  "dist",
16
16
  ".claude-plugin",
17
+ ".codex-plugin",
17
18
  "commands",
18
19
  "skills"
19
20
  ],
@@ -3,12 +3,13 @@ name: managing-linear-tasks
3
3
  description: Use when the user mentions Linear or Trello issues, references issue IDs like MP-123, or asks to sync, show, start, complete, create, assign, edit, cancel, comment on, or check status of tasks.
4
4
  ---
5
5
 
6
- <law>
7
- ALL task operations MUST go through the `ttt` CLI via Bash tool.
8
- NEVER manually edit `.ttt/` files (cycle.toon, config.toon, local.toon).
9
- NEVER fabricate issue data — always run the CLI to get real data.
10
- After completing any task, MUST execute `/ttt:done -m "summary"`.
11
- </law>
6
+ ## 執行方式
7
+
8
+ Codex Claude Code 中,使用可用的 shell 工具執行 `ttt` CLI。
9
+ 任務資料以 CLI 的查詢結果為準;透過 CLI 更新 `.ttt/` 內的設定與狀態。
10
+ 使用者要求完成任務時,執行 `ttt done -m "摘要"`。
11
+ Claude Code 也提供 `/ttt:*` slash commands,對應下方相同的 CLI 操作。
12
+
12
13
 
13
14
  # Task Manager (Linear/Trello)
14
15
 
@@ -16,23 +17,23 @@ Manage developer task workflows using the `ttt` CLI.
16
17
 
17
18
  ## Command Router
18
19
 
19
- Match user intent to the correct `/ttt:*` command:
20
+ 依使用者意圖選擇下列 `ttt` CLI 指令:
20
21
 
21
22
  | User Intent | Command | Example |
22
23
  |-------------|---------|---------|
23
- | Sync/fetch issues | `/ttt:sync` | "sync my issues", "pull from Linear" |
24
- | Show/search issues | `/ttt:show` | "show MP-624", "list my tasks", "what issues do I have" |
25
- | Start working on a task | `/ttt:work-on` | "work on next", "start MP-624" |
26
- | Create a new issue | `/ttt:create` | "create issue", "open a ticket", "new task" |
27
- | Reassign an issue | `/ttt:assign` | "assign MP-624 to john", "reassign to jane" |
28
- | Edit issue fields | `/ttt:edit` | "rename MP-624", "change priority", "update labels" |
29
- | Cancel an issue | `/ttt:cancel` | "cancel MP-624", "abandon this task" |
30
- | Record an estimate | `/ttt:estimate` | "estimate MP-624 as 6h", "save 2.5h estimate" |
31
- | Check/change status | `/ttt:status` | "what's my current task", "set MP-624 to blocked" |
32
- | Add a comment | `/ttt:comment` | "comment on MP-624", "add note to task" |
33
- | Complete a task | `/ttt:done` | "done", "mark complete", "finish task" |
34
-
35
- **When a matching intent is detected, invoke the corresponding `/ttt:*` slash command.**
24
+ | Sync/fetch issues | `ttt sync` | "sync my issues", "pull from Linear" |
25
+ | Show/search issues | `ttt show` | "show MP-624", "list my tasks", "what issues do I have" |
26
+ | Start working on a task | `ttt work-on` | "work on next", "start MP-624" |
27
+ | Create a new issue | `ttt create` | "create issue", "open a ticket", "new task" |
28
+ | Reassign an issue | `ttt assign` | "assign MP-624 to john", "reassign to jane" |
29
+ | Edit issue fields | `ttt edit` | "rename MP-624", "change priority", "update labels" |
30
+ | Cancel an issue | `ttt cancel` | "cancel MP-624", "abandon this task" |
31
+ | Record an estimate | `ttt estimate` | "estimate MP-624 as 6h", "save 2.5h estimate" |
32
+ | Check/change status | `ttt status` | "what's my current task", "set MP-624 to blocked" |
33
+ | Add a comment | `ttt comment` | "comment on MP-624", "add note to task" |
34
+ | Complete a task | `ttt done` | "done", "mark complete", "finish task" |
35
+
36
+ **意圖符合時,透過 shell 工具執行對應的 `ttt` CLI 指令。**
36
37
 
37
38
  ## Quick Reference
38
39
 
@@ -96,7 +97,7 @@ ttt sync → ttt work-on next → ttt estimate <id> <hours> → [implement] →
96
97
  | "I'll edit `cycle.toon` directly, faster" | `cycle.toon` is auto-generated. Manual edits get overwritten on next `ttt sync`. Always go through the CLI. |
97
98
  | "I remember this issue ID, no need to sync" | Remote status, assignee, priority may have changed. Run `ttt sync` or `ttt show <id> --remote` first. |
98
99
  | "I'll create the issue in the Linear/Trello UI instead" | Bypassing `ttt create` leaves the new issue outside local cycle data. Use the CLI so it gets tracked. |
99
- | "Task is obvious, skip `/ttt:done`" | `/ttt:done` syncs local + remote status, posts a completion comment, reads git commit info. Skipping leaves state inconsistent. |
100
+ | "Task is obvious, skip `ttt done`" | `ttt done` syncs local + remote status, posts a completion comment, reads git commit info. Skipping leaves state inconsistent. |
100
101
  | "I know what the task needs without reading it" | Fabricated assumptions produce wrong work. Run `ttt show <id>` before starting. |
101
102
  | "Fetch issue details via Linear MCP / web UI" | The CLI is authoritative and token-efficient. Use `ttt show` / `ttt sync`, not alternate data paths. |
102
103
 
@@ -109,17 +110,17 @@ digraph ttt_router {
109
110
  user [label="User mentions\nLinear/Trello", shape=doublecircle];
110
111
  classify [label="Classify intent", shape=diamond];
111
112
 
112
- sync [label="/ttt:sync", shape=box];
113
- show [label="/ttt:show", shape=box];
114
- work_on [label="/ttt:work-on", shape=box];
115
- create [label="/ttt:create", shape=box];
116
- assign [label="/ttt:assign", shape=box];
117
- edit [label="/ttt:edit", shape=box];
118
- cancel [label="/ttt:cancel", shape=box];
119
- estimate [label="/ttt:estimate", shape=box];
120
- status [label="/ttt:status", shape=box];
121
- comment [label="/ttt:comment", shape=box];
122
- done [label="/ttt:done", shape=box];
113
+ sync [label="ttt sync", shape=box];
114
+ show [label="ttt show", shape=box];
115
+ work_on [label="ttt work-on", shape=box];
116
+ create [label="ttt create", shape=box];
117
+ assign [label="ttt assign", shape=box];
118
+ edit [label="ttt edit", shape=box];
119
+ cancel [label="ttt cancel", shape=box];
120
+ estimate [label="ttt estimate", shape=box];
121
+ status [label="ttt status", shape=box];
122
+ comment [label="ttt comment", shape=box];
123
+ done [label="ttt done", shape=box];
123
124
 
124
125
  user -> classify;
125
126
  classify -> sync [label="fetch / pull"];