overlord-cli 0.2605312007.1 → 0.2606010745.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.
package/README.md CHANGED
@@ -74,6 +74,9 @@ ovld protocol search-tickets --query "auth refactor" --status next-up,execute
74
74
  ovld protocol update --session-key <session-key> --ticket-id <ticket_id> --summary "Working on it" --phase execute
75
75
  ovld protocol heartbeat --session-key <session-key> --ticket-id <ticket_id> --phase execute --percent 50 --note "Running tests"
76
76
  ovld runner start
77
+ ovld runner status
78
+ ovld runner clear <objective_id>
79
+ ovld runner clear-all
77
80
  ovld setup
78
81
  ovld setup codex
79
82
  ovld setup claude
@@ -148,12 +151,12 @@ Agents can find docs here: https://www.ovld.ai/docs/for-agents
148
151
  - `attachment-upload-file` - prepare, upload, and finalize a local objective attachment in one command
149
152
  - `get-device` / `update-device` - register the caller machine (per organization + user + fingerprint) and rename its label
150
153
  - `list-project-resources` / `add-project-resource` / `update-project-resource` - manage filesystem directories tied to a project device
151
- - `request-execution` / `claim-execution` / `complete-execution-launch` / `fail-execution-launch` - durable runner queue operations used by auto-advance and manual Run
154
+ - `request-execution` / `claim-execution` / `list-execution-requests` / `clear-execution-requests` / `complete-execution-launch` / `fail-execution-launch` - durable runner queue operations used by auto-advance and manual Run
152
155
  - `list-organizations` - list every organization the authenticated user (or agent token) belongs to; the runner uses this to poll all of your organizations, not just the one stored at login
153
156
 
154
157
  Devices are keyed by **(organization, user, fingerprint)** so the same physical workstation can appear once per org session.
155
158
 
156
- `ovld runner start` keeps a foreground runner alive for CLI-only or remote hosts. It claims compatible execution requests for the current device and launches the assigned agent/model with `ovld launch`; `ovld runner once` claims at most one request and exits. By default a single runner drains queued requests from **every organization you belong to**, so you do not need one runner per org. Pin it to a single org with `--organization-id <id>` or `OVERLORD_ORGANIZATION_ID`.
159
+ `ovld runner start` keeps a foreground runner alive for CLI-only or remote hosts. It claims compatible execution requests for the current device and launches the assigned agent/model with `ovld launch`; `ovld runner once` claims at most one request and exits. `ovld runner status` now prints the local device record plus the active queue visible to that runner. `ovld runner clear <objective_id>` clears one queued objective, and `ovld runner clear-all` clears every active queue row visible to the caller. By default a single runner drains queued requests from **every organization you belong to**, so you do not need one runner per org. Pin it to a single org with `--organization-id <id>` or `OVERLORD_ORGANIZATION_ID`.
157
160
 
158
161
  Use `create` for future work you want to track, `prompt` for work that should start immediately, and `record-work` for work that was already completed in chat and now needs a review ticket plus feed post. Use multiple tickets when prompts represent different features or goals; use `add-objectives` or `--objectives-json '[{"objective":"Step one"},{"objective":"Step two"}]'` when prompts are sequential steps toward the same feature or goal.
159
162
 
@@ -2067,6 +2067,58 @@ async function protocolListOrganizations(args) {
2067
2067
  console.log(JSON.stringify(data, null, 2));
2068
2068
  }
2069
2069
 
2070
+ async function protocolListExecutionRequests(args) {
2071
+ const flags = parseFlags(args);
2072
+ const { platformUrl, bearerToken, localSecret, organizationId } =
2073
+ await resolveProtocolAuthForFlags(flags);
2074
+ const timeoutMs = resolveTimeout(flags);
2075
+
2076
+ const data = await apiPost(
2077
+ platformUrl,
2078
+ bearerToken,
2079
+ localSecret,
2080
+ organizationId,
2081
+ '/api/protocol/list-execution-requests',
2082
+ {
2083
+ ...(typeof flags['device-fingerprint'] === 'string'
2084
+ ? { deviceFingerprint: flags['device-fingerprint'] }
2085
+ : {}),
2086
+ ...(typeof flags['project-id'] === 'string' ? { projectId: flags['project-id'] } : {})
2087
+ },
2088
+ timeoutMs
2089
+ );
2090
+ console.log(JSON.stringify(data, null, 2));
2091
+ }
2092
+
2093
+ async function protocolClearExecutionRequests(args) {
2094
+ const flags = parseFlags(args);
2095
+ const { platformUrl, bearerToken, localSecret, organizationId } =
2096
+ await resolveProtocolAuthForFlags(flags);
2097
+ const timeoutMs = resolveTimeout(flags);
2098
+
2099
+ const clearAll = flags['clear-all'] === true || flags['clear-all'] === 'true';
2100
+ const objectiveId = typeof flags['objective-id'] === 'string' ? flags['objective-id'].trim() : '';
2101
+ if (!clearAll && !objectiveId) {
2102
+ console.error('Error: --objective-id is required unless --clear-all is set');
2103
+ process.exit(1);
2104
+ }
2105
+
2106
+ const data = await apiPost(
2107
+ platformUrl,
2108
+ bearerToken,
2109
+ localSecret,
2110
+ organizationId,
2111
+ '/api/protocol/clear-execution-requests',
2112
+ {
2113
+ ...(objectiveId ? { objectiveId } : {}),
2114
+ ...(clearAll ? { clearAll: true } : {}),
2115
+ ...(typeof flags['project-id'] === 'string' ? { projectId: flags['project-id'] } : {})
2116
+ },
2117
+ timeoutMs
2118
+ );
2119
+ console.log(JSON.stringify(data, null, 2));
2120
+ }
2121
+
2070
2122
  async function protocolCompleteExecutionLaunch(args) {
2071
2123
  const flags = parseFlags(args);
2072
2124
  const { platformUrl, bearerToken, localSecret, organizationId } =
@@ -2663,6 +2715,8 @@ Subcommands:
2663
2715
  request-execution Queue an objective for local/remote runner execution
2664
2716
  claim-execution Claim one queued execution request for this device
2665
2717
  list-organizations List organizations the authenticated user belongs to
2718
+ list-execution-requests List active execution requests in the runner queue
2719
+ clear-execution-requests Clear active execution requests by objective or wholesale
2666
2720
  complete-execution-launch Mark a claimed execution request launched
2667
2721
  fail-execution-launch Mark a claimed execution request failed
2668
2722
  permission-request Notify Overlord that the agent is requesting tool permission
@@ -3164,6 +3218,25 @@ list-organizations:
3164
3218
  The runner uses this to poll all of your organizations, not just the one
3165
3219
  stored at login. Takes no required flags.
3166
3220
 
3221
+ list-execution-requests:
3222
+ Purpose:
3223
+ List active execution requests ('queued', 'claimed', 'launching') visible to
3224
+ the caller. When --device-fingerprint is provided, queued rows are filtered
3225
+ to work this execution target could claim and in-flight rows are limited to
3226
+ rows already claimed by this target.
3227
+ Optional:
3228
+ --device-fingerprint <fp> Filter queue visibility to one execution target
3229
+ --project-id <uuid> Restrict to one project
3230
+
3231
+ clear-execution-requests:
3232
+ Purpose:
3233
+ Clear active execution requests from the runner queue by marking them failed.
3234
+ Required:
3235
+ --objective-id <uuid> Clear one objective's active request
3236
+ or: --clear-all Clear every active request visible to the caller
3237
+ Optional:
3238
+ --project-id <uuid> Restrict clear-all to one project
3239
+
3167
3240
  complete-execution-launch:
3168
3241
  Required:
3169
3242
  --request-id <uuid> (or EXECUTION_REQUEST_ID env var)
@@ -3210,6 +3283,9 @@ Examples:
3210
3283
  ovld protocol request-execution --ticket-id 1:899 --agent codex --requested-from manual_run
3211
3284
  ovld protocol claim-execution --device-fingerprint $OVERLORD_DEVICE_FINGERPRINT
3212
3285
  ovld protocol list-organizations
3286
+ ovld protocol list-execution-requests --device-fingerprint $OVERLORD_DEVICE_FINGERPRINT
3287
+ ovld protocol clear-execution-requests --objective-id <objective-uuid>
3288
+ ovld protocol clear-execution-requests --clear-all
3213
3289
  ovld protocol deliver --session-key <key> --ticket-id <ticket_id> --summary "Done"
3214
3290
  ovld protocol deliver --session-key <key> --ticket-id <ticket_id> --summary "Done" --artifacts-file ./artifacts.json
3215
3291
  ovld protocol deliver --session-key <key> --ticket-id <ticket_id> --payload-json '{"summary":"Done","artifacts":[{"type":"note","label":"Delivery","content":"..."}]}'
@@ -3333,6 +3409,14 @@ EOF
3333
3409
  await protocolListOrganizations(args);
3334
3410
  return;
3335
3411
  }
3412
+ if (subcommand === 'list-execution-requests') {
3413
+ await protocolListExecutionRequests(args);
3414
+ return;
3415
+ }
3416
+ if (subcommand === 'clear-execution-requests') {
3417
+ await protocolClearExecutionRequests(args);
3418
+ return;
3419
+ }
3336
3420
  if (subcommand === 'complete-execution-launch') {
3337
3421
  await protocolCompleteExecutionLaunch(args);
3338
3422
  return;
@@ -22,6 +22,8 @@ function printRunnerHelp(primaryCommand = 'ovld') {
22
22
  ${primaryCommand} runner once [options]
23
23
  ${primaryCommand} runner start [options]
24
24
  ${primaryCommand} runner status [options]
25
+ ${primaryCommand} runner clear <objective_id> [options]
26
+ ${primaryCommand} runner clear-all [options]
25
27
 
26
28
  Options:
27
29
  --device-fingerprint <fp> Override runner device identity
@@ -114,6 +116,37 @@ function claimExecution(flags, deviceFingerprint, organizationId) {
114
116
  return protocolJson('claim-execution', args, { OVERLORD_DEVICE_FINGERPRINT: deviceFingerprint });
115
117
  }
116
118
 
119
+ function listExecutionRequests(flags, deviceFingerprint, organizationId) {
120
+ const args = ['--device-fingerprint', deviceFingerprint];
121
+ if (organizationId) {
122
+ args.push('--organization-id', String(organizationId));
123
+ }
124
+ if (typeof flags['project-id'] === 'string') {
125
+ args.push('--project-id', flags['project-id']);
126
+ }
127
+ return protocolJson('list-execution-requests', args, {
128
+ OVERLORD_DEVICE_FINGERPRINT: deviceFingerprint
129
+ });
130
+ }
131
+
132
+ function clearExecutionRequests(flags, deviceFingerprint, organizationId, options = {}) {
133
+ const args = [];
134
+ if (organizationId) {
135
+ args.push('--organization-id', String(organizationId));
136
+ }
137
+ if (typeof flags['project-id'] === 'string') {
138
+ args.push('--project-id', flags['project-id']);
139
+ }
140
+ if (options.clearAll) {
141
+ args.push('--clear-all');
142
+ } else if (options.objectiveId) {
143
+ args.push('--objective-id', options.objectiveId);
144
+ }
145
+ return protocolJson('clear-execution-requests', args, {
146
+ OVERLORD_DEVICE_FINGERPRINT: deviceFingerprint
147
+ });
148
+ }
149
+
117
150
  function listOrganizationIds(deviceFingerprint) {
118
151
  const data = protocolJson('list-organizations', [], {
119
152
  OVERLORD_DEVICE_FINGERPRINT: deviceFingerprint
@@ -466,6 +499,58 @@ function sleep(ms) {
466
499
  return new Promise(resolve => setTimeout(resolve, ms));
467
500
  }
468
501
 
502
+ async function collectQueue(flags, deviceFingerprint, organizationScope) {
503
+ const scope = organizationScope ?? createOrganizationScope(flags, deviceFingerprint);
504
+ const queue = [];
505
+ const errors = [];
506
+
507
+ for (const organizationId of scope.resolve()) {
508
+ try {
509
+ const data = listExecutionRequests(flags, deviceFingerprint, organizationId);
510
+ for (const request of data.requests ?? []) {
511
+ queue.push({
512
+ organizationId: organizationId || null,
513
+ ...request
514
+ });
515
+ }
516
+ } catch (error) {
517
+ errors.push({
518
+ organizationId: organizationId || null,
519
+ error: error instanceof Error ? error.message : String(error)
520
+ });
521
+ }
522
+ }
523
+
524
+ return { queue, errors, pinned: scope.pinned };
525
+ }
526
+
527
+ async function clearQueue(flags, deviceFingerprint, organizationScope, options) {
528
+ const scope = organizationScope ?? createOrganizationScope(flags, deviceFingerprint);
529
+ let clearedCount = 0;
530
+ const cleared = [];
531
+ const errors = [];
532
+
533
+ for (const organizationId of scope.resolve()) {
534
+ try {
535
+ const data = clearExecutionRequests(flags, deviceFingerprint, organizationId, options);
536
+ clearedCount += data.clearedCount ?? 0;
537
+ for (const request of data.requests ?? []) {
538
+ cleared.push({
539
+ organizationId: organizationId || null,
540
+ ...request
541
+ });
542
+ }
543
+ } catch (error) {
544
+ errors.push({
545
+ organizationId: organizationId || null,
546
+ error: error instanceof Error ? error.message : String(error)
547
+ });
548
+ }
549
+ }
550
+
551
+ return { clearedCount, cleared, errors, pinned: scope.pinned };
552
+ }
553
+
469
554
  export async function runRunnerCommand(subcommand, args, primaryCommand = 'ovld') {
470
555
  if (!subcommand || subcommand === 'help' || subcommand === '--help' || subcommand === '-h') {
471
556
  printRunnerHelp(primaryCommand);
@@ -476,6 +561,7 @@ export async function runRunnerCommand(subcommand, args, primaryCommand = 'ovld'
476
561
  const deviceFingerprint = readOrCreateDeviceFingerprint(flags);
477
562
 
478
563
  if (subcommand === 'status') {
564
+ const organizationScope = createOrganizationScope(flags, deviceFingerprint);
479
565
  const data = protocolJson(
480
566
  'get-device',
481
567
  [
@@ -488,7 +574,38 @@ export async function runRunnerCommand(subcommand, args, primaryCommand = 'ovld'
488
574
  ],
489
575
  { OVERLORD_DEVICE_FINGERPRINT: deviceFingerprint }
490
576
  );
491
- console.log(JSON.stringify({ ok: true, device: data.device }, null, 2));
577
+ const queue = await collectQueue(flags, deviceFingerprint, organizationScope);
578
+ console.log(
579
+ JSON.stringify(
580
+ {
581
+ ok: true,
582
+ device: data.device,
583
+ queue: queue.queue,
584
+ queueErrors: queue.errors
585
+ },
586
+ null,
587
+ 2
588
+ )
589
+ );
590
+ return;
591
+ }
592
+
593
+ if (subcommand === 'clear') {
594
+ const objectiveId = typeof args[0] === 'string' && !args[0].startsWith('--') ? args[0] : '';
595
+ if (!objectiveId) {
596
+ console.error(`Usage: ${primaryCommand} runner clear <objective_id> [options]`);
597
+ process.exit(1);
598
+ }
599
+ const remainingArgs = objectiveId ? args.slice(1) : args;
600
+ const clearFlags = parseFlags(remainingArgs);
601
+ const queue = await clearQueue(clearFlags, deviceFingerprint, null, { objectiveId });
602
+ console.log(JSON.stringify({ ok: true, ...queue }, null, 2));
603
+ return;
604
+ }
605
+
606
+ if (subcommand === 'clear-all') {
607
+ const queue = await clearQueue(flags, deviceFingerprint, null, { clearAll: true });
608
+ console.log(JSON.stringify({ ok: true, ...queue }, null, 2));
492
609
  return;
493
610
  }
494
611
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "overlord-cli",
3
- "version": "0.2605312007.1",
3
+ "version": "0.2606010745.0",
4
4
  "description": "Overlord CLI — launch AI agents on tickets from anywhere",
5
5
  "homepage": "https://www.ovld.ai/docs/",
6
6
  "type": "module",
@@ -1054,6 +1054,40 @@ const tools = [
1054
1054
  }),
1055
1055
  subcommand: 'claim-execution'
1056
1056
  },
1057
+ {
1058
+ name: 'list_execution_requests',
1059
+ description: 'List active execution requests in the local runner queue.',
1060
+ inputSchema: {
1061
+ type: 'object',
1062
+ properties: {
1063
+ device_fingerprint: { type: 'string' },
1064
+ project_id: { type: 'string' }
1065
+ }
1066
+ },
1067
+ toCliFlags: args => ({
1068
+ 'device-fingerprint': args.device_fingerprint,
1069
+ 'project-id': args.project_id
1070
+ }),
1071
+ subcommand: 'list-execution-requests'
1072
+ },
1073
+ {
1074
+ name: 'clear_execution_requests',
1075
+ description: 'Clear active execution requests from the local runner queue.',
1076
+ inputSchema: {
1077
+ type: 'object',
1078
+ properties: {
1079
+ objective_id: { type: 'string' },
1080
+ clear_all: { type: 'boolean' },
1081
+ project_id: { type: 'string' }
1082
+ }
1083
+ },
1084
+ toCliFlags: args => ({
1085
+ 'objective-id': args.objective_id,
1086
+ ...(args.clear_all ? { 'clear-all': true } : {}),
1087
+ 'project-id': args.project_id
1088
+ }),
1089
+ subcommand: 'clear-execution-requests'
1090
+ },
1057
1091
  {
1058
1092
  name: 'complete_execution_launch',
1059
1093
  description: 'Mark a claimed execution request as launched.',
@@ -4,7 +4,7 @@
4
4
  - Hosted Overlord MCP (`/functions/v1/mcp`) uses camelCase JSON keys (`ticketId`, `sessionKey`, `deviceFingerprint`) matching `POST /api/protocol/*` bodies. The local shim uses snake_case keys mapped to CLI flags (`ticket_id`, `session_key`, `device_fingerprint`). Some local-only operations (`connect`, `load_ticket_context`, `revert`, `prompt`, runner queue tools) intentionally remain out of hosted MCP for now.
5
5
  - `discover_project` accepts an explicit project id (`projectId` hosted, `project_id` local shim) or a working directory (`workingDirectory` hosted, `working_directory` local shim). When resolving by directory and a device fingerprint is available, include `deviceFingerprint` / `device_fingerprint` so resource-directory matching prefers the current device.
6
6
  - `permission-request` is invoked by the Claude Code permission hook installed by the bundle. Agents do not normally call it directly.
7
- - Execution request tools (`request_execution`, `claim_execution`, `complete_execution_launch`, `fail_execution_launch`) back the local runner queue. Agents normally work tickets with `attach`/`update`/`deliver`; runner processes use these queue tools.
7
+ - Execution request tools (`request_execution`, `claim_execution`, `list_execution_requests`, `clear_execution_requests`, `complete_execution_launch`, `fail_execution_launch`) back the local runner queue. Agents normally work tickets with `attach`/`update`/`deliver`; runner processes use these queue tools.
8
8
  - `record_change_rationales` (MCP) and `ovld protocol record-change-rationales` (CLI) both write to the same `file_changes` table. The dedicated CLI route is `POST /api/protocol/record-change-rationales`.
9
9
  - Objective attachment tools follow the `<verb>_<noun>` MCP naming: `list_attachments`, `prepare_attachment_upload`, `finalize_attachment_upload`, `get_attachment_download_url`, `upload_attachment_file`. CLI commands use `attachment-*`. `ticket_id` / `ticketId` is optional for attachment calls when the objective or attachment id lets the server derive ticket scope.
10
10
  - "Artifacts" in `deliver` are the structured records an agent submits at delivery time (next_steps, test_results, migration, decision, note, url) — not user-uploaded files. Files attached by users live on objectives via the attachment tools above.
@@ -4,7 +4,7 @@
4
4
  - Hosted Overlord MCP (`/functions/v1/mcp`) uses camelCase JSON keys (`ticketId`, `sessionKey`, `deviceFingerprint`) matching `POST /api/protocol/*` bodies. The local shim uses snake_case keys mapped to CLI flags (`ticket_id`, `session_key`, `device_fingerprint`). Some local-only operations (`connect`, `load_ticket_context`, `revert`, `prompt`, runner queue tools) intentionally remain out of hosted MCP for now.
5
5
  - `discover_project` accepts an explicit project id (`projectId` hosted, `project_id` local shim) or a working directory (`workingDirectory` hosted, `working_directory` local shim). When resolving by directory and a device fingerprint is available, include `deviceFingerprint` / `device_fingerprint` so resource-directory matching prefers the current device.
6
6
  - `permission-request` is invoked by the Cursor permission hook installed by the bundle. Agents do not normally call it directly.
7
- - Execution request tools (`request_execution`, `claim_execution`, `complete_execution_launch`, `fail_execution_launch`) back the local runner queue. Agents normally work tickets with `attach`/`update`/`deliver`; runner processes use these queue tools.
7
+ - Execution request tools (`request_execution`, `claim_execution`, `list_execution_requests`, `clear_execution_requests`, `complete_execution_launch`, `fail_execution_launch`) back the local runner queue. Agents normally work tickets with `attach`/`update`/`deliver`; runner processes use these queue tools.
8
8
  - `record_change_rationales` (MCP) and `ovld protocol record-change-rationales` (CLI) both write to the same `file_changes` table. The dedicated CLI route is `POST /api/protocol/record-change-rationales`.
9
9
  - Objective attachment tools follow the `<verb>_<noun>` MCP naming: `list_attachments`, `prepare_attachment_upload`, `finalize_attachment_upload`, `get_attachment_download_url`, `upload_attachment_file`. CLI commands use `attachment-*`. `ticket_id` / `ticketId` is optional for attachment calls when the objective or attachment id lets the server derive ticket scope.
10
10
  - "Artifacts" in `deliver` are the structured records an agent submits at delivery time (next_steps, test_results, migration, decision, note, url) — not user-uploaded files. Files attached by users live on objectives via the attachment tools above.
@@ -1009,6 +1009,40 @@ const tools = [
1009
1009
  }),
1010
1010
  subcommand: 'claim-execution'
1011
1011
  },
1012
+ {
1013
+ name: 'list_execution_requests',
1014
+ description: 'List active execution requests in the local runner queue.',
1015
+ inputSchema: {
1016
+ type: 'object',
1017
+ properties: {
1018
+ device_fingerprint: { type: 'string' },
1019
+ project_id: { type: 'string' }
1020
+ }
1021
+ },
1022
+ toCliFlags: args => ({
1023
+ 'device-fingerprint': args.device_fingerprint,
1024
+ 'project-id': args.project_id
1025
+ }),
1026
+ subcommand: 'list-execution-requests'
1027
+ },
1028
+ {
1029
+ name: 'clear_execution_requests',
1030
+ description: 'Clear active execution requests from the local runner queue.',
1031
+ inputSchema: {
1032
+ type: 'object',
1033
+ properties: {
1034
+ objective_id: { type: 'string' },
1035
+ clear_all: { type: 'boolean' },
1036
+ project_id: { type: 'string' }
1037
+ }
1038
+ },
1039
+ toCliFlags: args => ({
1040
+ 'objective-id': args.objective_id,
1041
+ ...(args.clear_all ? { 'clear-all': true } : {}),
1042
+ 'project-id': args.project_id
1043
+ }),
1044
+ subcommand: 'clear-execution-requests'
1045
+ },
1012
1046
  {
1013
1047
  name: 'complete_execution_launch',
1014
1048
  description: 'Mark a claimed execution request as launched.',
@@ -4,7 +4,7 @@
4
4
  - Hosted Overlord MCP (`/functions/v1/mcp`) uses camelCase JSON keys (`ticketId`, `sessionKey`, `deviceFingerprint`) matching `POST /api/protocol/*` bodies. The local shim uses snake_case keys mapped to CLI flags (`ticket_id`, `session_key`, `device_fingerprint`). Some local-only operations (`connect`, `load_ticket_context`, `revert`, `prompt`, runner queue tools) intentionally remain out of hosted MCP for now.
5
5
  - `discover_project` accepts an explicit project id (`projectId` hosted, `project_id` local shim) or a working directory (`workingDirectory` hosted, `working_directory` local shim). When resolving by directory and a device fingerprint is available, include `deviceFingerprint` / `device_fingerprint` so resource-directory matching prefers the current device.
6
6
  - `permission-request` is invoked by the Codex permission hook installed by the bundle. Agents do not normally call it directly.
7
- - Execution request tools (`request_execution`, `claim_execution`, `complete_execution_launch`, `fail_execution_launch`) back the local runner queue. Agents normally work tickets with `attach`/`update`/`deliver`; runner processes use these queue tools.
7
+ - Execution request tools (`request_execution`, `claim_execution`, `list_execution_requests`, `clear_execution_requests`, `complete_execution_launch`, `fail_execution_launch`) back the local runner queue. Agents normally work tickets with `attach`/`update`/`deliver`; runner processes use these queue tools.
8
8
  - `record_change_rationales` (MCP) and `ovld protocol record-change-rationales` (CLI) both write to the same `file_changes` table. The dedicated CLI route is `POST /api/protocol/record-change-rationales`.
9
9
  - Objective attachment tools follow the `<verb>_<noun>` MCP naming: `list_attachments`, `prepare_attachment_upload`, `finalize_attachment_upload`, `get_attachment_download_url`, `upload_attachment_file`. CLI commands use `attachment-*`. `ticket_id` / `ticketId` is optional for attachment calls when the objective or attachment id lets the server derive ticket scope.
10
10
  - "Artifacts" in `deliver` are the structured records an agent submits at delivery time (next_steps, test_results, migration, decision, note, url) — not user-uploaded files. Files attached by users live on objectives via the attachment tools above.