overlord-cli 0.2610201032.0 → 0.2610231436.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.
@@ -63,45 +63,6 @@ async function runProtocol(subcommand, args = {}) {
63
63
  }
64
64
  }
65
65
 
66
- function objectSchema(properties, required = []) {
67
- return {
68
- type: 'object',
69
- properties,
70
- required,
71
- additionalProperties: false
72
- };
73
- }
74
-
75
- function stringProperty(description) {
76
- return { type: 'string', description };
77
- }
78
-
79
- function booleanProperty(description) {
80
- return { type: 'boolean', description };
81
- }
82
-
83
- function changeRationalesProperty(description) {
84
- return {
85
- type: 'array',
86
- description,
87
- items: objectSchema(
88
- {
89
- filePath: stringProperty('Repository-relative path of the changed file.'),
90
- label: stringProperty('Short reviewer title for the change.'),
91
- summary: stringProperty('What changed in this file.'),
92
- why: stringProperty('Why the change was made.'),
93
- impact: stringProperty('Behavioral impact of the change.'),
94
- hunks: {
95
- type: 'array',
96
- description: 'Optional diff-hunk headers only; file contents and diffs are prohibited.',
97
- items: objectSchema({ header: stringProperty('Unified-diff hunk header.') }, ['header'])
98
- }
99
- },
100
- ['filePath', 'label', 'summary', 'why', 'impact']
101
- )
102
- };
103
- }
104
-
105
66
  function compactSearchResponse(response) {
106
67
  const value = response?.structuredContent;
107
68
  if (!value || value.version !== 3 || !Array.isArray(value.results)) return response;
@@ -156,502 +117,1009 @@ function compactRunQueueResponse(response) {
156
117
  };
157
118
  }
158
119
 
120
+ // BEGIN GENERATED MCP TOOL CATALOG
121
+ // Generated from packages/contract/src/mcp-tools.ts — do not edit.
122
+ // Regenerate with `yarn connectors:mcp-tools`.
159
123
  const tools = [
160
124
  {
161
125
  name: 'overlord_resolve_project',
162
126
  title: 'Resolve Overlord project',
163
127
  description:
164
- "Resolve a project by id, slug, name, or linked repository directory metadata exposed to the MCP client. Names are matched case-insensitively across every workspace the caller can reach; a name matching in more than one returns a 'project_selection_required' result listing the candidates with their workspaces — ask the user, then retry with workspaceId.",
165
- inputSchema: objectSchema({
166
- projectId: stringProperty('Explicit Overlord project id, slug, or project name.'),
167
- workspaceId: stringProperty(
168
- "Optional workspace (id, slug, or name) narrowing an ambiguous projectId. Use this to retry after a 'project_selection_required' result."
169
- ),
170
- directory: stringProperty(
171
- 'Optional repository directory path when the MCP client can expose one with .overlord/project.json.'
172
- )
173
- })
128
+ "Use this when the user identifies an Overlord project by id, slug, name, or exposed repository metadata. Names are matched case-insensitively across every workspace the caller can reach; when a name matches in more than one, this returns a 'project_selection_required' result listing the candidates with their workspaces — ask the user which one, then retry with workspaceId set. When resolving from .overlord/project.json, the result is the isPrimary project if the checkout is linked to more than one project; linkedProjects lists every linked project.",
129
+ inputSchema: {
130
+ type: 'object',
131
+ properties: {
132
+ projectId: {
133
+ type: 'string',
134
+ description: 'Explicit Overlord project id, slug, or project name.'
135
+ },
136
+ workspaceId: {
137
+ type: 'string',
138
+ description:
139
+ "Optional workspace (id, slug, or name) that narrows an ambiguous projectId. Use this to retry after a 'project_selection_required' result."
140
+ },
141
+ directory: {
142
+ type: 'string',
143
+ description:
144
+ 'Optional repository directory path when the MCP client can expose one with .overlord/project.json.'
145
+ }
146
+ },
147
+ required: [],
148
+ additionalProperties: false
149
+ },
150
+ annotations: {
151
+ readOnlyHint: true,
152
+ destructiveHint: false,
153
+ openWorldHint: false
154
+ }
174
155
  },
175
156
  {
176
157
  name: 'overlord_create_project',
177
158
  title: 'Create Overlord project',
178
159
  description:
179
- 'Create a new Overlord project. If the caller belongs to more than one workspace and none is given, returns a workspace_selection_required result listing the workspaces for the user to choose.',
180
- inputSchema: objectSchema(
181
- {
182
- name: stringProperty('New project name.'),
183
- workspaceId: stringProperty(
184
- 'Workspace to create the project in (id, slug, or name). Required only when the caller belongs to multiple workspaces.'
185
- ),
186
- description: stringProperty('Optional project description.'),
187
- slug: stringProperty('Optional project slug; defaults to a slug derived from the name.')
160
+ "Use this only when the user explicitly asks to create a new Overlord project (workspace project). If the user belongs to more than one workspace and none is specified, this returns a 'workspace_selection_required' result listing the workspaces — ask the user which one, then call again with workspaceId set to the chosen id, slug, or name.",
161
+ inputSchema: {
162
+ type: 'object',
163
+ properties: {
164
+ name: {
165
+ type: 'string',
166
+ description: 'New project name.'
167
+ },
168
+ workspaceId: {
169
+ type: 'string',
170
+ description:
171
+ 'Workspace to create the project in (id, slug, or name). Required only when the caller belongs to multiple workspaces.'
172
+ },
173
+ description: {
174
+ type: 'string',
175
+ description: 'Optional project description.'
176
+ },
177
+ slug: {
178
+ type: 'string',
179
+ description: 'Optional project slug; defaults to a slug derived from the name.'
180
+ }
188
181
  },
189
- ['name']
190
- )
182
+ required: ['name'],
183
+ additionalProperties: false
184
+ },
185
+ annotations: {
186
+ readOnlyHint: false,
187
+ destructiveHint: false,
188
+ openWorldHint: false
189
+ }
191
190
  },
192
191
  {
193
192
  name: 'overlord_list_project_statuses',
194
193
  title: 'List Overlord project statuses',
195
194
  description:
196
- "Read one project's board columns. Status names and order are defined per project, so two projects in the same workspace can label the same lifecycle differently; each status also carries a stable type (draft, next, execute, review, complete, blocked, cancelled) that does not vary by project.",
197
- inputSchema: objectSchema(
198
- {
199
- projectId: stringProperty(
200
- "Overlord project id, slug, or name. An ambiguous name returns 'project_selection_required'; retry with workspaceId."
201
- ),
202
- workspaceId: stringProperty(
203
- 'Optional workspace (id, slug, or name) narrowing an ambiguous projectId.'
204
- )
195
+ "Use this to read one project's board columns. Status names and order are defined per project, so two projects in the same workspace can label the same lifecycle differently; this is the only way to discover a specific board’s columns. Each status carries a stable type (draft, next, execute, review, complete, blocked, cancelled) that does not vary by project — use the type for filtering and the name only for display.",
196
+ inputSchema: {
197
+ type: 'object',
198
+ properties: {
199
+ projectId: {
200
+ type: 'string',
201
+ description:
202
+ "Overlord project id, slug, or name. An ambiguous name returns 'project_selection_required'; retry with workspaceId."
203
+ },
204
+ workspaceId: {
205
+ type: 'string',
206
+ description: 'Optional workspace (id, slug, or name) that narrows an ambiguous projectId.'
207
+ }
205
208
  },
206
- ['projectId']
207
- )
209
+ required: ['projectId'],
210
+ additionalProperties: false
211
+ },
212
+ annotations: {
213
+ readOnlyHint: true,
214
+ destructiveHint: false,
215
+ openWorldHint: false
216
+ }
208
217
  },
209
218
  {
210
219
  name: 'overlord_search_missions',
211
220
  title: 'Search Overlord missions',
212
221
  description:
213
- "Search mission anchors with their matching objectives and deliveries across authorized workspaces. An objective displayId can be passed directly to overlord_load_mission_context; matches are matched-only, not the full objective list. Artifacts are not indexed. Use absolute ISO from/to bounds (no relative dates or implicit window), inspect workspaceCounts, entityCounts, and truncatedCandidates before claiming completeness, and treat appliedFilters.mode 'fallback' as a recency listing. Compact detail is default; request full for child snippets and metadata. Ranked results never prove absence: to check an exact token such as a canonical kb-feature: Knowledgebase Feature reference, pass reference with projectId (only workspaceId, limit 1-100 and cursor may accompany it) and follow nextCursor until complete is true.",
214
- inputSchema: objectSchema({
215
- query: stringProperty('Search query text.'),
216
- reference: stringProperty(
217
- 'Exact-reference mode: case-sensitive whole token (8-512 characters, no whitespace) in live objective text. Requires projectId; cannot be combined with ranked filters. Returns { results (with statusType and matching objectives), nextCursor, complete }.'
218
- ),
219
- cursor: stringProperty(
220
- 'Exact-reference mode only: nextCursor from the previous page for the same reference and projectId.'
221
- ),
222
- status: stringProperty(
223
- 'Comma-separated status TYPES, such as draft,next,execute,review. Types are workspace-invariant (draft, next, execute, review, complete, blocked, cancelled). Project-defined status names are not accepted here.'
224
- ),
225
- projectId: stringProperty(
226
- "Optional project reference: a stable UUID, a slug, or the project name as the user said it. Names are matched case-insensitively against the projects the caller can reach. If the name matches in more than one workspace the call returns a 'project_selection_required' result listing the candidates with their workspaces — ask the user which one, then retry with workspaceId set."
227
- ),
228
- workspaceId: stringProperty(
229
- "Optional workspace (id, slug, or name) narrowing an ambiguous projectId. Use this to retry after a 'project_selection_required' result."
230
- ),
231
- resourceKey: stringProperty(
232
- 'Optional logical resource key, matched by name within selected projects.'
233
- ),
234
- dateField: stringProperty(
235
- 'Date column for an explicit range: createdAt, updatedAt, or dueDatetime. Use dueDatetime for questions about what is scheduled or due; missions with no due date are excluded from a dueDatetime range.'
236
- ),
237
- from: stringProperty('Optional inclusive ISO-8601 date/time lower bound.'),
238
- to: stringProperty('Optional exclusive ISO-8601 date/time upper bound.'),
239
- limit: {
240
- type: 'number',
241
- description: 'Maximum result count. Defaults to 25.'
242
- },
243
- entityTypes: stringProperty(
244
- 'Optional comma-separated v3 entity types: mission, objective, delivery.'
245
- ),
246
- objectiveStates: stringProperty(
247
- 'Optional comma-separated v3 objective states for matching objectives.'
248
- ),
249
- matchesPerResult: {
250
- type: 'number',
251
- description:
252
- 'Optional v3 child-match cap per mission (default 3, max 10; compact returns at most 2).'
222
+ "Use this to find missions across the caller's authorized workspaces. Results are mission anchors with only the matching objectives and deliveries in matches; an objective displayId (for example coo:789.2nnh) can be passed directly to overlord_load_mission_context. matches is never the mission's complete objective list. Artifacts are not indexed; load mission context after locating the mission to read them. There is no relative-date parsing or implicit time window: compute absolute ISO bounds and pass from/to. Raise limit for broad questions and inspect workspaceCounts, entityCounts, and truncatedCandidates before claiming a list is complete. appliedFilters.mode 'fallback' means the query contributed nothing and results are a recency listing, not an answer. Compact detail is the default and retains navigation identity while reducing child payload; request full for snippets and child metadata. Ranked results can never prove that no mission mentions something. To prove absence or presence of an exact token (for example a canonical kb-feature: Knowledgebase Feature reference), pass reference with projectId instead: that mode is exhaustive, returns every mission in the project whose live objective text contains the exact token with its statusType, and pages with cursor until complete is true; it accepts only projectId, workspaceId, limit (1-100, default 50) and cursor.",
223
+ inputSchema: {
224
+ type: 'object',
225
+ properties: {
226
+ query: {
227
+ type: 'string',
228
+ description: 'Search query text.'
229
+ },
230
+ reference: {
231
+ type: 'string',
232
+ description:
233
+ 'Exact-reference mode: a case-sensitive token of 8-512 characters with no whitespace, matched as a whole token in live objective instruction text. Requires projectId; cannot be combined with query or other ranked filters. Returns MissionReferenceSearchResponse { results, nextCursor, complete }. Absence is proven only after following nextCursor to a page with complete: true.'
234
+ },
235
+ cursor: {
236
+ type: 'string',
237
+ description:
238
+ 'Exact-reference mode only: the nextCursor from the previous page for the same reference and projectId.'
239
+ },
240
+ status: {
241
+ type: 'string',
242
+ description:
243
+ 'Comma-separated status TYPES, such as draft,execute,review. Types are workspace-invariant (draft, next, execute, review, complete, blocked, cancelled). Project-defined status names — the board column labels read by overlord_list_project_statuses — are not accepted here.'
244
+ },
245
+ projectId: {
246
+ type: 'string',
247
+ description:
248
+ "Optional project reference: a stable UUID, a slug, or the project name as the user said it. Names are matched case-insensitively against the projects the caller can reach. If the name matches in more than one workspace the call returns a 'project_selection_required' result listing the candidates with their workspaces — ask the user which one, then retry with workspaceId set."
249
+ },
250
+ workspaceId: {
251
+ type: 'string',
252
+ description:
253
+ "Optional workspace (id, slug, or name) that narrows an ambiguous projectId. Use this to retry after a 'project_selection_required' result."
254
+ },
255
+ resourceKey: {
256
+ type: 'string',
257
+ description:
258
+ 'Optional logical resource key. Keys are matched by name within every selected project.'
259
+ },
260
+ dateField: {
261
+ type: 'string',
262
+ enum: ['createdAt', 'updatedAt', 'dueDatetime'],
263
+ description:
264
+ 'Date column for an explicit range: createdAt, updatedAt, or dueDatetime. Defaults to updatedAt only when from or to is supplied. Use dueDatetime for questions about what is scheduled or due — a mission is scheduled by its due date, not by an execution timer. Missions with no due date are excluded from a dueDatetime range.'
265
+ },
266
+ from: {
267
+ type: 'string',
268
+ description: 'Optional inclusive ISO-8601 date/time lower bound.'
269
+ },
270
+ to: {
271
+ type: 'string',
272
+ description: 'Optional exclusive ISO-8601 date/time upper bound.'
273
+ },
274
+ limit: {
275
+ type: 'number',
276
+ description: 'Maximum result count. Defaults to 25.'
277
+ },
278
+ entityTypes: {
279
+ type: 'string',
280
+ description: 'Optional comma-separated v3 entity types: mission, objective, delivery.'
281
+ },
282
+ objectiveStates: {
283
+ type: 'string',
284
+ description: 'Optional comma-separated v3 objective states for matching objectives.'
285
+ },
286
+ matchesPerResult: {
287
+ type: 'number',
288
+ description:
289
+ 'Optional v3 child-match cap per mission (default 3, max 10; compact returns at most 2).'
290
+ },
291
+ detail: {
292
+ type: 'string',
293
+ enum: ['compact', 'full'],
294
+ description:
295
+ 'Result detail: compact (default) keeps child navigation fields and removes child snippets/metadata; full returns the complete v3 child matches.'
296
+ }
253
297
  },
254
- detail: {
255
- type: 'string',
256
- enum: ['compact', 'full'],
257
- description:
258
- 'Result detail: compact (default) keeps child navigation fields and removes child snippets/metadata; full returns complete v3 child matches.'
259
- }
260
- })
298
+ required: [],
299
+ additionalProperties: false
300
+ },
301
+ annotations: {
302
+ readOnlyHint: true,
303
+ destructiveHint: false,
304
+ openWorldHint: false
305
+ }
261
306
  },
262
307
  {
263
308
  name: 'overlord_create_mission',
264
309
  title: 'Create Overlord mission',
265
310
  description:
266
- 'Create a draft mission with projectId. To intentionally create an account-owned inbox item, set unassignedToProject to true; omission of both is rejected.',
267
- inputSchema: objectSchema(
268
- {
269
- projectId: stringProperty(
270
- 'Overlord project id, slug, or name. Required unless unassignedToProject is true.'
271
- ),
272
- unassignedToProject: booleanProperty(
273
- 'Set true only to intentionally create an account-owned inbox item instead of a project mission. Cannot be combined with projectId.'
274
- ),
275
- objective: stringProperty('Initial objective text.'),
276
- title: stringProperty('Optional mission title.'),
277
- resourceKey: stringProperty('Optional logical project resource key for the objective.'),
278
- agent: stringProperty(
279
- 'Optional agent identifier to assign to the initial objective, such as codex or claude. Omitted leaves the project launch-preference default; set it here instead of appending a second objective just to name an agent.'
280
- ),
281
- model: stringProperty(
282
- 'Optional model identifier for the assigned agent. Requires agent; rejected without it.'
283
- ),
284
- assignedTo: stringProperty(
285
- 'Optional workspace member to own the mission (workspace_users.id, profile UUID, orgid:username, bare username, or email). Rejected when the member is not in the workspace; meaningless for an unassigned inbox item.'
286
- ),
287
- autoAdvance: booleanProperty(
288
- 'When true, Overlord queues the next objective for execution after this one is delivered. Defaults to false.'
289
- )
311
+ 'Use this to create a draft mission with projectId. To intentionally create an account-owned inbox item, set unassignedToProject to true; omission of both is rejected.',
312
+ inputSchema: {
313
+ type: 'object',
314
+ properties: {
315
+ projectId: {
316
+ type: 'string',
317
+ description:
318
+ 'Overlord project id, slug, or name. Required unless unassignedToProject is true.'
319
+ },
320
+ unassignedToProject: {
321
+ type: 'boolean',
322
+ description:
323
+ 'Set true only to intentionally create an account-owned inbox item instead of a project mission. Cannot be combined with projectId.'
324
+ },
325
+ objective: {
326
+ type: 'string',
327
+ description: 'Initial objective text.'
328
+ },
329
+ title: {
330
+ type: 'string',
331
+ description: 'Optional mission title.'
332
+ },
333
+ resourceKey: {
334
+ type: 'string',
335
+ description: 'Optional logical project resource key for the objective.'
336
+ },
337
+ agent: {
338
+ type: 'string',
339
+ description:
340
+ 'Optional agent identifier to assign to the initial objective, such as codex or claude. Omitted leaves the project launch-preference default; set it here instead of appending a second objective just to name an agent.'
341
+ },
342
+ model: {
343
+ type: 'string',
344
+ description:
345
+ 'Optional model identifier for the assigned agent. Requires agent; rejected without it.'
346
+ },
347
+ assignedTo: {
348
+ type: 'string',
349
+ description:
350
+ 'Optional workspace member to own the mission (workspace_users.id, profile UUID, orgid:username, bare username, or email). Rejected when the member is not in the workspace; meaningless for an unassigned inbox item.'
351
+ },
352
+ autoAdvance: {
353
+ type: 'boolean',
354
+ description:
355
+ 'When true, Overlord queues the next objective for execution after this one is delivered. Defaults to false.'
356
+ }
290
357
  },
291
- ['objective']
292
- )
358
+ required: ['objective'],
359
+ additionalProperties: false
360
+ },
361
+ annotations: {
362
+ readOnlyHint: false,
363
+ destructiveHint: false,
364
+ openWorldHint: false
365
+ }
293
366
  },
294
367
  {
295
368
  name: 'overlord_create_inbox_item',
296
369
  title: 'Create inbox item',
297
- description: 'Create a private, account-owned unassigned task capture.',
298
- inputSchema: objectSchema(
299
- {
300
- title: stringProperty('Inbox item title.'),
301
- objective: stringProperty('The one objective captured in v1.')
370
+ description: 'Use this to create a private, account-owned unassigned task capture.',
371
+ inputSchema: {
372
+ type: 'object',
373
+ properties: {
374
+ title: {
375
+ type: 'string',
376
+ description: 'Inbox item title.'
377
+ },
378
+ objective: {
379
+ type: 'string',
380
+ description: 'The one objective captured in v1.'
381
+ }
302
382
  },
303
- ['title', 'objective']
304
- )
383
+ required: ['title', 'objective'],
384
+ additionalProperties: false
385
+ },
386
+ annotations: {
387
+ readOnlyHint: false,
388
+ destructiveHint: false,
389
+ openWorldHint: false
390
+ }
305
391
  },
306
392
  {
307
393
  name: 'overlord_load_mission_context',
308
394
  title: 'Load mission context',
309
395
  description:
310
- 'Load structured mission context, objectives, history, artifacts, and shared context.',
311
- inputSchema: objectSchema(
312
- {
313
- missionId: stringProperty(
314
- 'Mission UUID or workspace display id. Optional when objectiveId is a display id such as coo:756.k7xm, which already names its mission.'
315
- ),
316
- objectiveId: stringProperty(
317
- 'Objective UUID or display id such as coo:756.k7xm. Returns that objective as the current one instead of rediscovering the mission active objective.'
318
- ),
319
- executionTargetId: stringProperty(
320
- 'Optional local execution target id for resolving sibling project resource paths.'
321
- )
396
+ 'Use this when the user wants to inspect one mission, its objectives, history, artifacts, or shared context.',
397
+ inputSchema: {
398
+ type: 'object',
399
+ properties: {
400
+ missionId: {
401
+ type: 'string',
402
+ description:
403
+ 'Mission UUID or workspace display id. Optional when objectiveId is a display id such as coo:756.k7xm, which already names its mission.'
404
+ },
405
+ objectiveId: {
406
+ type: 'string',
407
+ description:
408
+ 'Objective UUID or display id such as coo:756.k7xm. Returns that objective as the current one instead of rediscovering the mission active objective — required on a mission running objectives in parallel.'
409
+ },
410
+ executionTargetId: {
411
+ type: 'string',
412
+ description:
413
+ 'Optional local execution target id for resolving sibling project resource paths.'
414
+ }
322
415
  },
323
- []
324
- )
416
+ required: [],
417
+ additionalProperties: false
418
+ },
419
+ annotations: {
420
+ readOnlyHint: true,
421
+ destructiveHint: false,
422
+ openWorldHint: false
423
+ }
325
424
  },
326
425
  {
327
426
  name: 'overlord_list_deliveries',
328
427
  title: 'List mission deliveries',
329
428
  description:
330
- "Use this to read a mission's delivered work after locating it. Returns newest-first normalized delivery records including summary, verification, follow-up notes, and authoritative delivery evidence; it never exposes raw delivery payloads.",
331
- inputSchema: objectSchema({
332
- missionId: stringProperty(
333
- 'Mission UUID or workspace display id. Optional when objectiveId is a display id such as coo:756.k7xm, which already names its mission.'
334
- ),
335
- objectiveId: stringProperty(
336
- 'Objective UUID or display id such as coo:756.k7xm. Use a display id when that is the only identifier available.'
337
- )
338
- })
429
+ "Use this to read a mission's delivered work after locating it. Returns a newest-first MissionDeliveriesDto page { items, total, limit } of normalized delivery records including summary, verification, follow-up notes, and authoritative human-action, tradeoff, risk, deferred-work, and assumption evidence; items are capped at 200 and total is the matching count before that cap. It never exposes raw delivery payloads.",
430
+ inputSchema: {
431
+ type: 'object',
432
+ properties: {
433
+ missionId: {
434
+ type: 'string',
435
+ description:
436
+ 'Mission UUID or workspace display id. Optional when objectiveId is a display id such as coo:756.k7xm, which already names its mission.'
437
+ },
438
+ objectiveId: {
439
+ type: 'string',
440
+ description:
441
+ 'Objective UUID or display id such as coo:756.k7xm. Use a display id when that is the only identifier available.'
442
+ }
443
+ },
444
+ required: [],
445
+ additionalProperties: false
446
+ },
447
+ annotations: {
448
+ readOnlyHint: true,
449
+ destructiveHint: false,
450
+ openWorldHint: false
451
+ }
339
452
  },
340
453
  {
341
454
  name: 'overlord_launch_objective',
342
455
  title: 'Launch objective execution',
343
456
  description:
344
- 'Use this only when the user explicitly asks to start a particular objective. It queues the normal Overlord execution request; it does not attach this MCP agent to perform the work. An existing active request is returned instead of duplicated.',
345
- inputSchema: objectSchema(
346
- {
347
- objectiveId: stringProperty('Objective UUID or display id such as coo:756.k7xm.'),
348
- agent: stringProperty('Agent identifier to launch, such as codex or claude.'),
349
- model: stringProperty('Optional model identifier to snapshot onto the execution request.'),
350
- reasoningEffort: stringProperty(
351
- 'Optional reasoning-effort setting to snapshot onto the execution request.'
352
- ),
353
- executionTargetId: stringProperty(
354
- "Optional eligible execution target id. Omit to use the project's normal target selection."
355
- )
457
+ 'Use this only when the user explicitly asks to start a particular objective. It queues the normal Overlord execution request; it does not attach this MCP agent to perform the work. The objective must be launchable, its workspace must authorize execution, and an existing active request is returned instead of duplicated.',
458
+ inputSchema: {
459
+ type: 'object',
460
+ properties: {
461
+ objectiveId: {
462
+ type: 'string',
463
+ description: 'Objective UUID or display id such as coo:756.k7xm.'
464
+ },
465
+ agent: {
466
+ type: 'string',
467
+ description: 'Agent identifier to launch, such as codex or claude.'
468
+ },
469
+ model: {
470
+ type: 'string',
471
+ description: 'Optional model identifier to snapshot onto the execution request.'
472
+ },
473
+ reasoningEffort: {
474
+ type: 'string',
475
+ description: 'Optional reasoning-effort setting to snapshot onto the execution request.'
476
+ },
477
+ executionTargetId: {
478
+ type: 'string',
479
+ description:
480
+ "Optional eligible execution target id. Omit to use the project's normal target selection."
481
+ }
356
482
  },
357
- ['objectiveId', 'agent']
358
- )
483
+ required: ['objectiveId', 'agent'],
484
+ additionalProperties: false
485
+ },
486
+ annotations: {
487
+ readOnlyHint: false,
488
+ destructiveHint: false,
489
+ openWorldHint: false
490
+ }
359
491
  },
360
492
  {
361
493
  name: 'overlord_reorder_future_objectives',
362
494
  title: 'Reorder future objectives',
363
495
  description:
364
- 'Use this only when the user explicitly asks to change future-objective order in one mission. Supply every future objective UUID in its complete desired top-to-bottom order; draft, active, and completed objectives cannot be moved by this tool.',
365
- inputSchema: objectSchema(
366
- {
367
- missionId: stringProperty('Mission UUID.'),
496
+ 'Use this only when the user explicitly asks to change the order of future objectives in one mission. Supply every future objective UUID in its complete desired top-to-bottom order; draft, active, and completed objectives cannot be moved by this tool.',
497
+ inputSchema: {
498
+ type: 'object',
499
+ properties: {
500
+ missionId: {
501
+ type: 'string',
502
+ description: 'Mission UUID.'
503
+ },
368
504
  orderedObjectiveIds: {
369
505
  type: 'array',
370
506
  description:
371
507
  'Complete desired top-to-bottom UUID order of every objective currently in the future state.',
372
- items: stringProperty('Future objective UUID.')
508
+ items: {
509
+ type: 'string',
510
+ description: 'Future objective UUID.'
511
+ }
373
512
  }
374
513
  },
375
- ['missionId', 'orderedObjectiveIds']
376
- )
514
+ required: ['missionId', 'orderedObjectiveIds'],
515
+ additionalProperties: false
516
+ },
517
+ annotations: {
518
+ readOnlyHint: false,
519
+ destructiveHint: false,
520
+ openWorldHint: false
521
+ }
377
522
  },
378
523
  {
379
524
  name: 'overlord_add_objectives',
380
525
  title: 'Add objectives',
381
- description: 'Append one or more draft objectives to an existing mission.',
382
- inputSchema: objectSchema(
383
- {
384
- missionId: stringProperty(
385
- 'Mission UUID or workspace display id. Optional when objectiveId is a display id such as coo:756.k7xm, which already names its mission.'
386
- ),
387
- objectiveId: stringProperty(
388
- 'Objective UUID or display id such as coo:756.k7xm. Used only to supply missionId when it is omitted.'
389
- ),
526
+ description:
527
+ 'Use this only when the user explicitly asks to append draft objectives to an existing mission.',
528
+ inputSchema: {
529
+ type: 'object',
530
+ properties: {
531
+ missionId: {
532
+ type: 'string',
533
+ description:
534
+ 'Mission UUID or workspace display id. Optional when objectiveId is a display id such as coo:756.k7xm, which already names its mission.'
535
+ },
536
+ objectiveId: {
537
+ type: 'string',
538
+ description:
539
+ 'Objective UUID or display id such as coo:756.k7xm. Used only to supply missionId when it is omitted; the new objectives are appended to that objective mission.'
540
+ },
390
541
  objectives: {
391
542
  type: 'array',
392
543
  description:
393
- 'Objective objects with objective text and optional title, resourceKey, and autoAdvance.',
394
- items: objectSchema({
395
- objective: stringProperty('Objective text.'),
396
- title: stringProperty('Optional objective title.'),
397
- resourceKey: stringProperty('Optional logical project resource key.'),
398
- autoAdvance: booleanProperty(
399
- 'When true, Overlord queues the next objective for execution after this one is delivered. Defaults to false.'
400
- )
401
- })
544
+ 'Objective objects with objective text and optional title, agent/model launch selection, resourceKey, and autoAdvance.',
545
+ items: {
546
+ type: 'object',
547
+ properties: {
548
+ objective: {
549
+ type: 'string',
550
+ description: 'Objective text.'
551
+ },
552
+ title: {
553
+ type: 'string',
554
+ description: 'Optional objective title.'
555
+ },
556
+ agent: {
557
+ type: 'string',
558
+ description:
559
+ 'Optional agent identifier to assign to this objective, such as codex or claude.'
560
+ },
561
+ model: {
562
+ type: 'string',
563
+ description: 'Optional model identifier for this objective. Requires agent.'
564
+ },
565
+ resourceKey: {
566
+ type: 'string',
567
+ description: 'Optional logical project resource key.'
568
+ },
569
+ autoAdvance: {
570
+ type: 'boolean',
571
+ description:
572
+ 'When true, Overlord queues the next objective for execution after this one is delivered. Defaults to false.'
573
+ }
574
+ },
575
+ required: [],
576
+ additionalProperties: false
577
+ }
402
578
  }
403
579
  },
404
- ['objectives']
405
- )
580
+ required: ['objectives'],
581
+ additionalProperties: false
582
+ },
583
+ annotations: {
584
+ readOnlyHint: false,
585
+ destructiveHint: false,
586
+ openWorldHint: false
587
+ }
406
588
  },
407
589
  {
408
590
  name: 'overlord_update_objective',
409
591
  title: 'Update objective',
410
592
  description:
411
- 'Turn auto-advance on or off and/or edit instruction text on a draft or future objective.',
412
- inputSchema: objectSchema(
413
- {
414
- objectiveId: stringProperty('Objective UUID or display id.'),
415
- autoAdvance: booleanProperty(
416
- 'When true, Overlord queues the next objective after this one is delivered. When false, delivery waits for approval.'
417
- ),
418
- instructionText: stringProperty(
419
- 'Replacement instruction text. Allowed only when the objective is in draft or future state; blank clears the text in those states.'
420
- )
593
+ 'Use this to rewrite an objective title in any state, turn auto-advance on or off, and/or edit instruction text on a draft or future objective.',
594
+ inputSchema: {
595
+ type: 'object',
596
+ properties: {
597
+ objectiveId: {
598
+ type: 'string',
599
+ description: 'Objective UUID or display id.'
600
+ },
601
+ title: {
602
+ type: 'string',
603
+ description:
604
+ 'Replacement objective title. An empty string clears the custom title and restores instruction-derived presentation.'
605
+ },
606
+ autoAdvance: {
607
+ type: 'boolean',
608
+ description:
609
+ 'When true, Overlord queues the next objective after this one is delivered. When false, delivery waits for approval.'
610
+ },
611
+ instructionText: {
612
+ type: 'string',
613
+ description:
614
+ 'Replacement instruction text. Allowed only when the objective is in draft or future state; blank clears the text in those states.'
615
+ }
421
616
  },
422
- ['objectiveId']
423
- )
617
+ required: ['objectiveId'],
618
+ additionalProperties: false
619
+ },
620
+ annotations: {
621
+ readOnlyHint: false,
622
+ destructiveHint: false,
623
+ openWorldHint: false
624
+ }
424
625
  },
425
626
  {
426
627
  name: 'overlord_delete_missions',
427
628
  title: 'Delete missions',
428
629
  description:
429
630
  'Use this only after showing the resolved mission list to the user and receiving an affirmative response. Soft-deletes one to 100 missions atomically; any missing, duplicate, deleted, or unauthorized target rejects the entire request. Deleting a mission also soft-deletes its live objectives.',
430
- inputSchema: objectSchema(
431
- {
631
+ inputSchema: {
632
+ type: 'object',
633
+ properties: {
432
634
  missionIds: {
433
635
  type: 'array',
434
636
  description: 'One to 100 unique mission UUIDs or display IDs to delete.',
435
- items: stringProperty('Mission UUID or workspace display ID.')
637
+ items: {
638
+ type: 'string',
639
+ description: 'Mission UUID or workspace display ID.'
640
+ }
436
641
  },
437
- confirm: booleanProperty(
438
- 'Must be true only after the user has reviewed the resolved mission list and affirmatively approved deletion.'
439
- )
642
+ confirm: {
643
+ type: 'boolean',
644
+ description:
645
+ 'Must be true only after the user has reviewed the resolved mission list and affirmatively approved deletion.'
646
+ }
440
647
  },
441
- ['missionIds', 'confirm']
442
- )
648
+ required: ['missionIds', 'confirm'],
649
+ additionalProperties: false
650
+ },
651
+ annotations: {
652
+ readOnlyHint: false,
653
+ destructiveHint: true,
654
+ openWorldHint: false
655
+ }
443
656
  },
444
657
  {
445
658
  name: 'overlord_delete_objectives',
446
659
  title: 'Delete objectives',
447
660
  description:
448
661
  'Use this only after showing the resolved objective list to the user and receiving an affirmative response. Soft-deletes one to 100 objectives atomically; any missing, duplicate, deleted, or unauthorized target rejects the entire request. Deleting an objective also removes its live Run Queue membership.',
449
- inputSchema: objectSchema(
450
- {
662
+ inputSchema: {
663
+ type: 'object',
664
+ properties: {
451
665
  objectiveIds: {
452
666
  type: 'array',
453
667
  description: 'One to 100 unique objective UUIDs or display IDs to delete.',
454
- items: stringProperty('Objective UUID or display ID.')
668
+ items: {
669
+ type: 'string',
670
+ description: 'Objective UUID or display ID.'
671
+ }
455
672
  },
456
- confirm: booleanProperty(
457
- 'Must be true only after the user has reviewed the resolved objective list and affirmatively approved deletion.'
458
- )
673
+ confirm: {
674
+ type: 'boolean',
675
+ description:
676
+ 'Must be true only after the user has reviewed the resolved objective list and affirmatively approved deletion.'
677
+ }
459
678
  },
460
- ['objectiveIds', 'confirm']
461
- )
679
+ required: ['objectiveIds', 'confirm'],
680
+ additionalProperties: false
681
+ },
682
+ annotations: {
683
+ readOnlyHint: false,
684
+ destructiveHint: true,
685
+ openWorldHint: false
686
+ }
462
687
  },
463
688
  {
464
689
  name: 'overlord_list_run_queues',
465
690
  title: 'List Run Queues',
466
691
  description:
467
692
  "Use this to read a project's authoritative Run Queues before adding, moving, removing, or bulk-reordering entries. Compact detail is the default and includes ordering and blocking state; request full for the complete ProjectRunQueuesDto.",
468
- inputSchema: objectSchema({
469
- projectId: stringProperty('Optional project UUID, slug, or name.'),
470
- objectiveId: stringProperty(
471
- 'Optional objective UUID or display id; derives the project when projectId is omitted.'
472
- ),
473
- missionId: stringProperty(
474
- 'Optional mission UUID or display id; derives the project when projectId is omitted.'
475
- ),
476
- queue: stringProperty('Optional Run Queue UUID or unambiguous name to return by itself.'),
477
- detail: {
478
- type: 'string',
479
- enum: ['compact', 'full'],
480
- description:
481
- 'Result detail: compact (default) returns queue ordering state; full returns the raw ProjectRunQueuesDto.'
482
- }
483
- })
693
+ inputSchema: {
694
+ type: 'object',
695
+ properties: {
696
+ projectId: {
697
+ type: 'string',
698
+ description: 'Optional project UUID, slug, or name.'
699
+ },
700
+ objectiveId: {
701
+ type: 'string',
702
+ description:
703
+ 'Optional objective UUID or display id; derives the project when projectId is omitted.'
704
+ },
705
+ missionId: {
706
+ type: 'string',
707
+ description:
708
+ 'Optional mission UUID or display id; derives the project when projectId is omitted.'
709
+ },
710
+ queue: {
711
+ type: 'string',
712
+ description: 'Optional Run Queue UUID or unambiguous name to return by itself.'
713
+ },
714
+ detail: {
715
+ type: 'string',
716
+ enum: ['compact', 'full'],
717
+ description:
718
+ 'Result detail: compact (default) returns queue ordering state; full returns the raw ProjectRunQueuesDto.'
719
+ }
720
+ },
721
+ required: [],
722
+ additionalProperties: false
723
+ },
724
+ annotations: {
725
+ readOnlyHint: true,
726
+ destructiveHint: false,
727
+ openWorldHint: false
728
+ }
484
729
  },
485
730
  {
486
731
  name: 'overlord_reorder_run_queue',
487
732
  title: 'Reorder Run Queue entries',
488
733
  description:
489
734
  'Use this only when the user explicitly asks to reorder every entry in one Run Queue. Supply every live entry exactly once, using entry UUIDs, objective UUIDs, or objective display ids. Running and dispatched entries cannot move. On a mismatch, the error returns the current order; re-read the queue and retry.',
490
- inputSchema: objectSchema(
491
- {
492
- queue: stringProperty('Run Queue UUID or unambiguous name.'),
735
+ inputSchema: {
736
+ type: 'object',
737
+ properties: {
738
+ queue: {
739
+ type: 'string',
740
+ description: 'Run Queue UUID or unambiguous name.'
741
+ },
493
742
  orderedObjectives: {
494
743
  type: 'array',
495
744
  description:
496
745
  'Complete desired top-to-bottom entry order. Each item may be an entry UUID, objective UUID, or objective display id.',
497
- items: stringProperty('Run Queue entry UUID, objective UUID, or objective display id.')
746
+ items: {
747
+ type: 'string',
748
+ description: 'Run Queue entry UUID, objective UUID, or objective display id.'
749
+ }
498
750
  },
499
- projectId: stringProperty(
500
- 'Optional project UUID, slug, or name; disambiguates queue names.'
501
- )
751
+ projectId: {
752
+ type: 'string',
753
+ description: 'Optional project UUID, slug, or name; disambiguates queue names.'
754
+ }
502
755
  },
503
- ['queue', 'orderedObjectives']
504
- )
756
+ required: ['queue', 'orderedObjectives'],
757
+ additionalProperties: false
758
+ },
759
+ annotations: {
760
+ readOnlyHint: false,
761
+ destructiveHint: false,
762
+ openWorldHint: false
763
+ }
505
764
  },
506
765
  {
507
766
  name: 'overlord_queue_objective',
508
767
  title: 'Queue objective',
509
768
  description:
510
769
  'Use this only when the user explicitly asks to add, move, or remove an objective in the project Run Queue. Queue membership is target-neutral and sequences delivery-driven launches; it does not directly launch the objective. Adding an objective also queues every not-yet-started objective after it in the mission; a removed objective moves to the end of its mission.',
511
- inputSchema: objectSchema(
512
- {
513
- objectiveId: stringProperty('Objective UUID or display id such as coo:756.k7xm.'),
514
- queue: stringProperty('Optional Run Queue UUID or unambiguous queue name.'),
515
- after: stringProperty(
516
- 'Optional queued predecessor entry id, objective UUID, or objective display id. Its queue is used when queue is omitted.'
517
- ),
518
- front: booleanProperty('When true, place this objective first in the selected queue.'),
770
+ inputSchema: {
771
+ type: 'object',
772
+ properties: {
773
+ objectiveId: {
774
+ type: 'string',
775
+ description: 'Objective UUID or display id such as coo:756.k7xm.'
776
+ },
777
+ queue: {
778
+ type: 'string',
779
+ description: 'Optional Run Queue UUID or unambiguous queue name.'
780
+ },
781
+ after: {
782
+ type: 'string',
783
+ description:
784
+ 'Optional queued predecessor entry id, objective UUID, or objective display id. Its queue is used when queue is omitted.'
785
+ },
786
+ front: {
787
+ type: 'boolean',
788
+ description: 'When true, place this objective first in the selected queue.'
789
+ },
519
790
  position: {
520
791
  type: 'number',
521
792
  description: 'Optional one-based insertion position in the selected queue.'
522
793
  },
523
- remove: booleanProperty(
524
- 'When true, remove this objective from the Run Queue instead of adding or moving it.'
525
- )
794
+ remove: {
795
+ type: 'boolean',
796
+ description:
797
+ 'When true, remove this objective from the Run Queue instead of adding or moving it.'
798
+ }
526
799
  },
527
- ['objectiveId']
528
- )
800
+ required: ['objectiveId'],
801
+ additionalProperties: false
802
+ },
803
+ annotations: {
804
+ readOnlyHint: false,
805
+ destructiveHint: false,
806
+ openWorldHint: false
807
+ }
529
808
  },
530
809
  {
531
810
  name: 'overlord_manage_run_queue',
532
811
  title: 'Manage Run Queues',
533
812
  description:
534
813
  "Use this only when the user explicitly asks to create, rename, pause, resume, delete, or reorder the project's Run Queue definitions, or to retry one held queue entry. The queue-definition actions are administrative project-configuration and require a full-scope token; adding, moving, or removing objectives inside a queue uses overlord_queue_objective and overlord_reorder_run_queue instead.",
535
- inputSchema: objectSchema(
536
- {
814
+ inputSchema: {
815
+ type: 'object',
816
+ properties: {
537
817
  action: {
538
818
  type: 'string',
539
819
  enum: ['create', 'update', 'delete', 'reorder_queues', 'retry_entry'],
540
820
  description:
541
821
  "create a queue, update (rename/pause/resume) one, delete one, reorder the queue definitions, or retry_entry to clear one held entry's hold and attempt budget so the dispatcher tries it again."
542
822
  },
543
- projectId: stringProperty(
544
- 'Project UUID, slug, or name. Required for create and reorder_queues.'
545
- ),
546
- queue: stringProperty(
547
- 'Run Queue UUID or unambiguous name. Required for update and delete.'
548
- ),
549
- name: stringProperty('New queue name for create, or the replacement name for update.'),
550
- paused: booleanProperty(
551
- 'update only: true pauses dispatching from the queue, false resumes it.'
552
- ),
553
- moveEntriesTo: stringProperty(
554
- 'delete only: destination queue UUID or unambiguous name. Required when the queue still holds entries.'
555
- ),
556
- entry: stringProperty(
557
- 'retry_entry only: entry UUID, objective UUID, or objective display id. One of entry or objectiveId is required.'
558
- ),
559
- objectiveId: stringProperty(
560
- 'retry_entry only: objective UUID or display id whose live entry should be retried.'
561
- ),
823
+ projectId: {
824
+ type: 'string',
825
+ description: 'Project UUID, slug, or name. Required for create and reorder_queues.'
826
+ },
827
+ queue: {
828
+ type: 'string',
829
+ description: 'Run Queue UUID or unambiguous name. Required for update and delete.'
830
+ },
831
+ name: {
832
+ type: 'string',
833
+ description: 'New queue name for create, or the replacement name for update.'
834
+ },
835
+ paused: {
836
+ type: 'boolean',
837
+ description: 'update only: true pauses dispatching from the queue, false resumes it.'
838
+ },
839
+ moveEntriesTo: {
840
+ type: 'string',
841
+ description:
842
+ 'delete only: destination queue UUID or unambiguous name. Required when the queue still holds entries.'
843
+ },
844
+ entry: {
845
+ type: 'string',
846
+ description:
847
+ 'retry_entry only: entry UUID, objective UUID, or objective display id. One of entry or objectiveId is required.'
848
+ },
849
+ objectiveId: {
850
+ type: 'string',
851
+ description:
852
+ 'retry_entry only: objective UUID or display id whose live entry should be retried.'
853
+ },
562
854
  orderedQueues: {
563
855
  type: 'array',
564
856
  description:
565
857
  'reorder_queues only: every live queue exactly once, top to bottom, by UUID or unambiguous name. The default queue must stay first.',
566
- items: stringProperty('Run Queue UUID or unambiguous name.')
858
+ items: {
859
+ type: 'string',
860
+ description: 'Run Queue UUID or unambiguous name.'
861
+ }
567
862
  }
568
863
  },
569
- ['action']
570
- )
864
+ required: ['action'],
865
+ additionalProperties: false
866
+ },
867
+ annotations: {
868
+ readOnlyHint: false,
869
+ destructiveHint: false,
870
+ openWorldHint: false
871
+ }
571
872
  },
572
873
  {
573
874
  name: 'overlord_attach_session',
574
875
  title: 'Attach to mission',
575
876
  description:
576
- 'Attach an MCP-hosted agent session to a mission before update/ask/deliver. Pass objectiveId when the caller already knows which objective to execute.',
577
- inputSchema: objectSchema(
578
- {
579
- missionId: stringProperty(
580
- 'Mission UUID or workspace display id. Optional when objectiveId is a display id such as coo:756.k7xm, which already names its mission.'
581
- ),
582
- objectiveId: stringProperty(
583
- 'Optional objective UUID or display id (e.g. coo:756.k7xm). Pins attach to that objective.'
584
- ),
585
- agent: stringProperty(`Agent identifier. Defaults to ${DEFAULT_AGENT}.`),
586
- model: stringProperty('Optional model identifier.'),
587
- executionTargetId: stringProperty(
588
- 'Optional local execution target id for resolving sibling project resource paths.'
589
- )
877
+ 'Use this only after the user asks the connected agent to begin work on a mission. It opens an MCP-hosted session for later updates and delivery. Pass objectiveId when the caller already knows which objective to execute so attach does not rediscover another one.',
878
+ inputSchema: {
879
+ type: 'object',
880
+ properties: {
881
+ missionId: {
882
+ type: 'string',
883
+ description:
884
+ 'Mission UUID or workspace display id. Optional when objectiveId is a display id such as coo:756.k7xm, which already names its mission.'
885
+ },
886
+ objectiveId: {
887
+ type: 'string',
888
+ description:
889
+ 'Objective UUID or display id such as coo:756.k7xm. Pins attach to that objective, and supplies missionId when it is omitted.'
890
+ },
891
+ agent: {
892
+ type: 'string',
893
+ description: 'Agent identifier. Defaults to __OVERLORD_ADAPTER_KEY__.'
894
+ },
895
+ model: {
896
+ type: 'string',
897
+ description: 'Optional model identifier.'
898
+ },
899
+ executionTargetId: {
900
+ type: 'string',
901
+ description:
902
+ 'Optional local execution target id for resolving sibling project resource paths.'
903
+ }
590
904
  },
591
- []
592
- )
905
+ required: [],
906
+ additionalProperties: false
907
+ },
908
+ annotations: {
909
+ readOnlyHint: false,
910
+ destructiveHint: false,
911
+ openWorldHint: false
912
+ }
593
913
  },
594
914
  {
595
915
  name: 'overlord_update_session',
596
916
  title: 'Update mission session',
597
- description: 'Post an update, alert, decision, or discussion summary for an attached session.',
598
- inputSchema: objectSchema(
599
- {
600
- missionId: stringProperty(
601
- 'Mission UUID or workspace display id. Optional when objectiveId is a display id such as coo:756.k7xm, which already names its mission.'
602
- ),
603
- objectiveId: stringProperty(
604
- 'Objective UUID or display id such as coo:756.k7xm. Supplies missionId when it is omitted; the session key still determines which objective the event lands on.'
605
- ),
606
- sessionKey: stringProperty('Session key returned by overlord_attach_session.'),
607
- summary: stringProperty('Update text.'),
608
- phase: stringProperty('Optional protocol phase.'),
609
- eventType: stringProperty('Optional event type. Defaults to update.'),
610
- changeRationales: changeRationalesProperty(
611
- 'Optional reviewer-facing annotations for objective-ledger file evidence.'
612
- )
917
+ description:
918
+ 'Use this only to post the user-requested work update, alert, decision, or discussion summary to an attached mission session.',
919
+ inputSchema: {
920
+ type: 'object',
921
+ properties: {
922
+ missionId: {
923
+ type: 'string',
924
+ description:
925
+ 'Mission UUID or workspace display id. Optional when objectiveId is a display id such as coo:756.k7xm, which already names its mission.'
926
+ },
927
+ objectiveId: {
928
+ type: 'string',
929
+ description:
930
+ 'Objective UUID or display id such as coo:756.k7xm. Supplies missionId when it is omitted; the session key still determines which objective the event lands on.'
931
+ },
932
+ sessionKey: {
933
+ type: 'string',
934
+ description: 'Session key returned by overlord_attach_session.'
935
+ },
936
+ summary: {
937
+ type: 'string',
938
+ description: 'Update text.'
939
+ },
940
+ phase: {
941
+ type: 'string',
942
+ description: 'Optional protocol phase.'
943
+ },
944
+ eventType: {
945
+ type: 'string',
946
+ description: 'Optional event type. Defaults to update.'
947
+ },
948
+ changeRationales: {
949
+ type: 'array',
950
+ description: 'Optional reviewer-facing annotations for objective-ledger file evidence.',
951
+ items: {
952
+ type: 'object',
953
+ properties: {
954
+ filePath: {
955
+ type: 'string',
956
+ description: 'Repository-relative path of the changed file.'
957
+ },
958
+ label: {
959
+ type: 'string',
960
+ description: 'Short reviewer title for the change.'
961
+ },
962
+ summary: {
963
+ type: 'string',
964
+ description: 'What changed in this file.'
965
+ },
966
+ why: {
967
+ type: 'string',
968
+ description: 'Why the change was made.'
969
+ },
970
+ impact: {
971
+ type: 'string',
972
+ description: 'Behavioral impact of the change.'
973
+ },
974
+ hunks: {
975
+ type: 'array',
976
+ description:
977
+ 'Optional diff-hunk headers only; file contents and diffs are prohibited.',
978
+ items: {
979
+ type: 'object',
980
+ properties: {
981
+ header: {
982
+ type: 'string',
983
+ description: 'Unified-diff hunk header.'
984
+ }
985
+ },
986
+ required: ['header'],
987
+ additionalProperties: false
988
+ }
989
+ }
990
+ },
991
+ required: ['filePath', 'label', 'summary', 'why', 'impact'],
992
+ additionalProperties: false
993
+ }
994
+ }
613
995
  },
614
- ['sessionKey', 'summary']
615
- )
996
+ required: ['sessionKey', 'summary'],
997
+ additionalProperties: false
998
+ },
999
+ annotations: {
1000
+ readOnlyHint: false,
1001
+ destructiveHint: false,
1002
+ openWorldHint: false
1003
+ }
616
1004
  },
617
1005
  {
618
1006
  name: 'overlord_deliver_session',
619
1007
  title: 'Deliver mission session',
620
1008
  description:
621
- 'Deliver an attached session with explicit summary, optional change rationales, and optional human-action/tradeoff evidence.',
622
- inputSchema: objectSchema(
623
- {
624
- missionId: stringProperty(
625
- 'Mission UUID or workspace display id. Optional when objectiveId is a display id such as coo:756.k7xm, which already names its mission.'
626
- ),
627
- objectiveId: stringProperty(
628
- 'Objective UUID or display id such as coo:756.k7xm. Supplies missionId when it is omitted; the session key still determines which objective is delivered.'
629
- ),
630
- sessionKey: stringProperty('Session key returned by overlord_attach_session.'),
631
- summary: stringProperty('Delivery summary.'),
1009
+ 'Use this only when the user-requested mission work is complete. It delivers the attached session with an explicit summary, optional file-change rationales, and optional authoritative human-action/tradeoff evidence.',
1010
+ inputSchema: {
1011
+ type: 'object',
1012
+ properties: {
1013
+ missionId: {
1014
+ type: 'string',
1015
+ description:
1016
+ 'Mission UUID or workspace display id. Optional when objectiveId is a display id such as coo:756.k7xm, which already names its mission.'
1017
+ },
1018
+ objectiveId: {
1019
+ type: 'string',
1020
+ description:
1021
+ 'Objective UUID or display id such as coo:756.k7xm. Supplies missionId when it is omitted; the session key still determines which objective is delivered.'
1022
+ },
1023
+ sessionKey: {
1024
+ type: 'string',
1025
+ description: 'Session key returned by overlord_attach_session.'
1026
+ },
1027
+ summary: {
1028
+ type: 'string',
1029
+ description: 'Delivery summary.'
1030
+ },
632
1031
  artifacts: {
633
1032
  type: 'array',
634
- description: 'Optional mission artifacts to persist with this delivery.'
1033
+ description:
1034
+ 'Optional mission artifacts to persist with this delivery. Each artifact has type, label, optional content, and optional HTTP(S) url.',
1035
+ items: {
1036
+ type: 'object',
1037
+ properties: {
1038
+ type: {
1039
+ type: 'string',
1040
+ description:
1041
+ 'Artifact type, such as note, next_steps, test_results, decision, migration, or url.'
1042
+ },
1043
+ label: {
1044
+ type: 'string',
1045
+ description: 'Human-facing artifact label.'
1046
+ },
1047
+ content: {
1048
+ type: 'string',
1049
+ description: 'Optional text or Markdown content.'
1050
+ },
1051
+ url: {
1052
+ type: 'string',
1053
+ description: 'Optional HTTP(S) URL.'
1054
+ }
1055
+ },
1056
+ required: ['type', 'label'],
1057
+ additionalProperties: false
1058
+ }
1059
+ },
1060
+ changeRationales: {
1061
+ type: 'array',
1062
+ description: 'Optional reviewer-facing annotations for objective-ledger file evidence.',
1063
+ items: {
1064
+ type: 'object',
1065
+ properties: {
1066
+ filePath: {
1067
+ type: 'string',
1068
+ description: 'Repository-relative path of the changed file.'
1069
+ },
1070
+ label: {
1071
+ type: 'string',
1072
+ description: 'Short reviewer title for the change.'
1073
+ },
1074
+ summary: {
1075
+ type: 'string',
1076
+ description: 'What changed in this file.'
1077
+ },
1078
+ why: {
1079
+ type: 'string',
1080
+ description: 'Why the change was made.'
1081
+ },
1082
+ impact: {
1083
+ type: 'string',
1084
+ description: 'Behavioral impact of the change.'
1085
+ },
1086
+ hunks: {
1087
+ type: 'array',
1088
+ description:
1089
+ 'Optional diff-hunk headers only; file contents and diffs are prohibited.',
1090
+ items: {
1091
+ type: 'object',
1092
+ properties: {
1093
+ header: {
1094
+ type: 'string',
1095
+ description: 'Unified-diff hunk header.'
1096
+ }
1097
+ },
1098
+ required: ['header'],
1099
+ additionalProperties: false
1100
+ }
1101
+ }
1102
+ },
1103
+ required: ['filePath', 'label', 'summary', 'why', 'impact'],
1104
+ additionalProperties: false
1105
+ }
635
1106
  },
636
- changeRationales: changeRationalesProperty(
637
- 'Optional reviewer-facing annotations for objective-ledger file evidence.'
638
- ),
639
1107
  humanActions: {
640
1108
  type: 'array',
641
1109
  description:
642
- 'Concrete actions a human must perform; exclude Git operations and routine review/testing. ' +
643
- 'Each item needs action, reason, and category, plus command (exact command or setting), verify (how to confirm it worked), and link (HTTP(S) URL or repo-relative path) whenever they exist. ' +
644
- 'Vague: { action: "Set up the env var for Gemini." }. Good: { action: "Add GEMINI_API_KEY to the production backend service on Railway.", reason: "Compose falls back to the raw summary without it.", category: "environment", command: "railway variables set GEMINI_API_KEY=<key> --service backend", verify: "The next delivery card shows a composed presentation.", link: ".env.example" }.',
1110
+ 'Concrete actions a human must perform outside completed agent work. Exclude Git operations and routine review/testing. Each item is read on its own from the delivery card, so give every one an action, reason, and category, plus command, verify, and link whenever they exist. Vague: { action: "Set up the env var for Gemini." }. Good: { action: "Add GEMINI_API_KEY to the production backend service on Railway.", reason: "Compose falls back to the raw summary without it.", category: "environment", command: "railway variables set GEMINI_API_KEY=<key> --service backend", verify: "The next delivery card shows a composed presentation.", link: ".env.example" }.',
645
1111
  items: {
646
1112
  type: 'object',
647
1113
  properties: {
648
1114
  action: {
649
1115
  type: 'string',
650
- description: 'Required. One imperative sentence: what, where, which value.'
1116
+ description:
1117
+ 'Required. One imperative sentence naming what to do, where, and with which value.'
651
1118
  },
652
1119
  reason: {
653
1120
  type: 'string',
654
- description: 'Expected. Why it is needed and what stays broken until done.'
1121
+ description:
1122
+ 'Expected. Why the step is needed and what stays broken until it is done.'
655
1123
  },
656
1124
  category: {
657
1125
  type: 'string',
@@ -664,112 +1132,291 @@ const tools = [
664
1132
  },
665
1133
  command: {
666
1134
  type: 'string',
667
- description: 'Exact command, setting, or value to apply, verbatim.'
1135
+ description:
1136
+ 'The exact command, setting name, or value to apply, verbatim; placeholders in <angle brackets>.'
668
1137
  },
669
- verify: { type: 'string', description: 'How the operator confirms it worked.' },
670
- link: { type: 'string', description: 'HTTP(S) URL or repository-relative file path.' }
1138
+ verify: {
1139
+ type: 'string',
1140
+ description:
1141
+ 'How the operator confirms it worked: a command, a URL, or the state to observe.'
1142
+ },
1143
+ link: {
1144
+ type: 'string',
1145
+ description:
1146
+ 'An HTTP(S) URL or repository-relative file path relevant to the action. No other URI schemes.'
1147
+ }
671
1148
  },
672
- required: ['action']
1149
+ required: ['action'],
1150
+ additionalProperties: false
673
1151
  }
674
1152
  },
675
1153
  tradeoffsMade: {
676
1154
  type: 'array',
677
- description: 'Implementation decisions, alternatives considered, and rationale.'
1155
+ description: 'Implementation decisions and why the chosen approach was preferred.',
1156
+ items: {
1157
+ type: 'object',
1158
+ properties: {
1159
+ decision: {
1160
+ type: 'string',
1161
+ description: 'The chosen implementation decision.'
1162
+ },
1163
+ alternativesConsidered: {
1164
+ type: 'array',
1165
+ items: {
1166
+ type: 'string',
1167
+ description: 'Alternative considered.'
1168
+ }
1169
+ },
1170
+ rationale: {
1171
+ type: 'string',
1172
+ description: 'Why this approach was chosen.'
1173
+ },
1174
+ impact: {
1175
+ type: 'string',
1176
+ description: 'Resulting limitation or consequence.'
1177
+ }
1178
+ },
1179
+ required: [],
1180
+ additionalProperties: false
1181
+ }
1182
+ },
1183
+ knownRisks: {
1184
+ type: 'array',
1185
+ items: {
1186
+ type: 'string',
1187
+ description: 'Residual risk or limitation.'
1188
+ }
678
1189
  },
679
- knownRisks: { type: 'array', description: 'Residual risks or limitations.' },
680
1190
  deferredWork: {
681
1191
  type: 'array',
682
- description:
683
- 'Recommended new objective outside this mission (for example an out-of-scope bug). Name the component or file and why it was left. Omit queued future objectives, leftover current-objective work, and human follow-up (those belong in humanActions).'
1192
+ items: {
1193
+ type: 'string',
1194
+ description:
1195
+ 'Recommended new objective outside this mission (for example an out-of-scope bug). Name the component or file and why it was left. Omit queued future objectives, leftover current-objective work, and human follow-up (those belong in humanActions).'
1196
+ }
684
1197
  },
685
- assumptions: { type: 'array', description: 'Material implementation assumptions.' }
1198
+ assumptions: {
1199
+ type: 'array',
1200
+ items: {
1201
+ type: 'string',
1202
+ description: 'Material implementation assumption.'
1203
+ }
1204
+ }
686
1205
  },
687
- ['sessionKey', 'summary']
688
- )
1206
+ required: ['sessionKey', 'summary'],
1207
+ additionalProperties: false
1208
+ },
1209
+ annotations: {
1210
+ readOnlyHint: false,
1211
+ destructiveHint: false,
1212
+ openWorldHint: false
1213
+ }
689
1214
  },
690
1215
  {
691
1216
  name: 'overlord_add_artifact',
692
1217
  title: 'Add mission artifact',
693
1218
  description:
694
- 'Create a mission artifact during a turn without delivering (plan, notes, decision, URL). Provide type, label, and at least one of contentText or externalUrl. Optional sessionKey stamps provenance. Revise later with overlord_update_artifact.',
695
- inputSchema: objectSchema(
696
- {
697
- missionId: stringProperty(
698
- 'Mission UUID or workspace display id. Optional when objectiveId is a display id such as coo:756.k7xm, which already names its mission.'
699
- ),
700
- objectiveId: stringProperty(
701
- 'Objective UUID or display id such as coo:756.k7xm. Stamps objective provenance when no live sessionKey is available.'
702
- ),
703
- type: stringProperty(
704
- 'Artifact type: test_results, next_steps, note, url, decision, or migration.'
705
- ),
706
- label: stringProperty('Human-facing label.'),
707
- contentText: stringProperty('Optional Markdown/text content.'),
708
- externalUrl: stringProperty('Optional HTTP(S) URL.'),
709
- sessionKey: stringProperty('Optional live session key from attach.')
1219
+ 'Use this to create a mission artifact during a turn without delivering — for example a plan, notes, decision, or URL the reviewer should see while work continues. Provide type, label, and at least one of contentText or externalUrl. Optional sessionKey stamps session/objective provenance. Revise later with overlord_update_artifact. Delivery may still attach more artifacts.',
1220
+ inputSchema: {
1221
+ type: 'object',
1222
+ properties: {
1223
+ missionId: {
1224
+ type: 'string',
1225
+ description:
1226
+ 'Mission UUID or workspace display id. Optional when objectiveId is a display id such as coo:756.k7xm, which already names its mission.'
1227
+ },
1228
+ objectiveId: {
1229
+ type: 'string',
1230
+ description:
1231
+ 'Objective UUID or display id such as coo:756.k7xm. Stamps objective provenance when no live sessionKey is available; sessionKey wins when both are given.'
1232
+ },
1233
+ type: {
1234
+ type: 'string',
1235
+ description: 'Artifact type: test_results, next_steps, note, url, decision, or migration.'
1236
+ },
1237
+ label: {
1238
+ type: 'string',
1239
+ description: 'Human-facing label for the artifact.'
1240
+ },
1241
+ contentText: {
1242
+ type: 'string',
1243
+ description: 'Optional Markdown/text content.'
1244
+ },
1245
+ externalUrl: {
1246
+ type: 'string',
1247
+ description: 'Optional HTTP(S) URL.'
1248
+ },
1249
+ sessionKey: {
1250
+ type: 'string',
1251
+ description:
1252
+ 'Optional live session key from attach; stamps session/objective provenance when present.'
1253
+ }
710
1254
  },
711
- ['type', 'label']
712
- )
1255
+ required: ['type', 'label'],
1256
+ additionalProperties: false
1257
+ },
1258
+ annotations: {
1259
+ readOnlyHint: false,
1260
+ destructiveHint: false,
1261
+ openWorldHint: false
1262
+ }
713
1263
  },
714
1264
  {
715
1265
  name: 'overlord_update_artifact',
716
1266
  title: 'Update mission artifact',
717
1267
  description:
718
- 'Revise an existing mission artifact in place (label, Markdown content, and/or URL) using optimistic concurrency via expectedRevision.',
719
- inputSchema: objectSchema(
720
- {
721
- missionId: stringProperty(
722
- 'Mission UUID or workspace display id. Optional when objectiveId is a display id such as coo:756.k7xm, which already names its mission.'
723
- ),
724
- objectiveId: stringProperty(
725
- 'Objective UUID or display id such as coo:756.k7xm. Used only to supply missionId when it is omitted.'
726
- ),
727
- artifactId: stringProperty('Artifact id from mission context.'),
1268
+ 'Use this when an existing mission artifact must be revised in place (for example a plan written in an earlier objective) rather than delivering a duplicate. Requires the current artifact revision for optimistic concurrency. Provide at least one of label, contentText, or externalUrl.',
1269
+ inputSchema: {
1270
+ type: 'object',
1271
+ properties: {
1272
+ missionId: {
1273
+ type: 'string',
1274
+ description:
1275
+ 'Mission UUID or workspace display id. Optional when objectiveId is a display id such as coo:756.k7xm, which already names its mission.'
1276
+ },
1277
+ objectiveId: {
1278
+ type: 'string',
1279
+ description:
1280
+ 'Objective UUID or display id such as coo:756.k7xm. Used only to supply missionId when it is omitted.'
1281
+ },
1282
+ artifactId: {
1283
+ type: 'string',
1284
+ description: 'Artifact id from mission context or load-context artifacts.'
1285
+ },
728
1286
  expectedRevision: {
729
1287
  type: 'number',
730
1288
  description: 'Current artifact.revision. Stale values return a conflict error.'
731
1289
  },
732
- label: stringProperty('Optional new human-facing label.'),
733
- contentText: stringProperty('Optional new Markdown/text content.'),
734
- externalUrl: stringProperty('Optional HTTP(S) URL.')
1290
+ label: {
1291
+ type: 'string',
1292
+ description: 'Optional new human-facing label.'
1293
+ },
1294
+ contentText: {
1295
+ type: 'string',
1296
+ description:
1297
+ 'Optional new Markdown/text content. Pass an empty string to clear text content.'
1298
+ },
1299
+ externalUrl: {
1300
+ type: 'string',
1301
+ description: 'Optional HTTP(S) URL. Pass an empty string to clear the external URL.'
1302
+ }
735
1303
  },
736
- ['artifactId', 'expectedRevision']
737
- )
1304
+ required: ['artifactId', 'expectedRevision'],
1305
+ additionalProperties: false
1306
+ },
1307
+ annotations: {
1308
+ readOnlyHint: false,
1309
+ destructiveHint: false,
1310
+ openWorldHint: false
1311
+ }
738
1312
  },
739
1313
  {
740
1314
  name: 'overlord_record_work',
741
1315
  title: 'Record completed work as a mission',
742
1316
  description:
743
- 'Record work already completed in this chat as a mission that lands in review — one call, no attach/deliver cycle. Accepts optional file-change rationales and runs the delivery through the standard Gemini summarizer.',
744
- inputSchema: objectSchema(
745
- {
746
- projectId: stringProperty('Overlord project id, slug, or name.'),
747
- objective: stringProperty('What was asked and done, phrased as a completed objective.'),
748
- summary: stringProperty('Reviewer-facing narrative of what changed and why.'),
749
- title: stringProperty('Optional mission title.'),
750
- changeRationales: changeRationalesProperty(
751
- 'One optional reviewer annotation per meaningful file change.'
752
- ),
1317
+ 'Use this to log work already finished in this chat as a completed Overlord mission — one call, no attach/deliver cycle. It creates a mission and a single completed objective, records the file changes and their rationales, lands the mission in the review column, and runs the delivery through the standard Gemini summarizer so it reads like any other delivered mission. Provide an objective (what was asked/done) and a reviewer-facing summary; optional changeRationales may annotate meaningful file changes. Only use this when the work is genuinely complete; use overlord_create_mission for work still to be done.',
1318
+ inputSchema: {
1319
+ type: 'object',
1320
+ properties: {
1321
+ projectId: {
1322
+ type: 'string',
1323
+ description:
1324
+ 'Overlord project id, slug, or name. Overlord never chooses a project implicitly.'
1325
+ },
1326
+ objective: {
1327
+ type: 'string',
1328
+ description: 'What was asked and done, phrased as a completed objective (1-3 sentences).'
1329
+ },
1330
+ summary: {
1331
+ type: 'string',
1332
+ description: 'Reviewer-facing narrative of what changed and why.'
1333
+ },
1334
+ title: {
1335
+ type: 'string',
1336
+ description: 'Optional mission title; defaults to a title derived from the objective.'
1337
+ },
1338
+ changeRationales: {
1339
+ type: 'array',
1340
+ description: 'One optional reviewer annotation per meaningful file change.',
1341
+ items: {
1342
+ type: 'object',
1343
+ properties: {
1344
+ filePath: {
1345
+ type: 'string',
1346
+ description: 'Repository-relative path of the changed file.'
1347
+ },
1348
+ label: {
1349
+ type: 'string',
1350
+ description: 'Short reviewer title for the change.'
1351
+ },
1352
+ summary: {
1353
+ type: 'string',
1354
+ description: 'What changed in this file.'
1355
+ },
1356
+ why: {
1357
+ type: 'string',
1358
+ description: 'Why the change was made.'
1359
+ },
1360
+ impact: {
1361
+ type: 'string',
1362
+ description: 'Behavioral impact of the change.'
1363
+ },
1364
+ hunks: {
1365
+ type: 'array',
1366
+ description:
1367
+ 'Optional diff-hunk headers only; file contents and diffs are prohibited.',
1368
+ items: {
1369
+ type: 'object',
1370
+ properties: {
1371
+ header: {
1372
+ type: 'string',
1373
+ description: 'Unified-diff hunk header.'
1374
+ }
1375
+ },
1376
+ required: ['header'],
1377
+ additionalProperties: false
1378
+ }
1379
+ }
1380
+ },
1381
+ required: ['filePath', 'label', 'summary', 'why', 'impact'],
1382
+ additionalProperties: false
1383
+ }
1384
+ },
753
1385
  changedFiles: {
754
1386
  type: 'array',
755
1387
  description: 'Optional explicit file observations for this sessionless record.',
756
- items: objectSchema(
757
- {
758
- filePath: stringProperty('Repository-relative path.'),
759
- vcsStatus: stringProperty('Optional VCS status such as M, A, or D.')
1388
+ items: {
1389
+ type: 'object',
1390
+ properties: {
1391
+ filePath: {
1392
+ type: 'string',
1393
+ description: 'Repository-relative path.'
1394
+ },
1395
+ vcsStatus: {
1396
+ type: 'string',
1397
+ description: 'Optional VCS status such as M, A, or D.'
1398
+ }
760
1399
  },
761
- ['filePath']
762
- )
1400
+ required: ['filePath'],
1401
+ additionalProperties: false
1402
+ }
763
1403
  },
764
1404
  artifacts: {
765
1405
  type: 'array',
766
1406
  description: 'Optional artifacts: next_steps, test_results, decision, note, or url.'
767
1407
  }
768
1408
  },
769
- ['projectId', 'objective', 'summary']
770
- )
1409
+ required: ['projectId', 'objective', 'summary'],
1410
+ additionalProperties: false
1411
+ },
1412
+ annotations: {
1413
+ readOnlyHint: false,
1414
+ destructiveHint: false,
1415
+ openWorldHint: false
1416
+ }
771
1417
  }
772
1418
  ];
1419
+ // END GENERATED MCP TOOL CATALOG
773
1420
 
774
1421
  function optionalString(args, name) {
775
1422
  const value = args?.[name];
@@ -981,13 +1628,15 @@ async function callOverlordTool(name, args) {
981
1628
  });
982
1629
  }
983
1630
  if (name === 'overlord_update_objective') {
1631
+ const hasTitle = typeof args.title === 'string';
984
1632
  const hasAutoAdvance = typeof args.autoAdvance === 'boolean';
985
1633
  const hasInstructionText = typeof args.instructionText === 'string';
986
- if (!hasAutoAdvance && !hasInstructionText) {
987
- throw new Error('Provide autoAdvance and/or instructionText');
1634
+ if (!hasTitle && !hasAutoAdvance && !hasInstructionText) {
1635
+ throw new Error('Provide title, autoAdvance, and/or instructionText');
988
1636
  }
989
1637
  return runProtocol('update-objective', {
990
1638
  'objective-id': requiredString(args, 'objectiveId'),
1639
+ ...(hasTitle ? { title: args.title } : {}),
991
1640
  ...(hasAutoAdvance
992
1641
  ? args.autoAdvance
993
1642
  ? { 'auto-advance': true }
@@ -1271,7 +1920,7 @@ process.stdin.on('data', async chunk => {
1271
1920
  result: {
1272
1921
  protocolVersion: PROTOCOL_VERSION,
1273
1922
  capabilities: { tools: { listChanged: false } },
1274
- serverInfo: { name: 'overlord-__OVERLORD_ADAPTER_KEY__', version: '0.3.51' }
1923
+ serverInfo: { name: 'overlord-__OVERLORD_ADAPTER_KEY__', version: '0.3.53' }
1275
1924
  }
1276
1925
  });
1277
1926
  continue;