@infinitedusky/indusk-mcp 1.0.3 → 1.1.1
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/dist/tools/graph-tools.js +156 -1
- package/extensions/cgc/skill.md +57 -16
- package/hooks/validate-impl-structure.js +0 -7
- package/package.json +1 -1
- package/skills/{onboard.md → catchup.md} +36 -15
- package/skills/handoff.md +50 -0
|
@@ -69,7 +69,7 @@ export function indexProject(projectRoot) {
|
|
|
69
69
|
}
|
|
70
70
|
export function registerGraphTools(server, projectRoot) {
|
|
71
71
|
server.registerTool("index_project", {
|
|
72
|
-
description: "Index the project codebase into the code graph. Run this after init or when the codebase has changed significantly.
|
|
72
|
+
description: "Index the project codebase into the code graph. Run this after init or when the codebase has changed significantly.",
|
|
73
73
|
}, async () => {
|
|
74
74
|
const result = indexProject(projectRoot);
|
|
75
75
|
return {
|
|
@@ -113,4 +113,159 @@ export function registerGraphTools(server, projectRoot) {
|
|
|
113
113
|
content: [{ type: "text", text: output }],
|
|
114
114
|
};
|
|
115
115
|
});
|
|
116
|
+
server.registerTool("graph_visualize", {
|
|
117
|
+
description: "Launch the interactive code graph visualization in the browser. Shows nodes (files, functions, classes) and relationships (calls, imports, inherits). Use when the user wants to see or explore the code graph visually.",
|
|
118
|
+
}, async () => {
|
|
119
|
+
const cgc = cgcPath();
|
|
120
|
+
if (!cgc) {
|
|
121
|
+
return {
|
|
122
|
+
content: [
|
|
123
|
+
{ type: "text", text: JSON.stringify({ error: "CGC not installed" }) },
|
|
124
|
+
],
|
|
125
|
+
isError: true,
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
try {
|
|
129
|
+
execSync(`${cgc} visualize --port 8111 &`, {
|
|
130
|
+
encoding: "utf-8",
|
|
131
|
+
timeout: 5000,
|
|
132
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
133
|
+
cwd: projectRoot,
|
|
134
|
+
env: {
|
|
135
|
+
...process.env,
|
|
136
|
+
DATABASE_TYPE: "falkordb-remote",
|
|
137
|
+
FALKORDB_HOST: process.env.FALKORDB_HOST ?? "falkordb.orb.local",
|
|
138
|
+
FALKORDB_GRAPH_NAME: process.env.FALKORDB_GRAPH_NAME ?? basename(projectRoot),
|
|
139
|
+
},
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
catch {
|
|
143
|
+
// visualize runs in background, the timeout catch is expected
|
|
144
|
+
}
|
|
145
|
+
return {
|
|
146
|
+
content: [
|
|
147
|
+
{
|
|
148
|
+
type: "text",
|
|
149
|
+
text: JSON.stringify({
|
|
150
|
+
success: true,
|
|
151
|
+
url: "http://localhost:8111",
|
|
152
|
+
message: "Code graph visualization started at http://localhost:8111 — open in browser",
|
|
153
|
+
}, null, 2),
|
|
154
|
+
},
|
|
155
|
+
],
|
|
156
|
+
};
|
|
157
|
+
});
|
|
158
|
+
server.registerTool("graph_doctor", {
|
|
159
|
+
description: "Run CGC diagnostics to check database connection, configuration, and system health. Use when graph tools return errors or when debugging graph issues.",
|
|
160
|
+
}, async () => {
|
|
161
|
+
const output = runCgc("doctor", projectRoot);
|
|
162
|
+
return {
|
|
163
|
+
content: [{ type: "text", text: output }],
|
|
164
|
+
};
|
|
165
|
+
});
|
|
166
|
+
server.registerTool("graph_find_dead_code", {
|
|
167
|
+
description: "Find potentially unused functions (dead code) across the indexed codebase. Useful for cleanup and refactoring.",
|
|
168
|
+
}, async () => {
|
|
169
|
+
const output = runCgc("analyze dead-code", projectRoot);
|
|
170
|
+
return {
|
|
171
|
+
content: [{ type: "text", text: output }],
|
|
172
|
+
};
|
|
173
|
+
});
|
|
174
|
+
server.registerTool("graph_complexity", {
|
|
175
|
+
description: "Find the most complex functions in the codebase by cyclomatic complexity. Useful for identifying refactoring targets.",
|
|
176
|
+
inputSchema: {
|
|
177
|
+
limit: z.number().default(10).describe("Number of results to return"),
|
|
178
|
+
},
|
|
179
|
+
}, async ({ limit }) => {
|
|
180
|
+
const output = runCgc(`analyze complexity --limit ${limit}`, projectRoot);
|
|
181
|
+
return {
|
|
182
|
+
content: [{ type: "text", text: output }],
|
|
183
|
+
};
|
|
184
|
+
});
|
|
185
|
+
server.registerTool("graph_callers", {
|
|
186
|
+
description: "Find all functions that call a given function. Use to understand impact before modifying a function.",
|
|
187
|
+
inputSchema: {
|
|
188
|
+
function_name: z.string().describe("Name of the function to find callers for"),
|
|
189
|
+
},
|
|
190
|
+
}, async ({ function_name }) => {
|
|
191
|
+
const output = runCgc(`analyze callers "${function_name}"`, projectRoot);
|
|
192
|
+
return {
|
|
193
|
+
content: [{ type: "text", text: output }],
|
|
194
|
+
};
|
|
195
|
+
});
|
|
196
|
+
server.registerTool("graph_callees", {
|
|
197
|
+
description: "Find all functions that a given function calls. Use to understand what a function depends on.",
|
|
198
|
+
inputSchema: {
|
|
199
|
+
function_name: z.string().describe("Name of the function to find callees for"),
|
|
200
|
+
},
|
|
201
|
+
}, async ({ function_name }) => {
|
|
202
|
+
const output = runCgc(`analyze calls "${function_name}"`, projectRoot);
|
|
203
|
+
return {
|
|
204
|
+
content: [{ type: "text", text: output }],
|
|
205
|
+
};
|
|
206
|
+
});
|
|
207
|
+
server.registerTool("graph_find", {
|
|
208
|
+
description: "Search the code graph for functions, classes, or modules by name or content. Faster than grep for structural queries.",
|
|
209
|
+
inputSchema: {
|
|
210
|
+
query: z.string().describe("Name or keyword to search for"),
|
|
211
|
+
type: z
|
|
212
|
+
.enum(["name", "pattern", "content"])
|
|
213
|
+
.default("name")
|
|
214
|
+
.describe("Search type: exact name, substring pattern, or content search"),
|
|
215
|
+
},
|
|
216
|
+
}, async ({ query, type }) => {
|
|
217
|
+
const output = runCgc(`find ${type} "${query}"`, projectRoot);
|
|
218
|
+
return {
|
|
219
|
+
content: [{ type: "text", text: output }],
|
|
220
|
+
};
|
|
221
|
+
});
|
|
222
|
+
server.registerTool("graph_watch", {
|
|
223
|
+
description: "Start watching the project directory for file changes and auto-update the graph. Keeps the graph current without manual re-indexing.",
|
|
224
|
+
}, async () => {
|
|
225
|
+
const cgc = cgcPath();
|
|
226
|
+
if (!cgc) {
|
|
227
|
+
return {
|
|
228
|
+
content: [
|
|
229
|
+
{ type: "text", text: JSON.stringify({ error: "CGC not installed" }) },
|
|
230
|
+
],
|
|
231
|
+
isError: true,
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
try {
|
|
235
|
+
execSync(`${cgc} watch ${projectRoot} &`, {
|
|
236
|
+
encoding: "utf-8",
|
|
237
|
+
timeout: 5000,
|
|
238
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
239
|
+
cwd: projectRoot,
|
|
240
|
+
env: {
|
|
241
|
+
...process.env,
|
|
242
|
+
DATABASE_TYPE: "falkordb-remote",
|
|
243
|
+
FALKORDB_HOST: process.env.FALKORDB_HOST ?? "falkordb.orb.local",
|
|
244
|
+
FALKORDB_GRAPH_NAME: process.env.FALKORDB_GRAPH_NAME ?? basename(projectRoot),
|
|
245
|
+
},
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
catch {
|
|
249
|
+
// watch runs in background
|
|
250
|
+
}
|
|
251
|
+
return {
|
|
252
|
+
content: [
|
|
253
|
+
{
|
|
254
|
+
type: "text",
|
|
255
|
+
text: JSON.stringify({
|
|
256
|
+
success: true,
|
|
257
|
+
message: `Watching ${projectRoot} for changes — graph will auto-update`,
|
|
258
|
+
}, null, 2),
|
|
259
|
+
},
|
|
260
|
+
],
|
|
261
|
+
};
|
|
262
|
+
});
|
|
263
|
+
server.registerTool("graph_stats", {
|
|
264
|
+
description: "Get statistics about the indexed codebase: file count, function count, class count, module count.",
|
|
265
|
+
}, async () => {
|
|
266
|
+
const output = runCgc("stats", projectRoot);
|
|
267
|
+
return {
|
|
268
|
+
content: [{ type: "text", text: output }],
|
|
269
|
+
};
|
|
270
|
+
});
|
|
116
271
|
}
|
package/extensions/cgc/skill.md
CHANGED
|
@@ -2,34 +2,75 @@
|
|
|
2
2
|
|
|
3
3
|
CodeGraphContext (CGC) provides structural code intelligence — dependency analysis, dead code detection, complexity metrics — via a FalkorDB graph database.
|
|
4
4
|
|
|
5
|
+
## How to Use the Graph
|
|
6
|
+
|
|
7
|
+
**All graph operations go through indusk-mcp tools.** Do not call CGC's MCP tools directly — use the `graph_*` tools from indusk-mcp instead. They handle configuration, error recovery, and provide a consistent interface whether calling the MCP server or CLI under the hood.
|
|
8
|
+
|
|
5
9
|
## When to Query the Graph
|
|
6
10
|
|
|
7
11
|
- **Before modifying any file**: call `query_dependencies` to understand blast radius
|
|
8
|
-
- **During planning research**: call `
|
|
9
|
-
- **During verification**: call `
|
|
10
|
-
- **During retrospective**: call `
|
|
12
|
+
- **During planning research**: call `graph_find` and `query_dependencies` to scope work with real data
|
|
13
|
+
- **During verification**: call `graph_callers` to find affected consumers, then test them
|
|
14
|
+
- **During retrospective**: call `graph_find_dead_code` and `graph_complexity` for cleanup opportunities
|
|
15
|
+
- **When debugging structure**: call `graph_visualize` to see the graph in the browser
|
|
11
16
|
|
|
12
|
-
## Available Tools (from
|
|
17
|
+
## Available Tools (all from indusk-mcp)
|
|
13
18
|
|
|
19
|
+
### Core
|
|
14
20
|
| Tool | When |
|
|
15
21
|
|------|------|
|
|
16
|
-
| `
|
|
17
|
-
| `
|
|
18
|
-
| `
|
|
19
|
-
| `
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
|
22
|
+
| `index_project` | After init or when codebase changed significantly |
|
|
23
|
+
| `query_dependencies` | Before modifying any file — understand blast radius |
|
|
24
|
+
| `query_graph` | Custom Cypher queries for advanced structural analysis |
|
|
25
|
+
| `graph_stats` | Codebase size and structure overview |
|
|
26
|
+
|
|
27
|
+
### Analysis
|
|
28
|
+
| Tool | When |
|
|
29
|
+
|------|------|
|
|
30
|
+
| `graph_callers` | Find all functions that call a given function |
|
|
31
|
+
| `graph_callees` | Find all functions a given function calls |
|
|
32
|
+
| `graph_find` | Search for functions, classes, modules by name or content |
|
|
33
|
+
| `graph_find_dead_code` | Find unused functions for cleanup |
|
|
34
|
+
| `graph_complexity` | Find most complex functions for refactoring targets |
|
|
35
|
+
|
|
36
|
+
### Operations
|
|
37
|
+
| Tool | When |
|
|
38
|
+
|------|------|
|
|
39
|
+
| `graph_visualize` | Launch interactive graph UI in the browser |
|
|
40
|
+
| `graph_watch` | Auto-update graph on file changes (stays current) |
|
|
41
|
+
| `graph_doctor` | Diagnose graph issues (connection, config, health) |
|
|
23
42
|
|
|
24
43
|
## Visualizing
|
|
25
44
|
|
|
26
|
-
When asked to "show the graph"
|
|
27
|
-
1. Call `
|
|
28
|
-
2. For text output, use `
|
|
45
|
+
When asked to "show the graph", "display dependencies", or "visualize":
|
|
46
|
+
1. Call `graph_visualize` — launches the interactive playground UI at http://localhost:8111
|
|
47
|
+
2. For text output, use `query_graph` with a Cypher query and format as a table
|
|
48
|
+
3. FalkorDB's own browser UI is also available at `falkordb.orb.local:3000`
|
|
49
|
+
|
|
50
|
+
## Troubleshooting
|
|
51
|
+
|
|
52
|
+
**If any graph tool fails, call `graph_doctor` first.** It checks:
|
|
53
|
+
- CGC installation
|
|
54
|
+
- FalkorDB connection
|
|
55
|
+
- Configuration validity
|
|
56
|
+
- Parser availability
|
|
57
|
+
|
|
58
|
+
**Common issues:**
|
|
59
|
+
- FalkorDB not running → `docker start falkordb` (or start OrbStack)
|
|
60
|
+
- Repo not indexed → call `index_project`
|
|
61
|
+
- Data lost after container recreation → volume was on wrong path, reindex
|
|
62
|
+
- OrbStack not running → DNS resolution fails, start OrbStack app
|
|
29
63
|
|
|
30
64
|
## Setup
|
|
31
65
|
|
|
32
|
-
- FalkorDB runs as a global Docker container
|
|
66
|
+
- FalkorDB runs as a global Docker container at `falkordb.orb.local`
|
|
33
67
|
- CGC installed via pipx: `pipx install codegraphcontext`
|
|
34
68
|
- Per-project isolation via `FALKORDB_GRAPH_NAME` in `.mcp.json`
|
|
35
|
-
-
|
|
69
|
+
- Auto-watch enabled: graph updates automatically on file changes
|
|
70
|
+
- SCIP indexer enabled: higher accuracy call resolution for TypeScript
|
|
71
|
+
- Volume mount: `/var/lib/falkordb/data` (not `/data` — see community lesson)
|
|
72
|
+
|
|
73
|
+
## Known Limitations
|
|
74
|
+
|
|
75
|
+
- **Import resolution noise**: CGC creates Module nodes for every import, including npm packages (React, Next, etc.). These are orphan nodes. Filter in Cypher with `WHERE EXISTS((m)-[:CONTAINS]->())` to see only project modules.
|
|
76
|
+
- **No dependency resolution control**: Can't disable Module node creation for external imports. This is a CGC limitation.
|
|
@@ -179,13 +179,6 @@ for (const line of lines) {
|
|
|
179
179
|
}
|
|
180
180
|
if (currentPhase) phases.push(currentPhase);
|
|
181
181
|
|
|
182
|
-
// Check for opt-out content in gate sections
|
|
183
|
-
// Re-scan to check if sections that exist have (none needed) or skip-reason:
|
|
184
|
-
const isOptedOut = (text) =>
|
|
185
|
-
text.includes("(none needed)") ||
|
|
186
|
-
text.includes("(not applicable)") ||
|
|
187
|
-
text.includes("skip-reason:");
|
|
188
|
-
|
|
189
182
|
// Validate each phase
|
|
190
183
|
const errors = [];
|
|
191
184
|
for (const phase of phases) {
|
package/package.json
CHANGED
|
@@ -1,19 +1,30 @@
|
|
|
1
1
|
---
|
|
2
|
-
name:
|
|
3
|
-
description: Get
|
|
2
|
+
name: catchup
|
|
3
|
+
description: Get caught up on the project. Reads the handoff from the last session, then context, plans, lessons, extensions, and code graph. Run at the start of every new session.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
You are starting a new session on this project. Before doing anything else, get caught up.
|
|
7
7
|
|
|
8
8
|
## Steps (execute in order)
|
|
9
9
|
|
|
10
|
-
### 1. Read
|
|
10
|
+
### 1. Read Handoff
|
|
11
|
+
Check if `.claude/handoff.md` exists. If it does, read it first — this is the most recent context from the last session. It tells you:
|
|
12
|
+
- What was being worked on
|
|
13
|
+
- Where it stopped
|
|
14
|
+
- What's next
|
|
15
|
+
- Any warnings or open issues
|
|
16
|
+
|
|
17
|
+
If the handoff exists, present a brief summary to the user: "Last session was working on X, stopped at Y. Ready to pick up there?"
|
|
18
|
+
|
|
19
|
+
If no handoff exists, skip to step 2.
|
|
20
|
+
|
|
21
|
+
### 2. Read Lessons
|
|
11
22
|
Call `list_lessons`. Read every lesson. These are rules learned from past mistakes — not suggestions. Internalize them before touching any code.
|
|
12
23
|
|
|
13
|
-
###
|
|
24
|
+
### 3. Check Infrastructure
|
|
14
25
|
Call `check_health`. Verify FalkorDB and CGC are running. If unhealthy, tell the user what's down and how to fix it.
|
|
15
26
|
|
|
16
|
-
###
|
|
27
|
+
### 4. Read Project Context
|
|
17
28
|
Call `get_context` to read CLAUDE.md. This contains:
|
|
18
29
|
- **Architecture** — what the project is, how it's structured
|
|
19
30
|
- **Conventions** — rules to follow (commit style, no DB from Next.js, no fallback URLs, etc.)
|
|
@@ -23,39 +34,49 @@ Call `get_context` to read CLAUDE.md. This contains:
|
|
|
23
34
|
|
|
24
35
|
Read it fully. Don't skim.
|
|
25
36
|
|
|
26
|
-
###
|
|
37
|
+
### 5. Check Active Plans
|
|
27
38
|
Call `list_plans`. This shows every plan and its status. Pay attention to:
|
|
28
39
|
- Plans with status `in-progress` — these are actively being worked on
|
|
29
40
|
- The current phase of each active plan — this is where `/work` will pick up
|
|
30
41
|
- Dependencies between plans — don't start a blocked plan
|
|
31
42
|
|
|
32
|
-
###
|
|
33
|
-
Call `extensions_status` to see what extensions are enabled and their capabilities.
|
|
43
|
+
### 6. Review Skills and Extensions
|
|
44
|
+
Call `extensions_status` to see what extensions are enabled and their capabilities.
|
|
45
|
+
|
|
46
|
+
Then read all installed skill files in `.claude/skills/*/SKILL.md`. These define your workflows:
|
|
47
|
+
- **Process skills** (plan, work, verify, context, document, retrospective) — how you build things
|
|
48
|
+
- **Domain skills** (typescript, nextjs, etc.) — technology-specific best practices
|
|
49
|
+
- **Extension skills** (cgc, composable-env, etc.) — tool integrations and when to use them
|
|
50
|
+
- **Utility skills** (catchup, handoff, toolbelt) — operational skills
|
|
51
|
+
|
|
52
|
+
Understand what each skill does and when to use it. You should be able to answer: "What slash commands are available and what do they do?"
|
|
34
53
|
|
|
35
|
-
###
|
|
54
|
+
### 7. Check Code Graph
|
|
36
55
|
Call `get_repository_stats` to understand the codebase size and structure. This gives you a sense of what's indexed and queryable. If it fails, the CGC extension may not be enabled or FalkorDB may be down — check_health will have flagged this.
|
|
37
56
|
|
|
38
|
-
###
|
|
57
|
+
### 8. Summarize
|
|
39
58
|
|
|
40
|
-
After completing steps
|
|
59
|
+
After completing all steps, present a brief summary to the user:
|
|
41
60
|
|
|
42
61
|
```
|
|
43
|
-
**
|
|
62
|
+
**Caught up.**
|
|
63
|
+
- Handoff: [summary of last session's work, or "none"]
|
|
44
64
|
- Lessons: N loaded
|
|
45
65
|
- Infrastructure: [healthy / issues]
|
|
66
|
+
- Skills: N installed [list names]
|
|
46
67
|
- Extensions: N enabled [list names]
|
|
47
68
|
- Active plans: [list with current phase]
|
|
48
69
|
- Codebase: [N files indexed]
|
|
49
70
|
|
|
50
|
-
Ready to
|
|
71
|
+
Ready to pick up. What would you like to do?
|
|
51
72
|
```
|
|
52
73
|
|
|
53
74
|
## When to Use
|
|
54
75
|
|
|
55
76
|
- Start of every new Claude Code session
|
|
56
|
-
- When the user says "get caught up", "what's going on", "where are we"
|
|
77
|
+
- When the user says "get caught up", "what's going on", "where are we", "catch up"
|
|
57
78
|
- When context was compressed and you need to re-orient
|
|
58
|
-
- `/
|
|
79
|
+
- `/catchup` explicitly
|
|
59
80
|
|
|
60
81
|
## Important
|
|
61
82
|
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: handoff
|
|
3
|
+
description: Write a handoff file before ending a session. Captures what was worked on, where it stopped, what's next, and any warnings for the next agent.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
You are ending a session or handing off to another agent. Write a handoff file so the next session can pick up exactly where you left off.
|
|
7
|
+
|
|
8
|
+
## What to Write
|
|
9
|
+
|
|
10
|
+
Create or overwrite `.claude/handoff.md` with:
|
|
11
|
+
|
|
12
|
+
```markdown
|
|
13
|
+
# Handoff
|
|
14
|
+
|
|
15
|
+
**Date:** {YYYY-MM-DD}
|
|
16
|
+
**Session:** {brief description of what this session focused on}
|
|
17
|
+
|
|
18
|
+
## What Was Being Worked On
|
|
19
|
+
{Plan name, phase, specific checklist item. Be precise — "Phase 3 of extension-system, item 4: refactor check_health" not "working on extensions."}
|
|
20
|
+
|
|
21
|
+
## Where It Stopped
|
|
22
|
+
{Last thing completed. First thing that needs doing next. If mid-item, explain exactly where.}
|
|
23
|
+
|
|
24
|
+
## What's Next
|
|
25
|
+
{The immediate next step. Then the next 2-3 steps after that. This is the pickup point for /catchup.}
|
|
26
|
+
|
|
27
|
+
## Open Issues
|
|
28
|
+
{Anything broken, failing, or weird. Tests that don't pass. Errors being investigated. Things that worked before but don't now.}
|
|
29
|
+
|
|
30
|
+
## Decisions Made This Session
|
|
31
|
+
{Any decisions that aren't captured in CLAUDE.md or an ADR yet. These need to be formalized — they're here so they don't get lost between sessions.}
|
|
32
|
+
|
|
33
|
+
## Watch Out For
|
|
34
|
+
{Gotchas the next agent should know. "The FalkorDB graph needs reindexing." "The hooks aren't published yet — version 1.0.3 has them." "Don't touch init.ts until the extension system PR is merged."}
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## When to Write a Handoff
|
|
38
|
+
|
|
39
|
+
- Before ending any session where work was done
|
|
40
|
+
- When the user says "let's stop here", "wrap up", "hand off"
|
|
41
|
+
- When you're about to run out of context
|
|
42
|
+
- `/handoff` explicitly
|
|
43
|
+
|
|
44
|
+
## Rules
|
|
45
|
+
|
|
46
|
+
- **Be specific.** "Working on Phase 3" is useless. "Phase 3, item 4: refactored check_health to use extensions. extensions_status MCP tool created. Next: refactor init to remove hardcoded FalkorDB/CGC." is useful.
|
|
47
|
+
- **Include the ugly parts.** If something is broken, say so. The next agent needs to know.
|
|
48
|
+
- **Decisions that aren't saved anywhere else MUST go here.** They'll be lost otherwise.
|
|
49
|
+
- **Overwrite the previous handoff.** There's only one — the most recent session's. Old handoffs are consumed by /catchup and don't need to persist.
|
|
50
|
+
- **Keep it short.** This isn't a retrospective. It's a sticky note for the next person.
|