@artyfacts/claude 1.3.24 → 1.3.26

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/src/context.ts CHANGED
@@ -1,7 +1,8 @@
1
1
  /**
2
2
  * Context fetcher for Artyfacts tasks
3
3
  *
4
- * Fetches full context including organization, project, artifact, and related sections.
4
+ * Fetches full context including organization, project, goal, and related tasks.
5
+ * Updated for Schema v2 - tasks are first-class entities linked to goals.
5
6
  */
6
7
 
7
8
  // ============================================================================
@@ -20,6 +21,19 @@ export interface ProjectContext {
20
21
  description?: string;
21
22
  }
22
23
 
24
+ /**
25
+ * Related task summary (v2)
26
+ */
27
+ export interface RelatedTaskContext {
28
+ id: string;
29
+ title: string;
30
+ status: 'pending' | 'in_progress' | 'blocked' | 'done';
31
+ priority?: 'low' | 'medium' | 'high';
32
+ }
33
+
34
+ /**
35
+ * Section context (kept for artifact content)
36
+ */
23
37
  export interface SectionContext {
24
38
  id: string;
25
39
  heading: string;
@@ -28,27 +42,54 @@ export interface SectionContext {
28
42
  task_status?: string;
29
43
  }
30
44
 
31
- export interface ArtifactContext {
45
+ /**
46
+ * Goal context (v2 - replaces artifact context for task work)
47
+ */
48
+ export interface GoalContext {
32
49
  id: string;
33
50
  title: string;
51
+ objective?: string;
34
52
  summary?: string;
35
53
  description?: string;
36
54
  artifact_type?: string;
37
- sections: SectionContext[];
55
+ /** Related tasks on this goal */
56
+ tasks?: RelatedTaskContext[];
57
+ /** Legacy: sections for content-based artifacts */
58
+ sections?: SectionContext[];
38
59
  }
39
60
 
61
+ /** @deprecated Use GoalContext instead */
62
+ export interface ArtifactContext extends GoalContext {}
63
+
64
+ /**
65
+ * Full task context (v2)
66
+ */
40
67
  export interface TaskFullContext {
41
68
  task: {
69
+ /** Task UUID */
42
70
  id: string;
43
- heading: string;
44
- content: string;
71
+ /** Task title */
72
+ title: string;
73
+ /** @deprecated Use title instead */
74
+ heading?: string;
75
+ /** Task description */
76
+ description?: string;
77
+ /** @deprecated Use description instead */
78
+ content?: string;
79
+ /** Expected output format and requirements */
45
80
  expected_output?: {
46
81
  format?: string;
47
82
  requirements?: string[];
48
83
  };
49
- priority?: number;
84
+ /** Priority level */
85
+ priority?: 'low' | 'medium' | 'high';
86
+ /** Dependencies */
87
+ depends_on?: string[];
50
88
  };
51
- artifact: ArtifactContext;
89
+ /** The goal this task belongs to */
90
+ goal: GoalContext;
91
+ /** @deprecated Use goal instead */
92
+ artifact?: GoalContext;
52
93
  project?: ProjectContext;
53
94
  organization: OrganizationContext;
54
95
  }
@@ -98,7 +139,7 @@ export class ContextFetcher {
98
139
  // ============================================================================
99
140
 
100
141
  /**
101
- * Build a rich prompt with full context
142
+ * Build a rich prompt with full context (v2)
102
143
  */
103
144
  export function buildPromptWithContext(context: TaskFullContext): string {
104
145
  const parts: string[] = [];
@@ -115,12 +156,13 @@ You have access to Artyfacts MCP tools. USE THEM to complete your task:
115
156
  - **create_artifact** - Create new artifacts (documents, specs, reports)
116
157
  - **create_section** - Add sections to artifacts (content, tasks, decisions)
117
158
  - **update_section** - Update existing sections
118
- - **create_agent** - Create new AI agents with specific roles
119
- - **list_artifacts** - Query existing artifacts
120
- - **list_sections** - Query sections within an artifact
121
- - **complete_task** - Mark a task as complete
159
+ - **create_task** - Create new tasks under a goal
160
+ - **claim_task** - Claim a task for execution
161
+ - **complete_task** - Mark a task as complete (returns unblocked tasks)
122
162
  - **block_task** - Block a task with a reason
123
- - **create_blocker** - Create a decision blocker
163
+ - **list_tasks** - Query tasks from the queue
164
+ - **list_inbox** - Check pending decisions/approvals
165
+ - **resolve_inbox** - Resolve an inbox item
124
166
 
125
167
  IMPORTANT: When asked to create agents or update artifacts, USE THE TOOLS. Don't just describe what you would do - actually do it with the tools.
126
168
 
@@ -129,7 +171,7 @@ IMPORTANT: When asked to create agents or update artifacts, USE THE TOOLS. Don't
129
171
  - Be thorough but concise
130
172
  - USE THE TOOLS to take action, don't just analyze
131
173
  - If the task requires creating something, use create_artifact or create_section
132
- - If the task requires creating agents, use create_agent
174
+ - If you complete a task, check the response for unblocked_tasks to see follow-up work
133
175
  - If you cannot complete the task, explain why
134
176
 
135
177
  Format your response as follows:
@@ -159,47 +201,81 @@ Format your response as follows:
159
201
  parts.push('');
160
202
  }
161
203
 
162
- // Artifact context
163
- parts.push(`## Artifact: ${context.artifact.title}`);
164
- if (context.artifact.summary) {
165
- parts.push(context.artifact.summary);
166
- }
167
- if (context.artifact.description) {
204
+ // Goal context (v2 - was artifact)
205
+ const goal = context.goal || context.artifact;
206
+ if (goal) {
207
+ parts.push(`## Goal: ${goal.title}`);
208
+ if (goal.objective) {
209
+ parts.push(`**Objective:** ${goal.objective}`);
210
+ }
211
+ if (goal.summary) {
212
+ parts.push(goal.summary);
213
+ }
214
+ if (goal.description) {
215
+ parts.push('');
216
+ parts.push(goal.description);
217
+ }
168
218
  parts.push('');
169
- parts.push(context.artifact.description);
170
- }
171
- parts.push('');
172
219
 
173
- // Related sections (non-task sections for context, or other tasks for awareness)
174
- const relatedSections = context.artifact.sections.filter(
175
- s => s.id !== context.task.id
176
- );
177
-
178
- if (relatedSections.length > 0) {
179
- parts.push('### Related Sections:');
180
- for (const section of relatedSections) {
181
- const preview = section.content
182
- ? section.content.substring(0, 200) + (section.content.length > 200 ? '...' : '')
183
- : 'No content';
184
- const statusBadge = section.task_status ? ` [${section.task_status}]` : '';
185
- parts.push(`- **${section.heading}**${statusBadge}: ${preview}`);
220
+ // Related tasks on this goal (v2)
221
+ if (goal.tasks && goal.tasks.length > 0) {
222
+ const relatedTasks = goal.tasks.filter(t => t.id !== context.task.id);
223
+ if (relatedTasks.length > 0) {
224
+ parts.push('### Related Tasks:');
225
+ for (const task of relatedTasks) {
226
+ const statusEmoji = {
227
+ pending: '⏳',
228
+ in_progress: '🔄',
229
+ blocked: '🚫',
230
+ done: '',
231
+ }[task.status] || '';
232
+ const priorityBadge = task.priority ? ` [${task.priority}]` : '';
233
+ parts.push(`- ${statusEmoji} **${task.title}**${priorityBadge}`);
234
+ }
235
+ parts.push('');
236
+ }
237
+ }
238
+
239
+ // Legacy: related sections (for content-based artifacts)
240
+ if (goal.sections && goal.sections.length > 0) {
241
+ const relatedSections = goal.sections.filter(s => s.id !== context.task.id);
242
+ if (relatedSections.length > 0) {
243
+ parts.push('### Related Sections:');
244
+ for (const section of relatedSections) {
245
+ const preview = section.content
246
+ ? section.content.substring(0, 200) + (section.content.length > 200 ? '...' : '')
247
+ : 'No content';
248
+ const statusBadge = section.task_status ? ` [${section.task_status}]` : '';
249
+ parts.push(`- **${section.heading}**${statusBadge}: ${preview}`);
250
+ }
251
+ parts.push('');
252
+ }
186
253
  }
187
- parts.push('');
188
254
  }
189
255
 
190
256
  // The task itself
191
257
  parts.push('---');
192
258
  parts.push('');
193
- parts.push(`## Your Task: ${context.task.heading}`);
259
+ const taskTitle = context.task.title || context.task.heading;
260
+ parts.push(`## Your Task: ${taskTitle}`);
194
261
 
195
262
  if (context.task.priority) {
196
- const priorityLabels = ['🔴 High', '🟡 Medium', '🟢 Low'];
197
- parts.push(`**Priority:** ${priorityLabels[context.task.priority - 1] || 'Medium'}`);
263
+ const priorityEmoji = {
264
+ high: '🔴 High',
265
+ medium: '🟡 Medium',
266
+ low: '🟢 Low',
267
+ }[context.task.priority] || '🟡 Medium';
268
+ parts.push(`**Priority:** ${priorityEmoji}`);
269
+ }
270
+
271
+ if (context.task.depends_on && context.task.depends_on.length > 0) {
272
+ parts.push(`**Dependencies:** ${context.task.depends_on.length} task(s)`);
198
273
  }
199
274
  parts.push('');
200
275
 
201
276
  parts.push('### Description');
202
- parts.push(context.task.content || 'No additional description provided.');
277
+ const taskDescription = context.task.description || context.task.content;
278
+ parts.push(taskDescription || 'No additional description provided.');
203
279
  parts.push('');
204
280
 
205
281
  // Expected output
package/src/executor.ts CHANGED
@@ -15,19 +15,32 @@ import { ContextFetcher, createContextFetcher, buildPromptWithContext, TaskFullC
15
15
  // Types
16
16
  // ============================================================================
17
17
 
18
+ /**
19
+ * Task context for execution (v2)
20
+ */
18
21
  export interface TaskContext {
19
- /** Task ID (section ID) */
20
- taskId: string;
21
- /** Task heading/title */
22
- heading: string;
23
- /** Task content/description */
24
- content: string;
25
- /** Parent artifact ID */
26
- artifactId: string;
27
- /** Parent artifact title */
22
+ /** Task UUID */
23
+ id: string;
24
+ /** @deprecated Use id instead */
25
+ taskId?: string;
26
+ /** Task title */
27
+ title: string;
28
+ /** @deprecated Use title instead */
29
+ heading?: string;
30
+ /** Task description */
31
+ description?: string;
32
+ /** @deprecated Use description instead */
33
+ content?: string;
34
+ /** Goal UUID this task belongs to */
35
+ goalId: string;
36
+ /** @deprecated Use goalId instead */
37
+ artifactId?: string;
38
+ /** Goal title for context */
39
+ goalTitle?: string;
40
+ /** @deprecated Use goalTitle instead */
28
41
  artifactTitle?: string;
29
- /** Task priority (1=high, 2=medium, 3=low) */
30
- priority?: number;
42
+ /** Task priority */
43
+ priority?: 'low' | 'medium' | 'high';
31
44
  /** Additional context */
32
45
  context?: Record<string, unknown>;
33
46
  }
@@ -138,9 +151,14 @@ export class ClaudeExecutor {
138
151
 
139
152
  if (useFullContext) {
140
153
  try {
141
- fullContext = await this.contextFetcher!.fetchTaskContext(task.taskId);
154
+ // v2: use id, fallback to taskId for backwards compatibility
155
+ const taskId = task.id || task.taskId;
156
+ if (!taskId) {
157
+ throw new Error('Task ID required for context fetch');
158
+ }
159
+ fullContext = await this.contextFetcher!.fetchTaskContext(taskId);
142
160
  prompt = buildPromptWithContext(fullContext);
143
- console.log(' 📚 Using full context (org, project, artifact, related sections)');
161
+ console.log(' 📚 Using full context (org, project, goal, related tasks)');
144
162
  } catch (contextError) {
145
163
  console.warn(' ⚠️ Could not fetch full context, using minimal prompt');
146
164
  console.warn(` ${contextError instanceof Error ? contextError.message : contextError}`);
@@ -153,8 +171,9 @@ export class ClaudeExecutor {
153
171
  // Execute via Claude Code CLI
154
172
  const output = await this.runClaude(prompt);
155
173
 
156
- // Extract summary if present
157
- const { content, summary } = this.parseResponse(output, task.heading);
174
+ // Extract summary if present (v2: use title, fallback to heading)
175
+ const taskTitle = task.title || task.heading || 'Task';
176
+ const { content, summary } = this.parseResponse(output, taskTitle);
158
177
 
159
178
  return {
160
179
  success: true,
@@ -247,7 +266,7 @@ export class ClaudeExecutor {
247
266
  }
248
267
 
249
268
  /**
250
- * Build the task prompt
269
+ * Build the task prompt (v2)
251
270
  */
252
271
  private buildTaskPrompt(task: TaskContext): string {
253
272
  const parts: string[] = [];
@@ -262,25 +281,32 @@ export class ClaudeExecutor {
262
281
  parts.push('---');
263
282
  parts.push('');
264
283
 
265
- // Task header
266
- parts.push(`# Task: ${task.heading}`);
284
+ // Task header (v2: use title, fallback to heading)
285
+ const taskTitle = task.title || task.heading;
286
+ parts.push(`# Task: ${taskTitle}`);
267
287
  parts.push('');
268
288
 
269
- // Artifact context
270
- if (task.artifactTitle) {
271
- parts.push(`**Artifact:** ${task.artifactTitle}`);
289
+ // Goal context (v2: was artifact)
290
+ const goalTitle = task.goalTitle || task.artifactTitle;
291
+ if (goalTitle) {
292
+ parts.push(`**Goal:** ${goalTitle}`);
272
293
  }
273
294
 
274
- // Priority
295
+ // Priority (v2: string-based)
275
296
  if (task.priority) {
276
- const priorityLabels = ['High', 'Medium', 'Low'];
277
- parts.push(`**Priority:** ${priorityLabels[task.priority - 1] || 'Medium'}`);
297
+ const priorityEmoji = {
298
+ high: '🔴 High',
299
+ medium: '🟡 Medium',
300
+ low: '🟢 Low',
301
+ }[task.priority] || '🟡 Medium';
302
+ parts.push(`**Priority:** ${priorityEmoji}`);
278
303
  }
279
304
  parts.push('');
280
305
 
281
- // Task content
306
+ // Task description (v2: use description, fallback to content)
282
307
  parts.push('## Description');
283
- parts.push(task.content || 'No additional description provided.');
308
+ const taskDescription = task.description || task.content;
309
+ parts.push(taskDescription || 'No additional description provided.');
284
310
  parts.push('');
285
311
 
286
312
  // Additional context
package/src/listener.ts CHANGED
@@ -11,18 +11,39 @@ import EventSource from 'eventsource';
11
11
  // Types
12
12
  // ============================================================================
13
13
 
14
+ /**
15
+ * Task assigned event (v2)
16
+ * Uses task ID and goal ID (not section_id/artifact_id)
17
+ */
14
18
  export interface TaskAssignedEvent {
15
19
  type: 'task_assigned';
16
20
  timestamp: string;
17
21
  data: {
18
- taskId: string;
19
- sectionId: string;
20
- heading: string;
21
- content: string;
22
- artifactId: string;
22
+ /** Task UUID (primary identifier) */
23
+ id: string;
24
+ /** @deprecated Use id instead */
25
+ taskId?: string;
26
+ /** Goal UUID this task belongs to */
27
+ goalId: string;
28
+ /** @deprecated Use goalId instead */
29
+ artifactId?: string;
30
+ /** Task title */
31
+ title: string;
32
+ /** @deprecated Use title instead */
33
+ heading?: string;
34
+ /** Task description */
35
+ description?: string;
36
+ /** @deprecated Use description instead */
37
+ content?: string;
38
+ /** Goal title for context */
39
+ goalTitle?: string;
40
+ /** @deprecated Use goalTitle instead */
23
41
  artifactTitle?: string;
24
- priority?: number;
42
+ /** Priority level */
43
+ priority?: 'low' | 'medium' | 'high';
44
+ /** Assigned agent ID */
25
45
  assignedTo: string;
46
+ /** Assignment timestamp */
26
47
  assignedAt: string;
27
48
  };
28
49
  }
@@ -242,18 +263,24 @@ export class ArtyfactsListener {
242
263
  try {
243
264
  const data = JSON.parse(event.data);
244
265
 
245
- // Normalize snake_case to camelCase for task data
266
+ // Normalize snake_case to camelCase for task data (v2 schema)
246
267
  const rawData = data.data || data;
247
- const normalizedData = rawData.task_id ? {
248
- taskId: rawData.task_id,
249
- sectionId: rawData.section_id,
250
- artifactId: rawData.artifact_id,
251
- artifactTitle: rawData.artifact_title,
252
- heading: rawData.heading,
253
- content: rawData.content,
268
+ const normalizedData = (rawData.id || rawData.task_id) ? {
269
+ // v2 fields (primary)
270
+ id: rawData.id || rawData.task_id,
271
+ goalId: rawData.goal_id || rawData.artifact_id,
272
+ goalTitle: rawData.goal_title || rawData.artifact_title,
273
+ title: rawData.title || rawData.heading,
274
+ description: rawData.description || rawData.content,
275
+ priority: rawData.priority,
254
276
  assignedTo: rawData.assigned_to,
255
277
  assignedAt: rawData.assigned_at,
256
- priority: rawData.priority,
278
+ // Deprecated fields for backwards compatibility
279
+ taskId: rawData.id || rawData.task_id,
280
+ artifactId: rawData.goal_id || rawData.artifact_id,
281
+ artifactTitle: rawData.goal_title || rawData.artifact_title,
282
+ heading: rawData.title || rawData.heading,
283
+ content: rawData.description || rawData.content,
257
284
  ...rawData, // Keep original fields too
258
285
  } : rawData;
259
286
 
@@ -225,9 +225,11 @@ export const updateAgentHandler: ToolHandler = async (args, client) => {
225
225
  };
226
226
 
227
227
  // =============================================================================
228
- // Task Handlers
228
+ // Task Handlers (v2 - tasks are first-class entities)
229
229
  // =============================================================================
230
230
 
231
+ import type { TaskQueueResponse, TaskClaimResponse, TaskCompleteResponse, InboxResponse, InboxResolveResponse } from './types';
232
+
231
233
  export const getTaskHandler: ToolHandler = async (args, client) => {
232
234
  try {
233
235
  const data = await client.get(`/tasks/${args.task_id}/context`);
@@ -237,36 +239,59 @@ export const getTaskHandler: ToolHandler = async (args, client) => {
237
239
  }
238
240
  };
239
241
 
242
+ /**
243
+ * List tasks from the queue (v2)
244
+ * Uses GET /api/v1/tasks/queue - returns tasks from tasks table
245
+ */
240
246
  export const listTasksHandler: ToolHandler = async (args, client) => {
241
247
  try {
242
248
  const params = new URLSearchParams();
243
- if (args.artifact_id) params.set('artifact_id', String(args.artifact_id));
249
+ if (args.goal_id) params.set('goal_id', String(args.goal_id));
244
250
  if (args.status) params.set('status', String(args.status));
245
251
  if (args.assignee) params.set('assignee', String(args.assignee));
246
252
  if (args.limit) params.set('limit', String(args.limit));
247
253
 
248
254
  const query = params.toString();
249
- const path = `/tasks${query ? `?${query}` : ''}`;
250
- const data = await client.get(path);
255
+ const path = `/tasks/queue${query ? `?${query}` : ''}`;
256
+ const data = await client.get<TaskQueueResponse>(path);
257
+ return { success: true, data };
258
+ } catch (error) {
259
+ return { success: false, error: String(error) };
260
+ }
261
+ };
262
+
263
+ /**
264
+ * Create a goal (v2)
265
+ * Uses POST /api/v1/goals - creates in goals table
266
+ */
267
+ export const createGoalHandler: ToolHandler = async (args, client) => {
268
+ try {
269
+ const data = await client.post('/goals', {
270
+ title: args.title,
271
+ description: args.description,
272
+ priority: args.priority || 'medium',
273
+ target_date: args.target_date,
274
+ tags: args.tags,
275
+ });
251
276
  return { success: true, data };
252
277
  } catch (error) {
253
278
  return { success: false, error: String(error) };
254
279
  }
255
280
  };
256
281
 
282
+ /**
283
+ * Create a task (v2)
284
+ * Uses POST /api/v1/tasks - creates in tasks table
285
+ */
257
286
  export const createTaskHandler: ToolHandler = async (args, client) => {
258
287
  try {
259
- const data = await client.post(`/artifacts/${args.artifact_id}/sections`, {
260
- section_id: `task-${Date.now()}`,
261
- heading: args.heading,
262
- content: args.content,
263
- type: 'task',
264
- task_status: 'pending',
288
+ const data = await client.post('/tasks', {
289
+ goal_id: args.goal_id,
290
+ title: args.title,
291
+ description: args.description,
265
292
  assignee_agent_id: args.assignee,
266
293
  depends_on: args.depends_on,
267
- priority: args.priority,
268
- agent_id: 'system',
269
- agent_name: 'System',
294
+ priority: args.priority || 'medium',
270
295
  });
271
296
  return { success: true, data };
272
297
  } catch (error) {
@@ -274,9 +299,27 @@ export const createTaskHandler: ToolHandler = async (args, client) => {
274
299
  }
275
300
  };
276
301
 
302
+ /**
303
+ * Claim a task (v2)
304
+ * Uses POST /api/v1/tasks/:id/claim
305
+ */
306
+ export const claimTaskHandler: ToolHandler = async (args, client) => {
307
+ try {
308
+ const data = await client.post<TaskClaimResponse>(`/tasks/${args.task_id}/claim`, {});
309
+ return { success: true, data };
310
+ } catch (error) {
311
+ return { success: false, error: String(error) };
312
+ }
313
+ };
314
+
315
+ /**
316
+ * Complete a task (v2)
317
+ * Uses POST /api/v1/tasks/:id/complete
318
+ * Returns unblocked_tasks for follow-up work
319
+ */
277
320
  export const completeTaskHandler: ToolHandler = async (args, client) => {
278
321
  try {
279
- const data = await client.post(`/tasks/${args.task_id}/complete`, {
322
+ const data = await client.post<TaskCompleteResponse>(`/tasks/${args.task_id}/complete`, {
280
323
  output: args.output,
281
324
  summary: args.summary,
282
325
  output_url: args.output_url,
@@ -287,9 +330,13 @@ export const completeTaskHandler: ToolHandler = async (args, client) => {
287
330
  }
288
331
  };
289
332
 
333
+ /**
334
+ * Block a task (v2)
335
+ * Uses POST /api/v1/tasks/:id/block
336
+ */
290
337
  export const blockTaskHandler: ToolHandler = async (args, client) => {
291
338
  try {
292
- const data = await client.post(`/tasks/${args.task_id}/fail`, {
339
+ const data = await client.post(`/tasks/${args.task_id}/block`, {
293
340
  reason: args.reason,
294
341
  blocker_type: args.blocker_type,
295
342
  });
@@ -299,6 +346,46 @@ export const blockTaskHandler: ToolHandler = async (args, client) => {
299
346
  }
300
347
  };
301
348
 
349
+ // =============================================================================
350
+ // Inbox Handlers (v2)
351
+ // =============================================================================
352
+
353
+ /**
354
+ * List inbox items (v2)
355
+ * Uses GET /api/v1/inbox
356
+ */
357
+ export const listInboxHandler: ToolHandler = async (args, client) => {
358
+ try {
359
+ const params = new URLSearchParams();
360
+ if (args.status) params.set('status', String(args.status));
361
+ if (args.kind) params.set('kind', String(args.kind));
362
+ if (args.limit) params.set('limit', String(args.limit));
363
+
364
+ const query = params.toString();
365
+ const path = `/inbox${query ? `?${query}` : ''}`;
366
+ const data = await client.get<InboxResponse>(path);
367
+ return { success: true, data };
368
+ } catch (error) {
369
+ return { success: false, error: String(error) };
370
+ }
371
+ };
372
+
373
+ /**
374
+ * Resolve an inbox item (v2)
375
+ * Uses POST /api/v1/inbox/:id/resolve with auto-execute
376
+ */
377
+ export const resolveInboxHandler: ToolHandler = async (args, client) => {
378
+ try {
379
+ const data = await client.post<InboxResolveResponse>(`/inbox/${args.inbox_id}/resolve`, {
380
+ decision: args.decision,
381
+ notes: args.notes,
382
+ });
383
+ return { success: true, data };
384
+ } catch (error) {
385
+ return { success: false, error: String(error) };
386
+ }
387
+ };
388
+
302
389
  // =============================================================================
303
390
  // Blocker Handlers
304
391
  // =============================================================================
@@ -418,14 +505,22 @@ export const handlers: Record<string, ToolHandler> = {
418
505
  create_agent: createAgentHandler,
419
506
  update_agent: updateAgentHandler,
420
507
 
421
- // Tasks
508
+ // Goals (v2)
509
+ create_goal: createGoalHandler,
510
+
511
+ // Tasks (v2)
422
512
  get_task: getTaskHandler,
423
513
  list_tasks: listTasksHandler,
424
514
  create_task: createTaskHandler,
515
+ claim_task: claimTaskHandler,
425
516
  complete_task: completeTaskHandler,
426
517
  block_task: blockTaskHandler,
427
518
 
428
- // Blockers
519
+ // Inbox (v2)
520
+ list_inbox: listInboxHandler,
521
+ resolve_inbox: resolveInboxHandler,
522
+
523
+ // Blockers (legacy - kept for compatibility)
429
524
  get_blocker: getBlockerHandler,
430
525
  list_blockers: listBlockersHandler,
431
526
  create_blocker: createBlockerHandler,