@damper/mcp 0.3.8 → 0.3.10

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/README.md CHANGED
@@ -74,14 +74,15 @@ The AI will see tools from both servers and can distinguish between them:
74
74
  | Tool | Description |
75
75
  |------|-------------|
76
76
  | `list_tasks` | Get roadmap tasks (filter by `status`, `type`, `quarter`, sort by `importance`/`newest`/`votes`) |
77
- | `get_task` | Task details + subtasks + linked feedback |
77
+ | `get_task` | Task details + subtasks + commits + linked feedback |
78
78
  | `create_task` | Create task with type (bug, feature, improvement, task) |
79
79
  | `update_task` | Update description, plan, priority, effort, quarter, labels |
80
80
  | `start_task` | Lock and start task (use `force` to take over). Returns project context index. |
81
81
  | `add_note` | Add progress note |
82
+ | `add_commit` | Log a commit (hash + message). Appears in task details. |
82
83
  | `create_subtask` | Add subtask to a task |
83
84
  | `update_subtask` | Mark subtask done/undone |
84
- | `complete_task` | Mark done, release lock. Suggests context updates if needed. |
85
+ | `complete_task` | Mark done, release lock. Optionally log commits at completion. |
85
86
  | `abandon_task` | Release lock, return to planned |
86
87
  | `list_feedback` | Browse user feedback |
87
88
  | `get_feedback` | Feedback details + votes |
@@ -93,6 +94,7 @@ The AI will see tools from both servers and can distinguish between them:
93
94
  | `get_module` | Get module details |
94
95
  | `update_module` | Register/update a module |
95
96
  | `sync_modules` | Bulk upload module registry |
97
+ | `get_agent_instructions` | Get canonical workflow for CLAUDE.md setup |
96
98
 
97
99
  ### Project Context
98
100
 
@@ -259,21 +261,42 @@ When you start a task, it's locked to prevent other agents from working on it si
259
261
  - Different agent starting → fails with 409 (use `force: true` to take over)
260
262
  - Complete or abandon → releases lock
261
263
 
264
+ ### Commit Tracking
265
+
266
+ Log commits as you work to track code changes for each task:
267
+
268
+ ```
269
+ > Log commit abc1234 with message "Added validation"
270
+ > Add commit def5678: "Fixed auth bug"
271
+ ```
272
+
273
+ Commits are stored structurally and displayed in task details:
274
+
275
+ ```
276
+ ## Commits (2)
277
+ - abc1234: Added validation
278
+ - def5678: Fixed auth bug
279
+ ```
280
+
281
+ **Two ways to log commits:**
282
+ 1. `add_commit` - Log commits as you make them
283
+ 2. `complete_task` with `commits` - Log final commits at completion
284
+
262
285
  ### Recommended Workflow
263
286
 
264
287
  When working on tasks, follow this workflow for best results:
265
288
 
266
289
  1. **Start**: `start_task` → locks the task and returns project context
267
290
  2. **Log start**: `add_note` with "Session started: <your goal>"
268
- 3. **Work**: Make changes, logging commits and decisions with `add_note`
291
+ 3. **Work**: Make changes, use `add_commit` after each commit, `add_note` for decisions
269
292
  4. **Log end**: `add_note` with "Session end: <summary, next steps>"
270
293
  5. **Finish**: `complete_task` (done) or `abandon_task` (stopping)
271
294
 
272
- **Note types to log:**
273
- - Session start: `"Session started: implementing dark mode"`
274
- - Commits: `"Committed abc123: Added theme provider"`
275
- - Decisions: `"Decision: Using CSS variables because..."`
276
- - Session end: `"Session end: Done theme provider, remaining: toggle UI"`
295
+ **What to log:**
296
+ - Session start: `add_note "Session started: implementing dark mode"`
297
+ - Commits: `add_commit abc123 "Added theme provider"`
298
+ - Decisions: `add_note "Decision: Using CSS variables because..."`
299
+ - Session end: `add_note "Session end: Done theme provider, remaining: toggle UI"`
277
300
 
278
301
  **Before completing:**
279
302
  - Push all commits
@@ -310,6 +333,20 @@ When working on tasks, follow this workflow for best results:
310
333
  > Sync all my documentation to Damper
311
334
  ```
312
335
 
336
+ ## Setting Up a Project
337
+
338
+ To add Damper workflow instructions to a new project:
339
+
340
+ ```
341
+ > Get the agent instructions and add them to my CLAUDE.md
342
+ ```
343
+
344
+ The agent will call `get_agent_instructions` and write to your CLAUDE.md file. This ensures you always have the latest workflow instructions.
345
+
346
+ **Formats:**
347
+ - `section` (default): Just the Damper workflow section - append to existing CLAUDE.md
348
+ - `markdown`: Full file with header - use when creating a new CLAUDE.md
349
+
313
350
  ## Agent Instructions (CLAUDE.md)
314
351
 
315
352
  Add this to your project's `CLAUDE.md` (or `.cursorrules` for Cursor) to ensure AI agents use Damper consistently:
@@ -319,25 +356,29 @@ Add this to your project's `CLAUDE.md` (or `.cursorrules` for Cursor) to ensure
319
356
 
320
357
  This project uses Damper MCP for task tracking. **You MUST follow this workflow.**
321
358
 
322
- ### At Session Start
323
- 1. `get_project_context` - Read available project documentation
324
- 2. `list_tasks` - Check for existing tasks to work on
325
- 3. If working on a task: `start_task` to lock it
359
+ ### At Session Start (MANDATORY)
360
+ 1. `get_project_context` - **READ THIS FIRST.** Contains architecture, conventions, and critical project info. Do NOT skip.
361
+ 2. `get_context_section` - Fetch full content for sections relevant to your task (e.g., "api", "database", "testing")
362
+ 3. `list_tasks` - Check for existing tasks to work on
363
+ 4. If working on a task: `start_task` to lock it (returns context index - read relevant sections)
326
364
 
327
365
  ### While Working
328
- - `add_note` after each commit: "Committed abc123: description"
366
+ - `add_commit` after each commit with hash and message
329
367
  - `add_note` for decisions: "Decision: chose X because Y"
330
368
  - `update_subtask` to mark subtask progress
369
+ - **Follow patterns from project context** - Don't reinvent; use existing conventions
331
370
 
332
371
  ### At Session End (MANDATORY)
333
372
  - ALWAYS call `add_note` with session summary before stopping
334
373
  - ALWAYS call `complete_task` (if done) or `abandon_task` (if stopping early)
335
374
  - NEVER leave a started task without completing or abandoning it
375
+ - If you learned something about the codebase, consider updating project context
336
376
 
337
377
  ### Why This Matters
378
+ - **Project context prevents mistakes** - Contains architecture decisions, gotchas, and patterns you need to follow
338
379
  - Locked tasks block other agents from working on them
339
- - Notes help the next agent (or you) continue the work
340
- - Project context saves future agents from re-analyzing the codebase
380
+ - Commits and notes help the next agent (or you) continue the work
381
+ - Updating context saves future agents from re-analyzing the codebase
341
382
  ```
342
383
 
343
384
  ## Environment
@@ -8,29 +8,36 @@
8
8
  * Format start_task response
9
9
  */
10
10
  export function formatStartTaskResponse(result) {
11
- const lines = [`Started ${result.id}: ${result.message}`];
11
+ const lines = [`✅ Started ${result.id}: ${result.message}`];
12
+ // Context section - emphatic about reading it first
12
13
  if (result.context) {
13
14
  if (result.context.isEmpty) {
14
15
  lines.push(`\n📚 ${result.context.hint || 'No project context available.'}`);
15
16
  }
16
17
  else {
17
- lines.push('\n**Project context available:**');
18
+ lines.push('\n⚠️ **BEFORE YOU START:** Read project context to understand patterns and conventions.');
19
+ lines.push('');
20
+ if (result.context.relevantSections && result.context.relevantSections.length > 0) {
21
+ lines.push(`**Required reading for this task:**`);
22
+ for (const section of result.context.relevantSections) {
23
+ lines.push(`→ \`get_context_section("${section}")\``);
24
+ }
25
+ lines.push('');
26
+ }
27
+ lines.push('**All available sections:**');
18
28
  for (const s of result.context.index) {
19
29
  const relevant = result.context.relevantSections?.includes(s.section) ? ' ⭐' : '';
20
30
  lines.push(`• ${s.section}${relevant}`);
21
31
  }
22
- if (result.context.relevantSections && result.context.relevantSections.length > 0) {
23
- lines.push(`\nRelevant for this task: ${result.context.relevantSections.join(', ')}`);
24
- lines.push('Use get_context_section to fetch full content.');
25
- }
26
32
  }
27
33
  }
28
34
  lines.push('\n---');
29
- lines.push('**📋 Workflow:**');
30
- lines.push('1. `add_note`: "Session started: <goal>"');
31
- lines.push('2. Work + log commits/decisions with `add_note`');
32
- lines.push('3. `add_note`: "Session end: <summary, next steps>"');
33
- lines.push('4. `complete_task` or `abandon_task`');
35
+ lines.push('**📋 Required workflow:**');
36
+ lines.push('1. **Read context sections above** (contains patterns you must follow)');
37
+ lines.push('2. `add_note`: "Session started: <goal>"');
38
+ lines.push('3. Work: use `add_commit` for commits, `add_note` for decisions');
39
+ lines.push('4. `add_note`: "Session end: <summary>"');
40
+ lines.push('5. `complete_task` or `abandon_task` (NEVER skip this)');
34
41
  return lines.join('\n');
35
42
  }
36
43
  /**
@@ -38,11 +45,13 @@ export function formatStartTaskResponse(result) {
38
45
  */
39
46
  export function formatCompleteTaskResponse(result) {
40
47
  const lines = [`✅ Completed ${result.id}`];
48
+ lines.push('\n---');
49
+ lines.push('**📚 Before you finish:**');
50
+ lines.push('Did you learn something about this codebase that would help future agents?');
51
+ lines.push('→ Use `update_context_section` to share architecture, patterns, or gotchas.');
41
52
  if (result.documentation) {
42
- lines.push('\n---');
43
- lines.push('**📚 Documentation:**');
44
53
  if (result.documentation.affectedSections?.length > 0) {
45
- lines.push(`May need updates: ${result.documentation.affectedSections.join(', ')}`);
54
+ lines.push(`\nSections that may need updates: ${result.documentation.affectedSections.join(', ')}`);
46
55
  }
47
56
  if (result.documentation.reminder) {
48
57
  lines.push(result.documentation.reminder);
package/dist/index.js CHANGED
@@ -61,6 +61,10 @@ const SubtaskSchema = z.object({
61
61
  title: z.string(),
62
62
  done: z.boolean(),
63
63
  });
64
+ const CommitSchema = z.object({
65
+ hash: z.string(),
66
+ message: z.string(),
67
+ });
64
68
  const TaskDetailSchema = z.object({
65
69
  id: z.string(),
66
70
  title: z.string(),
@@ -76,6 +80,7 @@ const TaskDetailSchema = z.object({
76
80
  voteScore: z.number(),
77
81
  subtasks: z.array(SubtaskSchema).optional(),
78
82
  agentNotes: z.string().nullable().optional(),
83
+ commits: z.array(CommitSchema).optional(),
79
84
  feedback: z.array(z.object({
80
85
  id: z.string(),
81
86
  title: z.string(),
@@ -105,7 +110,8 @@ const FeedbackDetailSchema = z.object({
105
110
  server.registerTool('list_tasks', {
106
111
  title: 'List Tasks',
107
112
  description: 'Get roadmap tasks. Returns planned/in-progress by default. ' +
108
- 'Filter by type, quarter, etc.',
113
+ 'Filter by type, quarter, etc.\n\n' +
114
+ '**Recommended:** Call `get_project_context` before starting work to understand codebase patterns.',
109
115
  inputSchema: z.object({
110
116
  status: z.enum(['planned', 'in_progress', 'done', 'all']).optional(),
111
117
  type: z.enum(['bug', 'feature', 'improvement', 'task']).optional().describe('Filter by task type'),
@@ -151,15 +157,21 @@ server.registerTool('list_tasks', {
151
157
  const quarterInfo = t.quarter ? ` 📅${t.quarter}` : '';
152
158
  return `• ${t.id}: ${typeIcon} ${t.title} [${t.status}] ${p}${quarterInfo}${t.hasImplementationPlan ? ' 📋' : ''}${subtaskInfo}`;
153
159
  });
160
+ const output = [
161
+ `Tasks in "${data.project.name}":`,
162
+ lines.join('\n'),
163
+ '',
164
+ '💡 **Tip:** Run `get_project_context` first to understand codebase patterns before starting work.',
165
+ ].join('\n');
154
166
  return {
155
- content: [{ type: 'text', text: `Tasks in "${data.project.name}":\n${lines.join('\n')}` }],
167
+ content: [{ type: 'text', text: output }],
156
168
  structuredContent: { project: data.project.name, tasks: data.tasks },
157
169
  };
158
170
  });
159
171
  // Tool: Get task
160
172
  server.registerTool('get_task', {
161
173
  title: 'Get Task',
162
- description: 'Get task details including description, plan, and linked feedback.',
174
+ description: 'Get task details including description, plan, commits, and linked feedback.',
163
175
  inputSchema: z.object({
164
176
  taskId: z.string().describe('Task ID'),
165
177
  }),
@@ -202,12 +214,24 @@ server.registerTool('get_task', {
202
214
  parts.push(`\n## Subtasks (${done}/${t.subtasks.length})`);
203
215
  t.subtasks.forEach((s) => parts.push(`- [${s.done ? 'x' : ' '}] ${s.title} (id: ${s.id})`));
204
216
  }
217
+ // Show commits
218
+ if (t.commits && t.commits.length) {
219
+ parts.push(`\n## Commits (${t.commits.length})`);
220
+ t.commits.forEach((c) => parts.push(`- ${c.hash.slice(0, 7)}: ${c.message}`));
221
+ }
205
222
  if (t.agentNotes)
206
223
  parts.push(`\n## Notes\n${t.agentNotes}`);
207
224
  if (t.feedback.length) {
208
225
  parts.push(`\n## Feedback (${t.feedback.length})`);
209
226
  t.feedback.forEach((f) => parts.push(`- ${f.title} (${f.voterCount} votes)`));
210
227
  }
228
+ // Add workflow reminder for tasks not yet started
229
+ if (t.status === 'planned') {
230
+ parts.push('\n---');
231
+ parts.push('**To work on this task:**');
232
+ parts.push('1. `get_project_context` → read relevant sections');
233
+ parts.push('2. `start_task` → locks task and shows context');
234
+ }
211
235
  return {
212
236
  content: [{ type: 'text', text: parts.join('\n') }],
213
237
  structuredContent: t,
@@ -343,11 +367,14 @@ server.registerTool('start_task', {
343
367
  description: 'Lock and start a task. Fails if locked by another agent unless force=true. ' +
344
368
  'Use force=true to take over a task from another agent (e.g., if they abandoned it). ' +
345
369
  'Returns project context index with relevant sections for the task.\n\n' +
370
+ '**IMPORTANT:** After starting, use get_context_section to read relevant sections. ' +
371
+ 'Project context contains architecture and patterns you MUST follow.\n\n' +
346
372
  '**Workflow after starting:**\n' +
347
- '1. add_note: "Session started: <your goal>"\n' +
348
- '2. Do work, log commits/decisions with add_note\n' +
349
- '3. add_note: "Session end: <summary, next steps>"\n' +
350
- '4. complete_task (done) or abandon_task (stopping)',
373
+ '1. Read relevant context sections (architecture, conventions, etc.)\n' +
374
+ '2. add_note: "Session started: <your goal>"\n' +
375
+ '3. Do work, log commits with add_commit, decisions with add_note\n' +
376
+ '4. add_note: "Session end: <summary, next steps>"\n' +
377
+ '5. complete_task (done) or abandon_task (stopping)',
351
378
  inputSchema: z.object({
352
379
  taskId: z.string(),
353
380
  force: z.boolean().optional().describe('Take over lock from another agent'),
@@ -405,9 +432,9 @@ server.registerTool('add_note', {
405
432
  description: 'Add progress note to task. Notes help future agents continue your work.\n\n' +
406
433
  '**When to use:**\n' +
407
434
  '- Session start: "Session started: implementing X"\n' +
408
- '- Commits: "Committed abc123: Added validation"\n' +
409
435
  '- Decisions: "Decision: Using X because Y"\n' +
410
436
  '- Session end: "Session end: Done X, remaining Y, blockers Z"\n\n' +
437
+ '**For commits:** Use `add_commit` instead for structured commit tracking.\n\n' +
411
438
  '**Important:** Always log session end before complete_task or abandon_task.',
412
439
  inputSchema: z.object({
413
440
  taskId: z.string(),
@@ -430,6 +457,37 @@ server.registerTool('add_note', {
430
457
  structuredContent: { taskId, success: true },
431
458
  };
432
459
  });
460
+ // Tool: Add commit
461
+ server.registerTool('add_commit', {
462
+ title: 'Add Commit',
463
+ description: 'Log a commit for a task. Stores structured commit info that appears in task details.\n\n' +
464
+ '**When to use:**\n' +
465
+ '- After making a commit: log hash and message\n' +
466
+ '- When completing work: optionally pass commits to complete_task instead\n\n' +
467
+ '**Example:** After `git commit`, call this with the commit hash and message.',
468
+ inputSchema: z.object({
469
+ taskId: z.string(),
470
+ hash: z.string().describe('Commit hash (short or full)'),
471
+ message: z.string().describe('Commit message'),
472
+ }),
473
+ outputSchema: z.object({
474
+ taskId: z.string(),
475
+ hash: z.string(),
476
+ success: z.boolean(),
477
+ }),
478
+ annotations: {
479
+ readOnlyHint: false,
480
+ destructiveHint: false,
481
+ idempotentHint: false,
482
+ openWorldHint: false,
483
+ },
484
+ }, async ({ taskId, hash, message }) => {
485
+ const result = await api('POST', `/api/agent/tasks/${taskId}/commits`, { hash, message });
486
+ return {
487
+ content: [{ type: 'text', text: `📝 Commit logged: ${hash.slice(0, 7)} - ${message}` }],
488
+ structuredContent: { taskId, hash: result.hash, success: true },
489
+ };
490
+ });
433
491
  // Tool: Create subtask
434
492
  server.registerTool('create_subtask', {
435
493
  title: 'Create Subtask',
@@ -510,15 +568,20 @@ const DocumentationSchema = z.object({
510
568
  // Tool: Complete task
511
569
  server.registerTool('complete_task', {
512
570
  title: 'Complete Task',
513
- description: 'Mark task done with summary. Include commit hashes and any follow-up work.\n\n' +
571
+ description: 'Mark task done with summary. Optionally log final commits at completion.\n\n' +
514
572
  '**Before calling:**\n' +
515
573
  '1. Push all commits\n' +
516
574
  '2. add_note: "Session end: <what was done>"\n' +
517
575
  '3. Check if project context docs need updating\n\n' +
576
+ '**Commits:** Pass commits array to log them at completion (convenience for final commits).\n\n' +
518
577
  'Returns documentation update suggestions.',
519
578
  inputSchema: z.object({
520
579
  taskId: z.string(),
521
580
  summary: z.string().describe('What was implemented'),
581
+ commits: z.array(z.object({
582
+ hash: z.string().describe('Commit hash (short or full)'),
583
+ message: z.string().describe('Commit message'),
584
+ })).optional().describe('Optional: commits to log at completion'),
522
585
  }),
523
586
  outputSchema: z.object({
524
587
  id: z.string(),
@@ -531,8 +594,8 @@ server.registerTool('complete_task', {
531
594
  idempotentHint: true,
532
595
  openWorldHint: false,
533
596
  },
534
- }, async ({ taskId, summary }) => {
535
- const result = await api('POST', `/api/agent/tasks/${taskId}/complete`, { summary });
597
+ }, async ({ taskId, summary, commits }) => {
598
+ const result = await api('POST', `/api/agent/tasks/${taskId}/complete`, { summary, commits });
536
599
  return {
537
600
  content: [{ type: 'text', text: formatCompleteTaskResponse(result) }],
538
601
  structuredContent: result,
@@ -568,6 +631,65 @@ server.registerTool('abandon_task', {
568
631
  structuredContent: result,
569
632
  };
570
633
  });
634
+ // ==================== Agent Instructions ====================
635
+ // Tool: Get agent instructions
636
+ server.registerTool('get_agent_instructions', {
637
+ title: 'Get Agent Instructions',
638
+ description: 'Get the canonical Damper workflow instructions. ' +
639
+ 'Use this to set up or update CLAUDE.md in a project.',
640
+ inputSchema: z.object({
641
+ format: z.enum(['markdown', 'section']).optional()
642
+ .describe('markdown = full file, section = just the Damper section (default: section)'),
643
+ }),
644
+ outputSchema: z.object({
645
+ format: z.enum(['markdown', 'section']),
646
+ content: z.string(),
647
+ }),
648
+ annotations: {
649
+ readOnlyHint: true,
650
+ destructiveHint: false,
651
+ idempotentHint: true,
652
+ openWorldHint: false,
653
+ },
654
+ }, async ({ format = 'section' }) => {
655
+ const section = `## Task Management with Damper MCP
656
+
657
+ This project uses Damper MCP for task tracking. **You MUST follow this workflow.**
658
+
659
+ ### At Session Start (MANDATORY)
660
+ 1. \`get_project_context\` - **READ THIS FIRST.** Contains architecture, conventions, and critical project info.
661
+ 2. \`get_context_section\` - Fetch full content for sections relevant to your task
662
+ 3. \`list_tasks\` - Check for existing tasks to work on
663
+ 4. If working on a task: \`start_task\` to lock it
664
+
665
+ ### While Working
666
+ - \`add_commit\` after each commit with hash and message
667
+ - \`add_note\` for decisions: "Decision: chose X because Y"
668
+ - \`update_subtask\` to mark subtask progress
669
+ - **Follow patterns from project context** - Don't reinvent; use existing conventions
670
+
671
+ ### At Session End (MANDATORY)
672
+ - ALWAYS call \`add_note\` with session summary before stopping
673
+ - ALWAYS call \`complete_task\` (if done) or \`abandon_task\` (if stopping early)
674
+ - NEVER leave a started task without completing or abandoning it
675
+ - If you learned something about the codebase, consider updating project context
676
+
677
+ ### Why This Matters
678
+ - **Project context prevents mistakes** - Contains architecture decisions, gotchas, and patterns
679
+ - Locked tasks block other agents from working on them
680
+ - Commits and notes help the next agent continue the work
681
+ - Updating context saves future agents from re-analyzing the codebase`;
682
+ if (format === 'markdown') {
683
+ return {
684
+ content: [{ type: 'text', text: `# CLAUDE.md\n\n${section}` }],
685
+ structuredContent: { format: 'markdown', content: `# CLAUDE.md\n\n${section}` },
686
+ };
687
+ }
688
+ return {
689
+ content: [{ type: 'text', text: section }],
690
+ structuredContent: { format: 'section', content: section },
691
+ };
692
+ });
571
693
  // ==================== Context Tools ====================
572
694
  // Tool: List context sections
573
695
  server.registerTool('list_context_sections', {
@@ -786,7 +908,9 @@ server.registerTool('sync_project_context', {
786
908
  server.registerTool('get_project_context', {
787
909
  title: 'Get Project Context',
788
910
  description: 'Get project context index (token-efficient). Returns section list with previews. ' +
789
- 'Use get_context_section to fetch full content for sections you need.',
911
+ 'Use get_context_section to fetch full content for sections you need.\n\n' +
912
+ '**IMPORTANT:** Call this at session start. Contains architecture, conventions, and ' +
913
+ 'patterns you MUST follow. Skipping this leads to mistakes and inconsistent code.',
790
914
  inputSchema: z.object({
791
915
  taskId: z.string().optional().describe('If provided, highlights sections relevant to this task'),
792
916
  }),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@damper/mcp",
3
- "version": "0.3.8",
3
+ "version": "0.3.10",
4
4
  "description": "MCP server for Damper task management",
5
5
  "author": "Damper <hello@usedamper.com>",
6
6
  "repository": {