@specforge/mcp 3.3.9 → 3.5.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.
@@ -14,7 +14,7 @@
14
14
  * - Search: Search, find by file/tag, find related
15
15
  * - Git: Link commits and PRs, get linked items
16
16
  */
17
- import { ValidationError, ApiError, validateToolArgs, formatMCPError, transformError, validateTicket, filterWarningsByStrictness, } from '../validation/index.js';
17
+ import { ValidationError, ApiError, validateToolArgs, formatMCPError, transformError, } from '../validation/index.js';
18
18
  import { resolvePatternsWithCache, getPatternOverrides, flattenCodeStandards, } from '../patterns/index.js';
19
19
  import { getResponseModeFromArgs, formatWriteResponse, } from '../lib/response.js';
20
20
  import { createFeedbackHandler } from './core/feedback.js';
@@ -140,40 +140,6 @@ export function getTools() {
140
140
  required: ['projectId'],
141
141
  },
142
142
  },
143
- {
144
- name: 'get_specification',
145
- description: `Get specification with optional summary mode or full details.
146
-
147
- Use summary: true for minimal response (~70 tokens) with key fields only (id, title, status, priority, epicCount, ticketCount, completedTicketCount).
148
-
149
- Optional includes (ignored when summary=true):
150
- - 'status': Progress, ticket counts, blockers (replaces get_specification_status)
151
- - 'epics': List of epics with summary data
152
- - 'patterns': Tech stack, code patterns, naming conventions`,
153
- inputSchema: {
154
- type: 'object',
155
- properties: {
156
- specificationId: {
157
- type: 'string',
158
- description: 'The ID of the specification to retrieve',
159
- },
160
- summary: {
161
- type: 'boolean',
162
- description: 'Return minimal summary fields only (~70 tokens vs ~600 full). Ignores include parameter when true. Default: false',
163
- default: false,
164
- },
165
- include: {
166
- type: 'array',
167
- items: {
168
- type: 'string',
169
- enum: ['status', 'epics', 'patterns'],
170
- },
171
- description: 'Optional data to include in response (ignored when summary=true)',
172
- },
173
- },
174
- required: ['specificationId'],
175
- },
176
- },
177
143
  {
178
144
  name: 'lookup_specification',
179
145
  description: 'Fast specification lookup by title. Returns minimal data (id, title, status, epicCount, ticketCount) for token efficiency.',
@@ -197,7 +163,7 @@ Optional includes (ignored when summary=true):
197
163
  // ========================================================================
198
164
  {
199
165
  name: 'list_epics',
200
- description: 'List epics for a specification with optional status and field filters. Supports pagination with limit/offset. Use fields to select specific fields and reduce token usage.',
166
+ description: 'List epics for a specification with optional status and field filters. Supports pagination with limit/offset. Use fields to select specific fields and reduce token usage. During active planning sessions, field selection and result limits are automatically enforced.',
201
167
  inputSchema: {
202
168
  type: 'object',
203
169
  properties: {
@@ -251,39 +217,6 @@ Optional includes (ignored when summary=true):
251
217
  required: ['specificationId'],
252
218
  },
253
219
  },
254
- {
255
- name: 'get_epic',
256
- description: `Get epic with optional summary mode or full details.
257
-
258
- Use summary: true for minimal response (~80 tokens) with key fields only (id, epicNumber, title, status, objective, ticketCount, completedTicketCount).
259
-
260
- Optional includes (ignored when summary=true):
261
- - 'status': Progress percentage, ticket counts, active tickets (replaces get_epic_status)
262
- - 'tickets': List of tickets with summary data`,
263
- inputSchema: {
264
- type: 'object',
265
- properties: {
266
- epicId: {
267
- type: 'string',
268
- description: 'The ID of the epic to retrieve',
269
- },
270
- summary: {
271
- type: 'boolean',
272
- description: 'Return minimal summary fields only (~80 tokens vs ~400 full). Ignores include parameter when true. Default: false',
273
- default: false,
274
- },
275
- include: {
276
- type: 'array',
277
- items: {
278
- type: 'string',
279
- enum: ['status', 'tickets'],
280
- },
281
- description: 'Optional data to include in response (ignored when summary=true)',
282
- },
283
- },
284
- required: ['epicId'],
285
- },
286
- },
287
220
  {
288
221
  name: 'lookup_epic',
289
222
  description: "Fast epic lookup by number or title. Returns minimal data (id, number, title, status, ticketCount). Use 'number' for exact match, 'title' for partial match.",
@@ -311,7 +244,7 @@ Optional includes (ignored when summary=true):
311
244
  // ========================================================================
312
245
  {
313
246
  name: 'list_tickets',
314
- description: 'List tickets for an epic with optional status and field filters. Supports pagination with limit/offset. Use fields to select specific fields and reduce token usage. Use include: ["statusReason"] to get reasons why pending tickets are blocked.',
247
+ description: 'List tickets for an epic with optional status and field filters. Supports pagination with limit/offset. Use fields to select specific fields and reduce token usage. Use include: ["statusReason"] to get reasons why pending tickets are blocked. During active planning sessions, field selection and result limits are automatically enforced.',
315
248
  inputSchema: {
316
249
  type: 'object',
317
250
  properties: {
@@ -382,44 +315,6 @@ Optional includes (ignored when summary=true):
382
315
  required: ['epicId'],
383
316
  },
384
317
  },
385
- {
386
- name: 'get_ticket',
387
- description: `Get ticket with optional summary mode or full details.
388
-
389
- Use summary: true for minimal response (~100 tokens) with key fields only (id, ticketNumber, title, status, complexity, estimatedHours, priority).
390
-
391
- For full details, statusReason is auto-included for pending tickets explaining why the ticket is blocked.
392
-
393
- Optional includes (ignored when summary=true):
394
- - 'dependencies': Tickets this blocks and is blocked by (replaces get_ticket_dependencies)
395
- - 'testStatus': Test results and history (replaces get_ticket_test_status)
396
- - 'commits': Linked git commits (replaces get_ticket_commits)
397
- - 'prs': Linked pull requests (replaces get_ticket_prs)
398
- - 'statusReason': Why ticket is pending (auto-included for pending tickets)`,
399
- inputSchema: {
400
- type: 'object',
401
- properties: {
402
- ticketId: {
403
- type: 'string',
404
- description: 'The ID of the ticket to retrieve',
405
- },
406
- summary: {
407
- type: 'boolean',
408
- description: 'Return minimal summary fields only (~100 tokens vs ~500 full). Ignores include parameter when true. Default: false',
409
- default: false,
410
- },
411
- include: {
412
- type: 'array',
413
- items: {
414
- type: 'string',
415
- enum: ['dependencies', 'testStatus', 'commits', 'prs', 'statusReason'],
416
- },
417
- description: 'Additional data to include (ignored when summary=true). statusReason is auto-included for pending tickets.',
418
- },
419
- },
420
- required: ['ticketId'],
421
- },
422
- },
423
318
  {
424
319
  name: 'lookup_ticket',
425
320
  description: "Fast ticket lookup by number or title. Returns minimal data (id, number, title, status, complexity). Use 'number' for exact match, 'title' for partial match.",
@@ -459,90 +354,6 @@ Optional includes (ignored when summary=true):
459
354
  },
460
355
  },
461
356
  // ========================================================================
462
- // Core Operations - Dependencies (Epic 3)
463
- // ========================================================================
464
- {
465
- name: 'add_dependency',
466
- description: 'Add a dependency between two tickets. The first ticket will depend on the second.',
467
- inputSchema: {
468
- type: 'object',
469
- properties: {
470
- ticketId: {
471
- type: 'string',
472
- description: 'The ID of the ticket that will depend on another',
473
- },
474
- dependsOnId: {
475
- type: 'string',
476
- description: 'The ID of the ticket it will depend on',
477
- },
478
- type: {
479
- type: 'string',
480
- enum: ['blocks', 'requires'],
481
- description: "Type of dependency (default: 'requires')",
482
- },
483
- },
484
- required: ['ticketId', 'dependsOnId'],
485
- },
486
- },
487
- {
488
- name: 'remove_dependency',
489
- description: 'Remove a dependency between two tickets',
490
- inputSchema: {
491
- type: 'object',
492
- properties: {
493
- ticketId: {
494
- type: 'string',
495
- description: 'The ID of the dependent ticket',
496
- },
497
- dependsOnId: {
498
- type: 'string',
499
- description: 'The ID of the ticket it depends on',
500
- },
501
- dependencyId: {
502
- type: 'string',
503
- description: 'Alternative: Direct ID of the dependency record',
504
- },
505
- },
506
- },
507
- },
508
- {
509
- name: 'get_dependency_tree',
510
- description: 'Get the full dependency tree for a specification, showing all tickets and their dependency relationships',
511
- inputSchema: {
512
- type: 'object',
513
- properties: {
514
- specificationId: {
515
- type: 'string',
516
- description: 'The ID of the specification',
517
- },
518
- },
519
- required: ['specificationId'],
520
- },
521
- },
522
- {
523
- name: 'check_circular_dependencies',
524
- description: `Check for circular dependencies between tickets in a specification.
525
-
526
- Returns any cycles found where tickets depend on each other in a loop (e.g., A→B→C→A).
527
-
528
- Examples:
529
- - check_circular_dependencies specificationId="spec-123"
530
- - check_circular_dependencies projectId="proj-123" // Check all specs in project`,
531
- inputSchema: {
532
- type: 'object',
533
- properties: {
534
- specificationId: {
535
- type: 'string',
536
- description: 'Specification ID to check (optional if projectId provided)',
537
- },
538
- projectId: {
539
- type: 'string',
540
- description: 'Project ID to check all specifications (optional if specificationId provided)',
541
- },
542
- },
543
- },
544
- },
545
- // ========================================================================
546
357
  // Context & AI Tools (Epic 4)
547
358
  // ========================================================================
548
359
  {
@@ -600,20 +411,6 @@ Examples:
600
411
  required: ['specificationId'],
601
412
  },
602
413
  },
603
- {
604
- name: 'get_critical_path',
605
- description: 'Get the critical path (longest dependency chain) for a specification',
606
- inputSchema: {
607
- type: 'object',
608
- properties: {
609
- specificationId: {
610
- type: 'string',
611
- description: 'The ID of the specification',
612
- },
613
- },
614
- required: ['specificationId'],
615
- },
616
- },
617
414
  {
618
415
  name: 'get_patterns',
619
416
  description: 'Get patterns for a specification or ticket with full inheritance chain. When ticketId is provided, returns resolved patterns with spec → epic → ticket inheritance.',
@@ -636,7 +433,7 @@ Examples:
636
433
  // ========================================================================
637
434
  {
638
435
  name: 'start_work_session',
639
- description: 'Start working on a ticket. Creates a WorkSession record and transitions ready -> active. Returns the workSessionId along with error with statusReason if ticket is pending (dependencies not met).',
436
+ description: 'Start working on a ticket. Returns full ticket details (description, implementation steps, AC, technicalDetails, codeReferences, typeReferences, tags, notes, complexity, priority) alongside checklistState and workSessionId. No need to call get_ticket separately. Returns error with statusReason if ticket is pending.',
640
437
  inputSchema: {
641
438
  type: 'object',
642
439
  properties: {
@@ -763,7 +560,9 @@ Use this instead of calling update_ticket for checklist changes. Provides:
763
560
  - Auto-calculated progress percentage
764
561
  - Completion readiness hints
765
562
 
766
- IMPORTANT: All acceptance criteria must be validated and all implementation steps must be completed via this tool before calling complete_work_session. The completion gate enforces this.`,
563
+ IMPORTANT: All acceptance criteria must be validated and all implementation steps must be completed via this tool before calling complete_work_session. The completion gate enforces this.
564
+
565
+ Set getTicket: true to fetch full ticket details in the response — useful for re-reading ticket context mid-implementation. Can be the sole operation or combined with other actions.`,
767
566
  inputSchema: {
768
567
  type: 'object',
769
568
  properties: {
@@ -888,6 +687,10 @@ IMPORTANT: All acceptance criteria must be validated and all implementation step
888
687
  type: 'boolean',
889
688
  description: 'Clear existing blocker and resume work.',
890
689
  },
690
+ getTicket: {
691
+ type: 'boolean',
692
+ description: 'Fetch full ticket details. Can be the sole operation or combined with other actions.',
693
+ },
891
694
  },
892
695
  required: ['ticketId'],
893
696
  },
@@ -952,7 +755,7 @@ Combines:
952
755
  - Status, complexity, priority filters
953
756
 
954
757
  At least one of: query, files, tags, or relatedTo is required.
955
- At least one scope filter (projectId, specificationId, or epicId) is required.`,
758
+ At least one scope filter (projectId, specificationId, or epicId) is required. During active planning sessions, prefer lookup_ticket for targeted lookups.`,
956
759
  inputSchema: {
957
760
  type: 'object',
958
761
  properties: {
@@ -1129,7 +932,7 @@ At least one scope filter (projectId, specificationId, or epicId) is required.`,
1129
932
  // ========================================================================
1130
933
  {
1131
934
  name: 'create_specification',
1132
- description: 'Create a new specification with full context. Create epics separately using epic.create for better quality.',
935
+ description: 'Create a new specification with full context. Create epics separately using epic.create for better quality. After creation, use start_planning_session to begin structured planning.',
1133
936
  inputSchema: {
1134
937
  type: 'object',
1135
938
  properties: {
@@ -1293,659 +1096,45 @@ At least one scope filter (projectId, specificationId, or epicId) is required.`,
1293
1096
  },
1294
1097
  },
1295
1098
  {
1296
- name: 'create_epic',
1297
- description: 'Create a new epic in a specification with full context. Create tickets separately using ticket.create for better quality.',
1099
+ name: 'import_specification',
1100
+ description: 'Import a markdown file as a complete specification with AI-powered parsing. Parses epics from ## headers and tickets from ### headers.',
1298
1101
  inputSchema: {
1299
1102
  type: 'object',
1300
1103
  properties: {
1301
- specificationId: {
1302
- type: 'string',
1303
- description: 'The ID of the specification',
1304
- },
1305
- title: {
1306
- type: 'string',
1307
- description: 'Epic title',
1308
- },
1309
- description: {
1310
- type: 'string',
1311
- description: 'Detailed description',
1312
- },
1313
- objective: {
1104
+ projectId: {
1314
1105
  type: 'string',
1315
- description: 'What this epic achieves',
1316
- },
1317
- epicNumber: {
1318
- type: 'number',
1319
- description: 'Epic number (auto-incremented if not provided)',
1106
+ description: 'The ID of the project to import into',
1320
1107
  },
1321
1108
  content: {
1322
1109
  type: 'string',
1323
- description: 'Full epic content (markdown)',
1324
- },
1325
- scope: {
1326
- type: 'string',
1327
- description: "What's in/out of scope for this epic",
1328
- },
1329
- goals: {
1330
- type: 'array',
1331
- items: { type: 'string' },
1332
- description: 'Epic-specific goals',
1333
- },
1334
- guardrails: {
1335
- type: 'array',
1336
- items: { type: 'string' },
1337
- description: 'What NOT to do for this epic',
1338
- },
1339
- risks: {
1340
- type: 'array',
1341
- items: { type: 'string' },
1342
- description: 'Risk factors for this epic',
1343
- },
1344
- constraints: {
1345
- type: 'array',
1346
- items: { type: 'string' },
1347
- description: 'Technical or business constraints for this epic',
1348
- },
1349
- assumptions: {
1350
- type: 'array',
1351
- items: { type: 'string' },
1352
- description: 'Key assumptions made for this epic',
1353
- },
1354
- architecture: {
1355
- type: 'string',
1356
- description: 'Architectural approach for this epic',
1357
- },
1358
- fileStructure: {
1359
- type: 'string',
1360
- description: 'File/folder organization for this epic',
1361
- },
1362
- techStack: {
1363
- type: 'array',
1364
- items: { type: 'string' },
1365
- description: 'Technologies used (subset of specification)',
1366
- },
1367
- dependencies: {
1368
- type: 'array',
1369
- items: { type: 'string' },
1370
- description: 'Required packages/libraries',
1371
- },
1372
- apiContracts: {
1373
- type: 'object',
1374
- description: 'API specifications for this epic',
1375
- },
1376
- acceptanceCriteria: {
1377
- type: 'array',
1378
- items: { type: 'string' },
1379
- description: 'Epic-level success criteria',
1110
+ description: 'Raw markdown content to parse and import',
1380
1111
  },
1381
- priority: {
1112
+ title: {
1382
1113
  type: 'string',
1383
- enum: ['high', 'medium', 'low'],
1384
- description: 'Priority level',
1385
- },
1386
- tags: {
1387
- type: 'array',
1388
- items: { type: 'string' },
1389
- description: 'Categorization tags',
1390
- },
1391
- estimatedHours: {
1392
- type: 'number',
1393
- description: 'Total estimated hours for epic',
1394
- },
1395
- // Pattern inheritance fields (epic level)
1396
- sharedPatterns: {
1397
- type: 'object',
1398
- description: 'Patterns shared by all tickets in this epic',
1399
- properties: {
1400
- errorHandling: { type: 'string', description: 'Override error handling for this epic' },
1401
- returnType: { type: 'string', description: 'Epic-specific return type' },
1402
- actionPrefix: { type: 'string', description: 'Redux/action prefix for this epic' },
1403
- stateSlice: { type: 'string', description: 'State slice path for this epic' },
1404
- },
1405
- },
1406
- additionalImports: {
1407
- type: 'array',
1408
- items: { type: 'string' },
1409
- description: 'Additional imports for tickets in this epic (added to spec-level imports)',
1410
- },
1411
- commonFiles: {
1412
- type: 'object',
1413
- description: 'Common file paths for this epic',
1414
- properties: {
1415
- reducer: { type: 'string', description: 'Reducer file path' },
1416
- actions: { type: 'string', description: 'Actions file path' },
1417
- types: { type: 'string', description: 'Types file path' },
1418
- index: { type: 'string', description: 'Index/barrel file path' },
1419
- },
1114
+ description: 'Override the parsed title (optional)',
1420
1115
  },
1421
- responseMode: {
1116
+ specificationTypeId: {
1422
1117
  type: 'string',
1423
- enum: ['full', 'minimal', 'id-only'],
1424
- description: 'Response verbosity: full (default, ~500 tokens), minimal (~50 tokens), id-only (~20 tokens)',
1118
+ description: 'Specification type ID (uses default if not provided)',
1425
1119
  },
1426
1120
  },
1427
- required: ['specificationId', 'title', 'description', 'objective'],
1121
+ required: ['projectId', 'content'],
1428
1122
  },
1429
1123
  },
1124
+ // ========================================================================
1125
+ // Implementation Session Operations
1126
+ // ========================================================================
1430
1127
  {
1431
- name: 'create_ticket',
1432
- description: 'Create a new ticket in an epic. Returns validation warnings based on complexity level.',
1128
+ name: 'start_implementation_session',
1129
+ description: 'Start an implementation session for a specification. An implementation session is for autonomous multi-ticket implementation, tracking completed/failed/skipped tickets. This is different from a work session (session.start) which is for working on a single ticket. Returns actionable and blocked tickets.',
1433
1130
  inputSchema: {
1434
1131
  type: 'object',
1435
1132
  properties: {
1436
- epicId: {
1437
- type: 'string',
1438
- description: 'The ID of the epic',
1439
- },
1440
- title: {
1441
- type: 'string',
1442
- description: 'Ticket title',
1443
- },
1444
- ticketNumber: {
1445
- type: 'number',
1446
- description: 'Ticket number (auto-incremented if not provided)',
1447
- },
1448
- description: {
1133
+ specificationId: {
1449
1134
  type: 'string',
1450
- description: 'Ticket description',
1451
- },
1452
- implementation: {
1453
- type: 'object',
1454
- description: 'Detailed implementation steps (JSON)',
1135
+ description: 'The ID of the specification to create a session for',
1455
1136
  },
1456
- technicalDetails: {
1457
- type: 'object',
1458
- description: 'Technical details like stack, endpoints (JSON)',
1459
- },
1460
- acceptanceCriteria: {
1461
- type: 'array',
1462
- items: { type: 'string' },
1463
- description: 'Success criteria',
1464
- },
1465
- priority: {
1466
- type: 'string',
1467
- enum: ['high', 'medium', 'low'],
1468
- description: 'Priority level',
1469
- },
1470
- complexity: {
1471
- type: 'string',
1472
- enum: ['small', 'medium', 'large', 'xlarge'],
1473
- description: 'Size/complexity indicator',
1474
- },
1475
- tags: {
1476
- type: 'array',
1477
- items: { type: 'string' },
1478
- description: 'Categorization tags',
1479
- },
1480
- notes: {
1481
- type: 'string',
1482
- description: 'Additional context, warnings, or considerations',
1483
- },
1484
- estimatedHours: {
1485
- type: 'number',
1486
- description: 'Estimated effort in hours',
1487
- },
1488
- dependsOn: {
1489
- type: 'array',
1490
- items: { type: 'string' },
1491
- description: 'Array of ticket IDs this ticket depends on',
1492
- },
1493
- validationStrictness: {
1494
- type: 'string',
1495
- enum: ['lenient', 'normal', 'strict'],
1496
- description: 'Warning strictness level. lenient=warnings only, normal=warnings+recommendations, strict=all. Default: normal',
1497
- },
1498
- responseMode: {
1499
- type: 'string',
1500
- enum: ['full', 'minimal', 'id-only'],
1501
- description: 'Response verbosity: full (default, ~500 tokens), minimal (~50 tokens), id-only (~20 tokens)',
1502
- },
1503
- },
1504
- required: ['epicId', 'title'],
1505
- },
1506
- },
1507
- {
1508
- name: 'import_specification',
1509
- description: 'Import a markdown file as a complete specification with AI-powered parsing. Parses epics from ## headers and tickets from ### headers.',
1510
- inputSchema: {
1511
- type: 'object',
1512
- properties: {
1513
- projectId: {
1514
- type: 'string',
1515
- description: 'The ID of the project to import into',
1516
- },
1517
- content: {
1518
- type: 'string',
1519
- description: 'Raw markdown content to parse and import',
1520
- },
1521
- title: {
1522
- type: 'string',
1523
- description: 'Override the parsed title (optional)',
1524
- },
1525
- specificationTypeId: {
1526
- type: 'string',
1527
- description: 'Specification type ID (uses default if not provided)',
1528
- },
1529
- },
1530
- required: ['projectId', 'content'],
1531
- },
1532
- },
1533
- // ========================================================================
1534
- // Update Operations
1535
- // ========================================================================
1536
- {
1537
- name: 'update_ticket',
1538
- description: "Update a ticket's properties (status, description, estimate, etc.).\n\n" +
1539
- 'When status changes, counts are automatically propagated up the hierarchy ' +
1540
- '(Epic → Specification → Project).',
1541
- inputSchema: {
1542
- type: 'object',
1543
- properties: {
1544
- ticketId: {
1545
- type: 'string',
1546
- description: 'The ID of the ticket to update',
1547
- },
1548
- title: {
1549
- type: 'string',
1550
- description: 'New title (optional)',
1551
- },
1552
- description: {
1553
- type: 'string',
1554
- description: 'New description (optional)',
1555
- },
1556
- status: {
1557
- type: 'string',
1558
- enum: ['pending', 'ready', 'active', 'done'],
1559
- description: 'Ticket status. pending/ready may be recalculated based on dependencies.',
1560
- },
1561
- priority: {
1562
- type: 'string',
1563
- enum: ['low', 'medium', 'high', 'critical'],
1564
- description: 'Priority level (optional)',
1565
- },
1566
- complexity: {
1567
- type: 'string',
1568
- enum: ['small', 'medium', 'large', 'xlarge'],
1569
- description: 'Size/complexity indicator (optional)',
1570
- },
1571
- blockReason: {
1572
- type: 'string',
1573
- description: 'External block reason. Forces status to pending until cleared.',
1574
- },
1575
- notes: {
1576
- type: 'string',
1577
- description: 'Additional context, warnings, or considerations (optional)',
1578
- },
1579
- estimatedHours: {
1580
- type: 'number',
1581
- description: 'Estimated hours (optional)',
1582
- },
1583
- tags: {
1584
- type: 'array',
1585
- items: { type: 'string' },
1586
- description: 'Tags (optional)',
1587
- },
1588
- acceptanceCriteria: {
1589
- type: 'array',
1590
- items: { type: 'string' },
1591
- description: 'Acceptance criteria (optional)',
1592
- },
1593
- implementation: {
1594
- type: 'object',
1595
- description: 'Detailed implementation steps (JSON) (optional)',
1596
- },
1597
- technicalDetails: {
1598
- type: 'object',
1599
- description: 'Technical details like stack, endpoints (JSON) (optional)',
1600
- },
1601
- validationStrictness: {
1602
- type: 'string',
1603
- enum: ['lenient', 'normal', 'strict'],
1604
- description: 'Warning strictness level (default: normal)',
1605
- default: 'normal',
1606
- },
1607
- responseMode: {
1608
- type: 'string',
1609
- enum: ['full', 'minimal', 'id-only'],
1610
- description: 'Response verbosity: full (default, ~500 tokens), minimal (~50 tokens), id-only (~20 tokens)',
1611
- },
1612
- },
1613
- required: ['ticketId'],
1614
- },
1615
- },
1616
- {
1617
- name: 'update_epic',
1618
- description: "Update an epic's properties",
1619
- inputSchema: {
1620
- type: 'object',
1621
- properties: {
1622
- epicId: {
1623
- type: 'string',
1624
- description: 'The ID of the epic to update',
1625
- },
1626
- title: {
1627
- type: 'string',
1628
- description: 'New title (optional)',
1629
- },
1630
- description: {
1631
- type: 'string',
1632
- description: 'New description (optional)',
1633
- },
1634
- status: {
1635
- type: 'string',
1636
- enum: ['todo', 'in_progress', 'completed'],
1637
- description: 'New status (optional)',
1638
- },
1639
- objective: {
1640
- type: 'string',
1641
- description: 'New objective (optional)',
1642
- },
1643
- scope: {
1644
- type: 'string',
1645
- description: 'What\'s in/out of scope (optional)',
1646
- },
1647
- goals: {
1648
- type: 'array',
1649
- items: { type: 'string' },
1650
- description: 'Epic-specific goals (optional)',
1651
- },
1652
- guardrails: {
1653
- type: 'array',
1654
- items: { type: 'string' },
1655
- description: 'What NOT to do (optional)',
1656
- },
1657
- risks: {
1658
- type: 'array',
1659
- items: { type: 'string' },
1660
- description: 'Risk factors (optional)',
1661
- },
1662
- constraints: {
1663
- type: 'array',
1664
- items: { type: 'string' },
1665
- description: 'Technical/business constraints (optional)',
1666
- },
1667
- assumptions: {
1668
- type: 'array',
1669
- items: { type: 'string' },
1670
- description: 'Key assumptions (optional)',
1671
- },
1672
- architecture: {
1673
- type: 'string',
1674
- description: 'Architectural approach (optional)',
1675
- },
1676
- fileStructure: {
1677
- type: 'string',
1678
- description: 'File/folder organization (optional)',
1679
- },
1680
- techStack: {
1681
- type: 'array',
1682
- items: { type: 'string' },
1683
- description: 'Technologies used (optional)',
1684
- },
1685
- dependencies: {
1686
- type: 'array',
1687
- items: { type: 'string' },
1688
- description: 'Required packages/libraries (optional)',
1689
- },
1690
- apiContracts: {
1691
- type: 'object',
1692
- description: 'API specifications (optional)',
1693
- },
1694
- acceptanceCriteria: {
1695
- type: 'array',
1696
- items: { type: 'string' },
1697
- description: 'Success criteria (optional)',
1698
- },
1699
- tags: {
1700
- type: 'array',
1701
- items: { type: 'string' },
1702
- description: 'Categorization tags (optional)',
1703
- },
1704
- estimatedHours: {
1705
- type: 'number',
1706
- description: 'Total estimated hours (optional)',
1707
- },
1708
- priority: {
1709
- type: 'string',
1710
- enum: ['low', 'medium', 'high', 'critical'],
1711
- description: 'Priority level (optional)',
1712
- },
1713
- // Pattern inheritance fields (epic level)
1714
- sharedPatterns: {
1715
- type: 'object',
1716
- description: 'Patterns shared by all tickets in this epic (optional)',
1717
- properties: {
1718
- errorHandling: { type: 'string', description: 'Override error handling for this epic' },
1719
- returnType: { type: 'string', description: 'Epic-specific return type' },
1720
- actionPrefix: { type: 'string', description: 'Redux/action prefix for this epic' },
1721
- stateSlice: { type: 'string', description: 'State slice path for this epic' },
1722
- },
1723
- },
1724
- additionalImports: {
1725
- type: 'array',
1726
- items: { type: 'string' },
1727
- description: 'Additional imports for tickets in this epic (optional)',
1728
- },
1729
- commonFiles: {
1730
- type: 'object',
1731
- description: 'Common file paths for this epic (optional)',
1732
- properties: {
1733
- reducer: { type: 'string', description: 'Reducer file path' },
1734
- actions: { type: 'string', description: 'Actions file path' },
1735
- types: { type: 'string', description: 'Types file path' },
1736
- index: { type: 'string', description: 'Index/barrel file path' },
1737
- },
1738
- },
1739
- responseMode: {
1740
- type: 'string',
1741
- enum: ['full', 'minimal', 'id-only'],
1742
- description: 'Response verbosity: full (default, ~500 tokens), minimal (~50 tokens), id-only (~20 tokens)',
1743
- },
1744
- },
1745
- required: ['epicId'],
1746
- },
1747
- },
1748
- {
1749
- name: 'update_specification',
1750
- description: "Update a specification's properties",
1751
- inputSchema: {
1752
- type: 'object',
1753
- properties: {
1754
- specificationId: {
1755
- type: 'string',
1756
- description: 'The ID of the specification to update',
1757
- },
1758
- title: {
1759
- type: 'string',
1760
- description: 'New title (optional)',
1761
- },
1762
- description: {
1763
- type: 'string',
1764
- description: 'New description (optional)',
1765
- },
1766
- status: {
1767
- type: 'string',
1768
- enum: ['draft', 'planning', 'ready', 'in_progress', 'completed'],
1769
- description: 'New status (optional)',
1770
- },
1771
- background: {
1772
- type: 'string',
1773
- description: 'New background (optional)',
1774
- },
1775
- scope: {
1776
- type: 'string',
1777
- description: 'New scope (optional)',
1778
- },
1779
- goals: {
1780
- type: 'array',
1781
- items: { type: 'string' },
1782
- description: 'Business/user/technical objectives (optional)',
1783
- },
1784
- requirements: {
1785
- type: 'array',
1786
- items: { type: 'string' },
1787
- description: 'Functional requirements (optional)',
1788
- },
1789
- nonFunctionalRequirements: {
1790
- type: 'array',
1791
- items: { type: 'string' },
1792
- description: 'Non-functional requirements like performance, security (optional)',
1793
- },
1794
- successMetrics: {
1795
- type: 'array',
1796
- items: { type: 'string' },
1797
- description: 'KPIs to measure success (optional)',
1798
- },
1799
- constraints: {
1800
- type: 'array',
1801
- items: { type: 'string' },
1802
- description: 'Technical/business constraints (optional)',
1803
- },
1804
- assumptions: {
1805
- type: 'array',
1806
- items: { type: 'string' },
1807
- description: 'Key assumptions made (optional)',
1808
- },
1809
- risks: {
1810
- type: 'array',
1811
- items: { type: 'string' },
1812
- description: 'Risk factors and mitigations (optional)',
1813
- },
1814
- guardrails: {
1815
- type: 'array',
1816
- items: { type: 'string' },
1817
- description: 'What NOT to do (optional)',
1818
- },
1819
- architecture: {
1820
- type: 'string',
1821
- description: 'Architectural approach (optional)',
1822
- },
1823
- fileStructure: {
1824
- type: 'string',
1825
- description: 'File/folder organization (optional)',
1826
- },
1827
- techStack: {
1828
- type: 'array',
1829
- items: { type: 'string' },
1830
- description: 'Technologies to use (optional)',
1831
- },
1832
- dependencies: {
1833
- type: 'array',
1834
- items: { type: 'string' },
1835
- description: 'Required packages/libraries (optional)',
1836
- },
1837
- apiContracts: {
1838
- type: 'object',
1839
- description: 'API specifications (optional)',
1840
- },
1841
- acceptanceCriteria: {
1842
- type: 'array',
1843
- items: { type: 'string' },
1844
- description: 'Success criteria (optional)',
1845
- },
1846
- tags: {
1847
- type: 'array',
1848
- items: { type: 'string' },
1849
- description: 'Categorization tags (optional)',
1850
- },
1851
- estimatedHours: {
1852
- type: 'number',
1853
- description: 'Total estimated hours (optional)',
1854
- },
1855
- targetAudience: {
1856
- type: 'string',
1857
- description: 'Who this is for - developers, users, stakeholders, etc. (optional)',
1858
- },
1859
- priority: {
1860
- type: 'string',
1861
- enum: ['low', 'medium', 'high', 'critical'],
1862
- description: 'Priority level (optional)',
1863
- },
1864
- validationCommands: {
1865
- type: 'object',
1866
- description: 'Validation commands (test, lint, build, typeCheck, custom) (optional)',
1867
- properties: {
1868
- test: { type: 'string', description: 'Test command' },
1869
- lint: { type: 'string', description: 'Lint command' },
1870
- build: { type: 'string', description: 'Build command' },
1871
- typeCheck: { type: 'string', description: 'Type check command' },
1872
- preValidation: { type: 'string', description: 'Pre-validation command' },
1873
- postValidation: { type: 'string', description: 'Post-validation command' },
1874
- custom: {
1875
- type: 'object',
1876
- description: 'Custom validation commands',
1877
- additionalProperties: { type: 'string' },
1878
- },
1879
- },
1880
- },
1881
- workingDirectory: {
1882
- type: 'string',
1883
- description: 'Working directory for commands (optional)',
1884
- },
1885
- outputDirectory: {
1886
- type: 'string',
1887
- description: 'Output directory for build artifacts (optional)',
1888
- },
1889
- // Pattern inheritance fields (specification level)
1890
- codeStandards: {
1891
- type: 'object',
1892
- description: 'Code standards inherited by all epics/tickets (optional)',
1893
- properties: {
1894
- language: { type: 'string', description: 'Primary language (e.g., "TypeScript")' },
1895
- asyncPattern: { type: 'string', description: 'Async pattern (e.g., "async/await")' },
1896
- errorHandling: { type: 'string', description: 'Error handling approach' },
1897
- documentation: { type: 'string', description: 'Documentation style' },
1898
- testing: { type: 'string', description: 'Testing approach' },
1899
- naming: {
1900
- type: 'object',
1901
- description: 'Naming conventions',
1902
- properties: {
1903
- files: { type: 'string', description: 'File naming convention' },
1904
- functions: { type: 'string', description: 'Function naming convention' },
1905
- interfaces: { type: 'string', description: 'Interface naming convention' },
1906
- actions: { type: 'string', description: 'Action naming convention' },
1907
- },
1908
- },
1909
- },
1910
- },
1911
- commonImports: {
1912
- type: 'array',
1913
- items: { type: 'string' },
1914
- description: 'Common imports inherited by all epics/tickets (optional)',
1915
- },
1916
- returnTypes: {
1917
- type: 'object',
1918
- description: 'Standard return types for CRUD operations (optional)',
1919
- properties: {
1920
- create: { type: 'string', description: 'Return type for create operations' },
1921
- update: { type: 'string', description: 'Return type for update operations' },
1922
- delete: { type: 'string', description: 'Return type for delete operations' },
1923
- list: { type: 'string', description: 'Return type for list operations' },
1924
- },
1925
- },
1926
- responseMode: {
1927
- type: 'string',
1928
- enum: ['full', 'minimal', 'id-only'],
1929
- description: 'Response verbosity: full (default, ~500 tokens), minimal (~50 tokens), id-only (~20 tokens)',
1930
- },
1931
- },
1932
- required: ['specificationId'],
1933
- },
1934
- },
1935
- // ========================================================================
1936
- // Implementation Session Operations
1937
- // ========================================================================
1938
- {
1939
- name: 'start_implementation_session',
1940
- description: 'Start an implementation session for a specification. An implementation session is for autonomous multi-ticket implementation, tracking completed/failed/skipped tickets. This is different from a work session (session.start) which is for working on a single ticket. Returns actionable and blocked tickets.',
1941
- inputSchema: {
1942
- type: 'object',
1943
- properties: {
1944
- specificationId: {
1945
- type: 'string',
1946
- description: 'The ID of the specification to create a session for',
1947
- },
1948
- config: {
1137
+ config: {
1949
1138
  type: 'object',
1950
1139
  description: 'Optional session configuration',
1951
1140
  properties: {
@@ -2008,51 +1197,6 @@ At least one scope filter (projectId, specificationId, or epicId) is required.`,
2008
1197
  required: ['sessionId', 'status'],
2009
1198
  },
2010
1199
  },
2011
- // ========================================================================
2012
- // Bulk Operations
2013
- // ========================================================================
2014
- {
2015
- name: 'bulk_add_dependencies',
2016
- description: 'Add multiple dependencies between tickets in a single atomic transaction.',
2017
- inputSchema: {
2018
- type: 'object',
2019
- properties: {
2020
- dependencies: {
2021
- type: 'array',
2022
- description: 'Array of dependency definitions',
2023
- items: {
2024
- type: 'object',
2025
- properties: {
2026
- ticketId: {
2027
- type: 'string',
2028
- description: 'ID of the ticket that will depend on another',
2029
- },
2030
- dependsOnId: {
2031
- type: 'string',
2032
- description: 'ID of the ticket it will depend on',
2033
- },
2034
- type: {
2035
- type: 'string',
2036
- enum: ['blocks', 'requires'],
2037
- description: "Type of dependency (default: 'requires')",
2038
- },
2039
- },
2040
- required: ['ticketId', 'dependsOnId'],
2041
- },
2042
- },
2043
- skipCircularCheck: {
2044
- type: 'boolean',
2045
- description: 'Skip validation of circular dependencies (default: false)',
2046
- },
2047
- onError: {
2048
- type: 'string',
2049
- enum: ['rollback', 'continue'],
2050
- description: "Error handling mode: 'rollback' stops and undoes all, 'continue' skips failures (default: 'continue')",
2051
- },
2052
- },
2053
- required: ['dependencies'],
2054
- },
2055
- },
2056
1200
  {
2057
1201
  name: 'bulk_update_tickets',
2058
1202
  description: 'Update multiple tickets in a single atomic operation. All updates succeed or all fail (unless atomic: false).',
@@ -2450,34 +1594,6 @@ At least one scope filter (projectId, specificationId, or epicId) is required.`,
2450
1594
  // ========================================================================
2451
1595
  // Delete Operations
2452
1596
  // ========================================================================
2453
- {
2454
- name: 'delete_ticket',
2455
- description: 'Delete a ticket and all its related records (dependencies, test results, discoveries, blueprint references)',
2456
- inputSchema: {
2457
- type: 'object',
2458
- properties: {
2459
- ticketId: {
2460
- type: 'string',
2461
- description: 'The ID of the ticket to delete',
2462
- },
2463
- },
2464
- required: ['ticketId'],
2465
- },
2466
- },
2467
- {
2468
- name: 'delete_epic',
2469
- description: 'Delete an epic and cascade delete all its tickets and related records',
2470
- inputSchema: {
2471
- type: 'object',
2472
- properties: {
2473
- epicId: {
2474
- type: 'string',
2475
- description: 'The ID of the epic to delete',
2476
- },
2477
- },
2478
- required: ['epicId'],
2479
- },
2480
- },
2481
1597
  {
2482
1598
  name: 'delete_specification',
2483
1599
  description: 'Delete a specification and cascade delete all epics, tickets, and related records',
@@ -2571,50 +1687,42 @@ At least one scope filter (projectId, specificationId, or epicId) is required.`,
2571
1687
  // Review & Completion
2572
1688
  // ========================================================================
2573
1689
  {
2574
- name: 'review_planning',
2575
- description: 'Review the planning quality of a specification. Analyzes ticket completeness, dependency structure, estimation coverage, and acceptance criteria. Returns a detailed report with scores and actionable suggestions.',
1690
+ name: 'review_implementation',
1691
+ description: 'Review the implementation progress and quality of a specification. Analyzes completed tickets, test coverage, code quality signals, and remaining work. Returns a progress report with recommendations.',
2576
1692
  inputSchema: {
2577
1693
  type: 'object',
2578
1694
  properties: {
2579
1695
  specificationId: {
2580
1696
  type: 'string',
2581
- description: 'The ID of the specification to review',
2582
- },
2583
- page: {
2584
- type: 'integer',
2585
- description: 'Page number for paginated results (default: 1)',
2586
- },
2587
- pageSize: {
2588
- type: 'integer',
2589
- description: 'Number of items per page (default: 20)',
1697
+ description: 'The ID of the specification to review',
2590
1698
  },
2591
1699
  },
2592
1700
  required: ['specificationId'],
2593
1701
  },
2594
1702
  },
2595
1703
  {
2596
- name: 'review_implementation',
2597
- description: 'Review the implementation progress and quality of a specification. Analyzes completed tickets, test coverage, code quality signals, and remaining work. Returns a progress report with recommendations.',
1704
+ name: 'complete_specification',
1705
+ description: 'Mark a specification as complete. Validates that all epics and tickets are done, calculates final metrics, and transitions the specification to completed status. Use review_implementation first to check readiness.',
2598
1706
  inputSchema: {
2599
1707
  type: 'object',
2600
1708
  properties: {
2601
1709
  specificationId: {
2602
1710
  type: 'string',
2603
- description: 'The ID of the specification to review',
1711
+ description: 'The ID of the specification to complete',
2604
1712
  },
2605
1713
  },
2606
1714
  required: ['specificationId'],
2607
1715
  },
2608
1716
  },
2609
1717
  {
2610
- name: 'complete_specification',
2611
- description: 'Mark a specification as complete. Validates that all epics and tickets are done, calculates final metrics, and transitions the specification to completed status. Use review_implementation first to check readiness.',
1718
+ name: 'reopen_specification',
1719
+ description: 'Reopen a specification in "ready" status, regressing to "planning". After reopening, call start_planning_session to begin a new planning session.',
2612
1720
  inputSchema: {
2613
1721
  type: 'object',
2614
1722
  properties: {
2615
1723
  specificationId: {
2616
1724
  type: 'string',
2617
- description: 'The ID of the specification to complete',
1725
+ description: 'The ID of the specification to reopen',
2618
1726
  },
2619
1727
  },
2620
1728
  required: ['specificationId'],
@@ -2640,6 +1748,83 @@ At least one scope filter (projectId, specificationId, or epicId) is required.`,
2640
1748
  },
2641
1749
  },
2642
1750
  },
1751
+ // ========================================================================
1752
+ // Planning Session Operations
1753
+ // ========================================================================
1754
+ {
1755
+ name: 'start_planning_session',
1756
+ description: 'Start or resume a guided planning session for a specification. Auto-detects the current state — whether the spec is new, partially complete, or needs refinement after review. Returns current status, progress scores, blockers, and suggested next actions. Always call this before using action_planning_session.',
1757
+ inputSchema: {
1758
+ type: 'object',
1759
+ properties: {
1760
+ specificationId: {
1761
+ type: 'string',
1762
+ description: 'The ID of the specification to plan',
1763
+ },
1764
+ },
1765
+ required: ['specificationId'],
1766
+ },
1767
+ },
1768
+ {
1769
+ name: 'action_planning_session',
1770
+ description: "Execute a planning action within an active session. Wraps all planning operations (create/update epics, tickets, dependencies, blueprints) and read operations (get_ticket for inspecting details) with automatic status tracking. The spec status advances or regresses automatically based on the action type and gate checks. Returns updated progress, blockers, and next suggested actions after every call. Use responseDetail to control verbosity: 'minimal' (~80 tokens) for rapid iteration, 'standard' (~200 tokens, default) for normal work, 'full' (~500 tokens) for debugging.",
1771
+ inputSchema: {
1772
+ type: 'object',
1773
+ properties: {
1774
+ specificationId: {
1775
+ type: 'string',
1776
+ description: 'The ID of the specification',
1777
+ },
1778
+ operation: {
1779
+ type: 'object',
1780
+ description: 'The operation to perform. Must include a "type" field.',
1781
+ properties: {
1782
+ type: {
1783
+ type: 'string',
1784
+ enum: [
1785
+ 'set_metadata',
1786
+ 'create_epic',
1787
+ 'update_epic',
1788
+ 'create_ticket',
1789
+ 'update_ticket',
1790
+ 'delete_epic',
1791
+ 'delete_ticket',
1792
+ 'add_dependencies',
1793
+ 'remove_dependency',
1794
+ 'create_blueprint',
1795
+ 'link_blueprint',
1796
+ 'get_ticket',
1797
+ 'advance_phase',
1798
+ 'get_status',
1799
+ ],
1800
+ description: 'The type of planning operation to perform',
1801
+ },
1802
+ },
1803
+ required: ['type'],
1804
+ },
1805
+ responseDetail: {
1806
+ type: 'string',
1807
+ enum: ['minimal', 'standard', 'full'],
1808
+ description: 'Response detail level: minimal (~80 tokens), standard (~200, default), full (~500)',
1809
+ },
1810
+ },
1811
+ required: ['specificationId', 'operation'],
1812
+ },
1813
+ },
1814
+ {
1815
+ name: 'complete_planning_session',
1816
+ description: "Complete the planning session and submit the spec for final review. Spec must be in 'validating' status. Runs a dry-run check first, then full review if no errors. Transitions spec to 'ready' on success. If the spec isn't in validating yet, returns what's needed to get there.",
1817
+ inputSchema: {
1818
+ type: 'object',
1819
+ properties: {
1820
+ specificationId: {
1821
+ type: 'string',
1822
+ description: 'The ID of the specification to complete planning for',
1823
+ },
1824
+ },
1825
+ required: ['specificationId'],
1826
+ },
1827
+ },
2643
1828
  ];
2644
1829
  return tools;
2645
1830
  }
@@ -2750,14 +1935,6 @@ export function createToolHandlers(apiClient) {
2750
1935
  fields: argsWithContext.fields,
2751
1936
  });
2752
1937
  },
2753
- get_specification: async (_client, args) => {
2754
- validateRequired(args, 'specificationId');
2755
- return await apiClient.call('get_specification', {
2756
- specificationId: args.specificationId,
2757
- summary: args.summary,
2758
- include: args.include,
2759
- });
2760
- },
2761
1938
  lookup_specification: async (_client, args) => {
2762
1939
  validateRequired(args, 'title');
2763
1940
  // Inject projectId from .specforge.json if not provided
@@ -2782,14 +1959,6 @@ export function createToolHandlers(apiClient) {
2782
1959
  fields: argsWithContext.fields,
2783
1960
  });
2784
1961
  },
2785
- get_epic: async (_client, args) => {
2786
- validateRequired(args, 'epicId');
2787
- return await apiClient.call('get_epic', {
2788
- epicId: args.epicId,
2789
- summary: args.summary,
2790
- include: args.include,
2791
- });
2792
- },
2793
1962
  lookup_epic: async (_client, args) => {
2794
1963
  // Must provide either title or number
2795
1964
  if (!args.title && args.number === undefined) {
@@ -2821,14 +1990,6 @@ export function createToolHandlers(apiClient) {
2821
1990
  fields: argsWithContext.fields,
2822
1991
  });
2823
1992
  },
2824
- get_ticket: async (_client, args) => {
2825
- validateRequired(args, 'ticketId');
2826
- return await apiClient.call('get_ticket', {
2827
- ticketId: args.ticketId,
2828
- summary: args.summary,
2829
- include: args.include,
2830
- });
2831
- },
2832
1993
  lookup_ticket: async (_client, args) => {
2833
1994
  validateRequired(args, 'epicId');
2834
1995
  // Must provide either title or number
@@ -2866,42 +2027,6 @@ export function createToolHandlers(apiClient) {
2866
2027
  });
2867
2028
  },
2868
2029
  // ========================================================================
2869
- // Core Operations - Dependencies
2870
- // ========================================================================
2871
- add_dependency: async (_client, args) => {
2872
- validateRequired(args, 'ticketId');
2873
- validateRequired(args, 'dependsOnId');
2874
- return await apiClient.call('add_dependency', {
2875
- ticketId: args.ticketId,
2876
- dependsOnId: args.dependsOnId,
2877
- type: args.type,
2878
- });
2879
- },
2880
- remove_dependency: async (_client, args) => {
2881
- // Either dependencyId or (ticketId + dependsOnId) required
2882
- if (!args.dependencyId && !args.ticketId) {
2883
- throw new Error('Either dependencyId or ticketId is required');
2884
- }
2885
- return await apiClient.call('remove_dependency', {
2886
- ticketId: args.ticketId,
2887
- dependsOnId: args.dependsOnId,
2888
- dependencyId: args.dependencyId,
2889
- });
2890
- },
2891
- get_dependency_tree: async (_client, args) => {
2892
- validateRequired(args, 'specificationId');
2893
- return await apiClient.call('get_dependency_tree', {
2894
- specificationId: args.specificationId,
2895
- });
2896
- },
2897
- check_circular_dependencies: async (_client, args) => {
2898
- const argsWithContext = injectContext(args, ['specificationId', 'projectId']);
2899
- return await apiClient.call('check_circular_dependencies', {
2900
- specificationId: argsWithContext.specificationId,
2901
- projectId: argsWithContext.projectId,
2902
- });
2903
- },
2904
- // ========================================================================
2905
2030
  // Context & AI Tools
2906
2031
  // ========================================================================
2907
2032
  get_implementation_context: async (_client, args) => {
@@ -2976,16 +2101,6 @@ export function createToolHandlers(apiClient) {
2976
2101
  specificationId: argsWithContext.specificationId,
2977
2102
  });
2978
2103
  },
2979
- get_critical_path: async (_client, args) => {
2980
- // Inject specificationId from .specforge.json if not provided
2981
- const argsWithContext = injectContext(args, ['specificationId']);
2982
- if (!argsWithContext.specificationId) {
2983
- throw new Error('specificationId is required. Set working context with "specforge switch" or provide explicitly.');
2984
- }
2985
- return await apiClient.call('get_critical_path', {
2986
- specificationId: argsWithContext.specificationId,
2987
- });
2988
- },
2989
2104
  get_patterns: async (_client, args) => {
2990
2105
  // Inject specificationId from .specforge.json if not provided
2991
2106
  const argsWithContext = injectContext(args, ['specificationId']);
@@ -3162,6 +2277,7 @@ export function createToolHandlers(apiClient) {
3162
2277
  filesDeleted: args.filesDeleted,
3163
2278
  blockReason: args.blockReason,
3164
2279
  clearBlockReason: args.clearBlockReason,
2280
+ getTicket: args.getTicket,
3165
2281
  });
3166
2282
  },
3167
2283
  // ========================================================================
@@ -3276,79 +2392,6 @@ export function createToolHandlers(apiClient) {
3276
2392
  });
3277
2393
  return formatWriteResponse(result, responseMode, 'Specification created');
3278
2394
  },
3279
- create_epic: async (_client, args) => {
3280
- validateRequired(args, 'specificationId', 'title', 'description', 'objective');
3281
- const responseMode = getResponseModeFromArgs(args);
3282
- const result = await apiClient.call('create_epic', {
3283
- specificationId: args.specificationId,
3284
- title: args.title,
3285
- description: args.description,
3286
- objective: args.objective,
3287
- epicNumber: args.epicNumber,
3288
- content: args.content,
3289
- scope: args.scope,
3290
- goals: args.goals,
3291
- acceptanceCriteria: args.acceptanceCriteria,
3292
- priority: args.priority,
3293
- tags: args.tags,
3294
- estimatedHours: args.estimatedHours,
3295
- order: args.order,
3296
- // FI-003 fields
3297
- guardrails: args.guardrails,
3298
- risks: args.risks,
3299
- constraints: args.constraints,
3300
- assumptions: args.assumptions,
3301
- architecture: args.architecture,
3302
- fileStructure: args.fileStructure,
3303
- techStack: args.techStack,
3304
- dependencies: args.dependencies,
3305
- apiContracts: args.apiContracts,
3306
- // Pattern inheritance fields (F7-002)
3307
- sharedPatterns: args.sharedPatterns,
3308
- additionalImports: args.additionalImports,
3309
- commonFiles: args.commonFiles,
3310
- });
3311
- return formatWriteResponse(result, responseMode, 'Epic created');
3312
- },
3313
- create_ticket: async (_client, args) => {
3314
- validateRequired(args, 'epicId', 'title');
3315
- const responseMode = getResponseModeFromArgs(args);
3316
- // Extract validation options
3317
- const validationStrictness = args.validationStrictness === 'lenient' || args.validationStrictness === 'strict'
3318
- ? args.validationStrictness
3319
- : 'normal';
3320
- // Create the ticket
3321
- const result = await apiClient.call('create_ticket', {
3322
- epicId: args.epicId,
3323
- title: args.title,
3324
- ticketNumber: args.ticketNumber,
3325
- description: args.description,
3326
- implementation: args.implementation,
3327
- technicalDetails: args.technicalDetails,
3328
- acceptanceCriteria: args.acceptanceCriteria,
3329
- priority: args.priority,
3330
- complexity: args.complexity,
3331
- tags: args.tags,
3332
- estimatedHours: args.estimatedHours,
3333
- order: args.order,
3334
- dependsOn: args.dependsOn,
3335
- notes: args.notes, // F8-001: Add missing notes field
3336
- });
3337
- // Run validation
3338
- const validation = validateTicket({
3339
- complexity: args.complexity,
3340
- implementation: args.implementation,
3341
- technicalDetails: args.technicalDetails,
3342
- notes: args.notes,
3343
- acceptanceCriteria: args.acceptanceCriteria,
3344
- });
3345
- // Filter warnings by strictness level
3346
- const warnings = filterWarningsByStrictness(validation.warnings, validationStrictness);
3347
- // Add validation results to response
3348
- result.warnings = warnings;
3349
- result.completenessScore = validation.completenessScore;
3350
- return formatWriteResponse(result, responseMode, 'Ticket created');
3351
- },
3352
2395
  import_specification: async (_client, args) => {
3353
2396
  validateRequired(args, 'projectId', 'content');
3354
2397
  return await apiClient.call('import_specification', {
@@ -3359,145 +2402,6 @@ export function createToolHandlers(apiClient) {
3359
2402
  });
3360
2403
  },
3361
2404
  // ========================================================================
3362
- // Update Operations
3363
- // ========================================================================
3364
- update_ticket: async (_client, args) => {
3365
- validateRequired(args, 'ticketId');
3366
- const responseMode = getResponseModeFromArgs(args);
3367
- // Extract validation options
3368
- const validationStrictness = args.validationStrictness === 'lenient' || args.validationStrictness === 'strict'
3369
- ? args.validationStrictness
3370
- : 'normal';
3371
- // Get current ticket to calculate previous completeness score
3372
- let previousCompletenessScore;
3373
- try {
3374
- const currentTicket = await apiClient.call('get_ticket', {
3375
- ticketId: args.ticketId,
3376
- });
3377
- // Calculate previous completeness score
3378
- const prevValidation = validateTicket({
3379
- complexity: currentTicket.complexity,
3380
- implementation: currentTicket.implementation,
3381
- technicalDetails: currentTicket.technicalDetails,
3382
- notes: currentTicket.notes,
3383
- acceptanceCriteria: currentTicket.acceptanceCriteria,
3384
- });
3385
- previousCompletenessScore = prevValidation.completenessScore;
3386
- }
3387
- catch {
3388
- // If we can't get the current ticket, skip previous score tracking
3389
- previousCompletenessScore = undefined;
3390
- }
3391
- // Update the ticket
3392
- const result = await apiClient.call('update_ticket', {
3393
- ticketId: args.ticketId,
3394
- title: args.title,
3395
- description: args.description,
3396
- status: args.status,
3397
- priority: args.priority,
3398
- estimatedHours: args.estimatedHours,
3399
- tags: args.tags,
3400
- acceptanceCriteria: args.acceptanceCriteria,
3401
- // Additional fields
3402
- complexity: args.complexity,
3403
- notes: args.notes,
3404
- implementation: args.implementation,
3405
- technicalDetails: args.technicalDetails,
3406
- blockReason: args.blockReason,
3407
- });
3408
- // Run validation on updated ticket
3409
- // Use the updated values (from args) merged with existing values (from result)
3410
- // The result should contain the final state after update
3411
- const validation = validateTicket({
3412
- complexity: (args.complexity || result.complexity),
3413
- implementation: (args.implementation || result.implementation),
3414
- technicalDetails: (args.technicalDetails || result.technicalDetails),
3415
- notes: (args.notes || result.notes),
3416
- acceptanceCriteria: (args.acceptanceCriteria || result.acceptanceCriteria),
3417
- });
3418
- // Filter warnings by strictness level
3419
- const warnings = filterWarningsByStrictness(validation.warnings, validationStrictness);
3420
- // Add validation results to response
3421
- result.warnings = warnings;
3422
- result.completenessScore = validation.completenessScore;
3423
- if (previousCompletenessScore !== undefined) {
3424
- result.previousCompletenessScore = previousCompletenessScore;
3425
- }
3426
- return formatWriteResponse(result, responseMode, 'Ticket updated');
3427
- },
3428
- update_epic: async (_client, args) => {
3429
- validateRequired(args, 'epicId');
3430
- const responseMode = getResponseModeFromArgs(args);
3431
- const result = await apiClient.call('update_epic', {
3432
- epicId: args.epicId,
3433
- title: args.title,
3434
- description: args.description,
3435
- status: args.status,
3436
- objective: args.objective,
3437
- priority: args.priority,
3438
- // FI-003 fields
3439
- scope: args.scope,
3440
- goals: args.goals,
3441
- guardrails: args.guardrails,
3442
- risks: args.risks,
3443
- constraints: args.constraints,
3444
- assumptions: args.assumptions,
3445
- architecture: args.architecture,
3446
- fileStructure: args.fileStructure,
3447
- techStack: args.techStack,
3448
- dependencies: args.dependencies,
3449
- apiContracts: args.apiContracts,
3450
- acceptanceCriteria: args.acceptanceCriteria,
3451
- tags: args.tags,
3452
- estimatedHours: args.estimatedHours,
3453
- // Pattern inheritance fields (F7-002)
3454
- sharedPatterns: args.sharedPatterns,
3455
- additionalImports: args.additionalImports,
3456
- commonFiles: args.commonFiles,
3457
- });
3458
- return formatWriteResponse(result, responseMode, 'Epic updated');
3459
- },
3460
- update_specification: async (_client, args) => {
3461
- validateRequired(args, 'specificationId');
3462
- const responseMode = getResponseModeFromArgs(args);
3463
- const result = await apiClient.call('update_specification', {
3464
- specificationId: args.specificationId,
3465
- title: args.title,
3466
- description: args.description,
3467
- status: args.status,
3468
- background: args.background,
3469
- scope: args.scope,
3470
- priority: args.priority,
3471
- // FI-003 fields
3472
- goals: args.goals,
3473
- requirements: args.requirements,
3474
- nonFunctionalRequirements: args.nonFunctionalRequirements,
3475
- successMetrics: args.successMetrics,
3476
- constraints: args.constraints,
3477
- assumptions: args.assumptions,
3478
- risks: args.risks,
3479
- guardrails: args.guardrails,
3480
- architecture: args.architecture,
3481
- fileStructure: args.fileStructure,
3482
- techStack: args.techStack,
3483
- dependencies: args.dependencies,
3484
- apiContracts: args.apiContracts,
3485
- acceptanceCriteria: args.acceptanceCriteria,
3486
- tags: args.tags,
3487
- estimatedHours: args.estimatedHours,
3488
- targetAudience: args.targetAudience,
3489
- // Pattern inheritance fields (F7-001)
3490
- codeStandards: args.codeStandards,
3491
- commonImports: args.commonImports,
3492
- returnTypes: args.returnTypes,
3493
- // Validation and workflow fields
3494
- validationCommands: args.validationCommands,
3495
- workingDirectory: args.workingDirectory,
3496
- outputDirectory: args.outputDirectory,
3497
- });
3498
- return formatWriteResponse(result, responseMode, 'Specification updated');
3499
- },
3500
- // ========================================================================
3501
2405
  // Implementation Session Operations
3502
2406
  // ========================================================================
3503
2407
  start_implementation_session: async (_client, args) => {
@@ -3516,33 +2420,6 @@ export function createToolHandlers(apiClient) {
3516
2420
  summary: args.summary,
3517
2421
  });
3518
2422
  },
3519
- // ========================================================================
3520
- // Bulk Operations
3521
- // ========================================================================
3522
- bulk_add_dependencies: async (_client, args) => {
3523
- validateRequired(args, 'dependencies');
3524
- if (!Array.isArray(args.dependencies) || args.dependencies.length === 0) {
3525
- throw new Error('dependencies array is required and must not be empty');
3526
- }
3527
- // Validate each dependency has required fields
3528
- const deps = args.dependencies;
3529
- for (let i = 0; i < deps.length; i++) {
3530
- if (!deps[i].ticketId || typeof deps[i].ticketId !== 'string') {
3531
- throw new Error(`dependencies[${i}].ticketId is required`);
3532
- }
3533
- if (!deps[i].dependsOnId || typeof deps[i].dependsOnId !== 'string') {
3534
- throw new Error(`dependencies[${i}].dependsOnId is required`);
3535
- }
3536
- if (deps[i].ticketId === deps[i].dependsOnId) {
3537
- throw new Error(`dependencies[${i}]: ticket cannot depend on itself`);
3538
- }
3539
- }
3540
- return await apiClient.call('bulk_add_dependencies', {
3541
- dependencies: args.dependencies,
3542
- skipCircularCheck: args.skipCircularCheck,
3543
- onError: args.onError,
3544
- });
3545
- },
3546
2423
  bulk_update_tickets: async (_client, args) => {
3547
2424
  if (!args.updates || !Array.isArray(args.updates) || args.updates.length === 0) {
3548
2425
  throw new Error('updates array is required and must not be empty');
@@ -3672,18 +2549,6 @@ export function createToolHandlers(apiClient) {
3672
2549
  // ========================================================================
3673
2550
  // Delete Operations
3674
2551
  // ========================================================================
3675
- delete_ticket: async (_client, args) => {
3676
- validateRequired(args, 'ticketId');
3677
- return await apiClient.call('delete_ticket', {
3678
- ticketId: args.ticketId,
3679
- });
3680
- },
3681
- delete_epic: async (_client, args) => {
3682
- validateRequired(args, 'epicId');
3683
- return await apiClient.call('delete_epic', {
3684
- epicId: args.epicId,
3685
- });
3686
- },
3687
2552
  delete_specification: async (_client, args) => {
3688
2553
  validateRequired(args, 'specificationId');
3689
2554
  return await apiClient.call('delete_specification', {
@@ -3733,14 +2598,6 @@ export function createToolHandlers(apiClient) {
3733
2598
  // ========================================================================
3734
2599
  // Review & Completion
3735
2600
  // ========================================================================
3736
- review_planning: async (_client, args) => {
3737
- const argsWithContext = injectContextRequired(args, ['specificationId']);
3738
- return await apiClient.call('review_planning', {
3739
- specificationId: argsWithContext.specificationId,
3740
- page: argsWithContext.page,
3741
- pageSize: argsWithContext.pageSize,
3742
- });
3743
- },
3744
2601
  review_implementation: async (_client, args) => {
3745
2602
  const argsWithContext = injectContextRequired(args, ['specificationId']);
3746
2603
  return await apiClient.call('review_implementation', {
@@ -3753,12 +2610,44 @@ export function createToolHandlers(apiClient) {
3753
2610
  specificationId: argsWithContext.specificationId,
3754
2611
  });
3755
2612
  },
2613
+ reopen_specification: async (_client, args) => {
2614
+ const argsWithContext = injectContextRequired(args, ['specificationId']);
2615
+ return await apiClient.call('reopen_specification', {
2616
+ specificationId: argsWithContext.specificationId,
2617
+ });
2618
+ },
3756
2619
  // ========================================================================
3757
2620
  // Agent Teams - Workspace Files (Local-only)
3758
2621
  // ========================================================================
3759
2622
  get_workspace_files: async (_client, args) => {
3760
2623
  return await getWorkspaceFiles(args);
3761
2624
  },
2625
+ // ========================================================================
2626
+ // Planning Session Operations
2627
+ // ========================================================================
2628
+ start_planning_session: async (_client, args) => {
2629
+ validateRequired(args, 'specificationId');
2630
+ return await apiClient.call('start_planning_session', {
2631
+ specificationId: args.specificationId,
2632
+ });
2633
+ },
2634
+ action_planning_session: async (_client, args) => {
2635
+ validateRequired(args, 'specificationId');
2636
+ if (!args.operation || typeof args.operation !== 'object') {
2637
+ throw new Error('Missing required argument: operation');
2638
+ }
2639
+ return await apiClient.call('action_planning_session', {
2640
+ specificationId: args.specificationId,
2641
+ operation: args.operation,
2642
+ responseDetail: args.responseDetail,
2643
+ });
2644
+ },
2645
+ complete_planning_session: async (_client, args) => {
2646
+ validateRequired(args, 'specificationId');
2647
+ return await apiClient.call('complete_planning_session', {
2648
+ specificationId: args.specificationId,
2649
+ });
2650
+ },
3762
2651
  };
3763
2652
  }
3764
2653
  /**