overlord-cli 0.2605300746.0 → 0.2605311843.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
@@ -72,6 +72,7 @@ ovld protocol discover-project --working-directory /path/to/repo --device-finger
72
72
  ovld protocol attach --ticket-id <ticket_id>
73
73
  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
+ ovld protocol heartbeat --session-key <session-key> --ticket-id <ticket_id> --phase execute --percent 50 --note "Running tests"
75
76
  ovld runner start
76
77
  ovld setup
77
78
  ovld setup codex
@@ -133,6 +134,7 @@ Agents can find docs here: https://www.ovld.ai/docs/for-agents
133
134
  - `prompt` - create a ticket and attach to it immediately (`spawn` is a backward-compatible alias)
134
135
  - `record-work` - record already-completed chat work as a ticket in review with a completed objective and trigger feed-post generation
135
136
  - `update` - post progress, discussion/decision events, optional change rationales, and explicit `--begin-follow-up-work` transitions
137
+ - `heartbeat` - send a lightweight liveness ping plus optional transient `phase` / `percent` / `note` telemetry without creating a ticket event
136
138
  - `record-change-rationales` - persist structured change rationales without a normal progress update
137
139
  - `ask` - post a blocking question and move the ticket to review
138
140
  - `permission-request` - notify Overlord that the agent is requesting tool permission
@@ -156,7 +158,7 @@ Use `create` for future work you want to track, `prompt` for work that should st
156
158
 
157
159
  `ovld protocol deliver` accepts either discrete flags like `--summary` / `--artifacts-json`, an inline full payload with `--payload-json '{"summary":"...","artifacts":[...],"changeRationales":[...]}'`, or a file/stdin payload with `--payload-file <path|->`.
158
160
 
159
- After delivery, follow-up messages are recorded as discussion by default. To start implementation again on a delivered/review ticket, call `ovld protocol update --begin-follow-up-work --follow-up-intent execution --summary "Beginning follow-up work."` before moving back to `--phase execute`. Use `--event-type discussion_summary` or `--event-type decision` for important non-file outcomes. Once follow-up execution records a real work signal, such as an execution update, git snapshot, change rationales, deliverables, or explicit `pending_delivery` intent, Overlord marks the objective `pending_delivery` so redelivery is only required for actual post-delivery work.
161
+ After delivery, follow-up messages are recorded as discussion by default. To start implementation again on a delivered/review ticket, call `ovld protocol update --begin-follow-up-work --follow-up-intent execution --summary "Beginning follow-up work."` before moving back to `--phase execute`. Use `--event-type discussion_summary` or `--event-type decision` for important non-file outcomes. Once follow-up execution records a real work signal, such as an execution update, git snapshot, change rationales, deliverables, or explicit `pending_delivery` intent, Overlord marks the objective `pending_delivery` so redelivery is only required for actual post-delivery work. Use `ovld protocol heartbeat` during long-running mechanical work when you need liveness without adding activity-feed noise.
160
162
 
161
163
  ## License
162
164
 
@@ -54,7 +54,7 @@ Agents:
54
54
  installed connector (${primaryCommand} setup <agent>); your custom agents launch by id.
55
55
  Anything after a standalone -- is forwarded verbatim to the agent binary.
56
56
  Use ${primaryCommand} protocol help for ticket lifecycle commands.
57
- Key protocol commands: auth-status, discover-project, create, prompt, attach, connect, load-context.
57
+ Key protocol commands: auth-status, discover-project, create, prompt, attach, connect, load-context, heartbeat.
58
58
 
59
59
  Auth:
60
60
  ${primaryCommand} auth login Authorize CLI via browser or --token <oat_…>
@@ -1062,6 +1062,56 @@ async function protocolUpdate(args) {
1062
1062
  console.log(JSON.stringify(data, null, 2));
1063
1063
  }
1064
1064
 
1065
+ // ---------------------------------------------------------------------------
1066
+ // heartbeat
1067
+ // ---------------------------------------------------------------------------
1068
+
1069
+ async function protocolHeartbeat(args) {
1070
+ const flags = parseFlags(args);
1071
+ const { sessionKey, ticketId } = resolveSessionFlags(flags);
1072
+ if (!sessionKey) throw new Error('--session-key is required (or set SESSION_KEY)');
1073
+ if (!ticketId) throw new Error('--ticket-id is required (or set TICKET_ID)');
1074
+
1075
+ const { platformUrl, bearerToken, localSecret, organizationId } =
1076
+ await resolveProtocolAuthForFlags(flags, ticketId);
1077
+ const timeoutMs = resolveTimeout(flags);
1078
+ const externalSessionId = resolveExternalSessionId(flags);
1079
+ const percent =
1080
+ flags.percent !== undefined && flags.percent !== true ? Number(flags.percent) : undefined;
1081
+
1082
+ if (percent !== undefined && (!Number.isFinite(percent) || percent < 0 || percent > 100)) {
1083
+ throw new Error('--percent must be a number between 0 and 100');
1084
+ }
1085
+
1086
+ const body = {
1087
+ sessionKey,
1088
+ ticketId,
1089
+ ...(flags.phase ? { phase: String(flags.phase) } : {}),
1090
+ ...(percent !== undefined ? { percent } : {}),
1091
+ ...(flags.note ? { note: String(flags.note) } : {}),
1092
+ ...(externalSessionId !== undefined ? { externalSessionId } : {}),
1093
+ ...(flags['external-url']
1094
+ ? {
1095
+ externalUrl:
1096
+ String(flags['external-url']).trim().toLowerCase() === 'null'
1097
+ ? null
1098
+ : String(flags['external-url'])
1099
+ }
1100
+ : {})
1101
+ };
1102
+
1103
+ const data = await apiPost(
1104
+ platformUrl,
1105
+ bearerToken,
1106
+ localSecret,
1107
+ organizationId,
1108
+ '/api/protocol/heartbeat',
1109
+ body,
1110
+ timeoutMs
1111
+ );
1112
+ console.log(JSON.stringify(data, null, 2));
1113
+ }
1114
+
1065
1115
  // ---------------------------------------------------------------------------
1066
1116
  // record-change-rationales
1067
1117
  // ---------------------------------------------------------------------------
@@ -2588,6 +2638,7 @@ Subcommands:
2588
2638
  prompt Create a ticket and attach to it immediately
2589
2639
  record-work Record completed-from-chat work as a ticket in review + feed post (no attach)
2590
2640
  update Post progress, activity events, and optional change rationales
2641
+ heartbeat Send a lightweight liveness ping without creating a ticket event
2591
2642
  record-change-rationales Persist structured change rationales without a progress update
2592
2643
  ask Post a blocking question and move the ticket to review
2593
2644
  request-approval-gate Flip auto_advance=false on the next queued future objective
@@ -2741,6 +2792,23 @@ update:
2741
2792
  Pass --summary-file - to read the summary from stdin — avoids shell interpretation of backticks,
2742
2793
  quotes, or other special characters in the summary text.
2743
2794
 
2795
+ heartbeat:
2796
+ Purpose:
2797
+ Send a lightweight liveness ping for an attached session without adding activity-feed noise
2798
+ Required:
2799
+ --session-key <key>
2800
+ --ticket-id <ticket_id>
2801
+ Optional:
2802
+ --phase <status> draft | execute | review | deliver | complete | blocked | cancelled
2803
+ --percent <0-100> Optional percent-complete hint for transient UI progress
2804
+ --note <text> Optional short note, e.g. "Running the integration suite"
2805
+ --external-url <url|null> Store or clear a deep link to the live agent session
2806
+ --external-session-id <id|null>
2807
+ Notes:
2808
+ Heartbeat only updates session liveness plus transient telemetry on the session row.
2809
+ It does not create a ticket event and should be used when you are still working but have
2810
+ nothing meaningful to post via update.
2811
+
2744
2812
  record-change-rationales:
2745
2813
  Purpose:
2746
2814
  Persist structured file-change rationale records without also posting a normal update
@@ -3211,6 +3279,10 @@ EOF
3211
3279
  await protocolUpdate(args);
3212
3280
  return;
3213
3281
  }
3282
+ if (subcommand === 'heartbeat') {
3283
+ await protocolHeartbeat(args);
3284
+ return;
3285
+ }
3214
3286
  if (subcommand === 'record-change-rationales') {
3215
3287
  await protocolRecordChangeRationales(args);
3216
3288
  return;
@@ -275,11 +275,21 @@ function spawnLaunchProcess(args, claim, deviceFingerprint) {
275
275
  runnerTestHooks.platform ?? process.platform
276
276
  );
277
277
 
278
+ // Phase 4: thread the execution request id to the launched process so the
279
+ // agent's `ovld protocol attach` can mark this exact request `launched`.
280
+ // Attach falls back to matching by objective when this is absent, so this is
281
+ // a precision aid, not a correctness requirement.
282
+ const launchEnv = {
283
+ ...process.env,
284
+ OVERLORD_DEVICE_FINGERPRINT: deviceFingerprint,
285
+ ...(claim.request?.id ? { OVERLORD_EXECUTION_REQUEST_ID: claim.request.id } : {})
286
+ };
287
+
278
288
  if (!terminalCommand) {
279
289
  return {
280
290
  child: spawnImpl(process.execPath, [OVLD_ENTRY, ...args], {
281
291
  stdio: 'inherit',
282
- env: { ...process.env, OVERLORD_DEVICE_FINGERPRINT: deviceFingerprint }
292
+ env: launchEnv
283
293
  }),
284
294
  completeOnClose: false
285
295
  };
@@ -288,7 +298,7 @@ function spawnLaunchProcess(args, claim, deviceFingerprint) {
288
298
  return {
289
299
  child: spawnImpl('sh', ['-lc', terminalCommand], {
290
300
  stdio: 'inherit',
291
- env: { ...process.env, OVERLORD_DEVICE_FINGERPRINT: deviceFingerprint }
301
+ env: launchEnv
292
302
  }),
293
303
  completeOnClose: true
294
304
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "overlord-cli",
3
- "version": "0.2605300746.0",
3
+ "version": "0.2605311843.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",
@@ -373,6 +373,40 @@ const tools = [
373
373
  }),
374
374
  subcommand: 'update'
375
375
  },
376
+ {
377
+ name: 'heartbeat',
378
+ description:
379
+ 'Send a lightweight Overlord liveness ping without posting a ticket event. Optional phase/percent/note telemetry is stored on the session row.',
380
+ inputSchema: {
381
+ type: 'object',
382
+ properties: {
383
+ session_key: { type: 'string' },
384
+ ticket_id: {
385
+ type: 'string',
386
+ description: 'Ticket identifier (e.g. 1:899). Also accepts UUID.'
387
+ },
388
+ phase: {
389
+ type: 'string',
390
+ enum: ['draft', 'execute', 'review', 'deliver', 'complete', 'blocked', 'cancelled']
391
+ },
392
+ percent: { type: 'number' },
393
+ note: { type: 'string' },
394
+ external_url: { type: ['string', 'null'] },
395
+ external_session_id: { type: ['string', 'null'] }
396
+ },
397
+ required: ['session_key', 'ticket_id']
398
+ },
399
+ toCliFlags: args => ({
400
+ 'session-key': args.session_key,
401
+ 'ticket-id': args.ticket_id,
402
+ phase: args.phase,
403
+ percent: args.percent,
404
+ note: args.note,
405
+ 'external-url': args.external_url,
406
+ 'external-session-id': args.external_session_id
407
+ }),
408
+ subcommand: 'heartbeat'
409
+ },
376
410
  {
377
411
  name: 'record_change_rationales',
378
412
  description: 'Persist structured change rationale rows without posting a separate update.',
@@ -10,7 +10,6 @@
10
10
  "repository": "https://github.com/cooperativ/overlord",
11
11
  "license": "UNLICENSED",
12
12
  "keywords": ["overlord", "tickets", "agents", "workflow", "protocol", "claude-code"],
13
- "hooks": "./hooks/hooks.json",
14
13
  "userConfig": {
15
14
  "overlord_url": {
16
15
  "type": "string",
@@ -15,6 +15,7 @@ Use this mode when the prompt already contains a ticket ID or explicitly says th
15
15
  2. The attach response prints JSON to stdout containing `session.sessionKey`. The CLI also persists this key automatically so subsequent `ovld protocol` commands in the same working directory resolve it without `--session-key`. If auto-resolution fails, pass `--session-key <sessionKey>` explicitly on every subsequent call.
16
16
  3. Treat the Overlord ticket prompt as authoritative for the objective, constraints, and delivery target.
17
17
  4. Post updates while working: `ovld protocol update --session-key <sessionKey> --ticket-id <ticket_id> --summary "..." --phase execute`.
18
+ During long mechanical stretches with nothing meaningful to post, send `ovld protocol heartbeat --session-key <sessionKey> --ticket-id <ticket_id> [--phase execute] [--percent <0-100>] [--note "..."]` instead of an empty update.
18
19
  5. Follow-up messages after the initial ticket are captured automatically by the installed `UserPromptSubmit` hook and stay in discussion intent while the ticket is in review. Do not post `user_follow_up` manually unless the hook is unavailable.
19
20
  6. If blocked, call `ovld protocol ask --session-key <sessionKey> --ticket-id <ticket_id> --question "..."` and stop.
20
21
  7. Deliver last with `ovld protocol deliver --session-key <sessionKey> --ticket-id <ticket_id> --summary "..."`, including `changeRationales` for each meaningful behavioral file change.
@@ -113,5 +114,5 @@ For the `record-change-rationales` command and full payload shape with optional
113
114
  - [reference/context.md](reference/context.md) — Shared state, attachments, and large artifact policy
114
115
  - [reference/shell-escaping.md](reference/shell-escaping.md) — Heredoc stdin piping for special characters in summaries and payloads
115
116
 
116
- <!-- version: 0.5.8 -->
117
+ <!-- version: 0.5.9 -->
117
118
 
@@ -14,6 +14,14 @@ In a git workspace, `attach` automatically creates a local git checkpoint for ea
14
14
  ovld protocol update --session-key <sessionKey> --ticket-id $TICKET_ID --summary "What you did and why." --phase execute
15
15
  ```
16
16
 
17
+ ## Heartbeat
18
+
19
+ ```bash
20
+ ovld protocol heartbeat --session-key <sessionKey> --ticket-id $TICKET_ID --phase execute --percent 40 --note "Running the integration suite"
21
+ ```
22
+
23
+ Use `heartbeat` for liveness pings and transient UI telemetry when you have no meaningful narrative summary to post. It updates the attached session without creating a ticket event.
24
+
17
25
  Supported `--phase` values:
18
26
 
19
27
  - `draft`
@@ -34,7 +42,7 @@ Event types:
34
42
  - `discussion_summary` for important discussion outcomes that should remain visible on the ticket
35
43
  - `decision` for explicit non-file decisions made during follow-up discussion
36
44
 
37
- Post-delivery follow-up modes:
45
+ - Post-delivery follow-up modes:
38
46
 
39
47
  - User follow-up messages default to `discussion` intent while the ticket is in review.
40
48
  - Use `ovld protocol update --begin-follow-up-work --follow-up-intent execution --summary "Beginning follow-up work."` before moving a delivered/review ticket back to execution.
@@ -15,6 +15,7 @@ Use this mode when the prompt already contains a ticket ID or explicitly says th
15
15
  2. The attach response prints JSON to stdout containing `session.sessionKey`. The CLI also persists this key automatically so subsequent `ovld protocol` commands in the same working directory resolve it without `--session-key`. If auto-resolution fails, pass `--session-key <sessionKey>` explicitly on every subsequent call.
16
16
  3. Treat the Overlord ticket prompt as authoritative for the objective, constraints, and delivery target.
17
17
  4. Post updates while working: `ovld protocol update --session-key <sessionKey> --ticket-id <ticket_id> --summary "..." --phase execute`.
18
+ During long mechanical stretches with nothing meaningful to post, send `ovld protocol heartbeat --session-key <sessionKey> --ticket-id <ticket_id> [--phase execute] [--percent <0-100>] [--note "..."]` instead of an empty update.
18
19
  5. Follow-up messages after the initial ticket are captured automatically by the installed Cursor `beforeSubmitPrompt` hook (see `~/.cursor/hooks.json`) and stay in discussion intent while the ticket is in review. Do not post `user_follow_up` manually unless the hook is unavailable.
19
20
  6. If blocked, call `ovld protocol ask --session-key <sessionKey> --ticket-id <ticket_id> --question "..."` and stop.
20
21
  7. Deliver last with `ovld protocol deliver --session-key <sessionKey> --ticket-id <ticket_id> --summary "..."`, including `changeRationales` for each meaningful behavioral file change.
@@ -113,5 +114,5 @@ For the `record-change-rationales` command and full payload shape with optional
113
114
  - [reference/context.md](reference/context.md) — Shared state, attachments, and large artifact policy
114
115
  - [reference/shell-escaping.md](reference/shell-escaping.md) — Heredoc stdin piping for special characters in summaries and payloads
115
116
 
116
- <!-- version: 0.5.8 -->
117
+ <!-- version: 0.5.9 -->
117
118
 
@@ -14,6 +14,14 @@ In a git workspace, `attach` automatically creates a local git checkpoint for ea
14
14
  ovld protocol update --session-key <sessionKey> --ticket-id $TICKET_ID --summary "What you did and why." --phase execute
15
15
  ```
16
16
 
17
+ ## Heartbeat
18
+
19
+ ```bash
20
+ ovld protocol heartbeat --session-key <sessionKey> --ticket-id $TICKET_ID --phase execute --percent 40 --note "Running the integration suite"
21
+ ```
22
+
23
+ Use `heartbeat` for liveness pings and transient UI telemetry when you have no meaningful narrative summary to post. It updates the attached session without creating a ticket event.
24
+
17
25
  Supported `--phase` values:
18
26
 
19
27
  - `draft`
@@ -34,7 +42,7 @@ Event types:
34
42
  - `discussion_summary` for important discussion outcomes that should remain visible on the ticket
35
43
  - `decision` for explicit non-file decisions made during follow-up discussion
36
44
 
37
- Post-delivery follow-up modes:
45
+ - Post-delivery follow-up modes:
38
46
 
39
47
  - User follow-up messages default to `discussion` intent while the ticket is in review.
40
48
  - Use `ovld protocol update --begin-follow-up-work --follow-up-intent execution --summary "Beginning follow-up work."` before moving a delivered/review ticket back to execution.
@@ -37,7 +37,7 @@ Tool names match the hosted Overlord MCP server (`supabase/functions/mcp/tools.t
37
37
  - Project resolution: `discover_project`
38
38
  - Ticket search: `search_tickets` — keyword search + status/filter (same filters as `ovld protocol search-tickets`)
39
39
  - Ticket session flow: `attach`, `connect`, `load_ticket_context` (CLI `load-context` only; not on hosted MCP), `prompt`
40
- - Progress and review flow: `update`, `record_change_rationales`, `ask`, `deliver`
40
+ - Progress and review flow: `update`, `heartbeat`, `record_change_rationales`, `ask`, `deliver`
41
41
  - Shared context: `read_context`, `write_context`
42
42
  - Objective attachments: `list_attachments`, `prepare_attachment_upload`, `finalize_attachment_upload`, `get_attachment_download_url`, `upload_attachment_file`
43
43
  - Local runner queue: `request_execution`, `claim_execution`, `complete_execution_launch`, `fail_execution_launch`
@@ -373,6 +373,40 @@ const tools = [
373
373
  }),
374
374
  subcommand: 'update'
375
375
  },
376
+ {
377
+ name: 'heartbeat',
378
+ description:
379
+ 'Send a lightweight Overlord liveness ping without posting a ticket event. Optional phase/percent/note telemetry is stored on the session row.',
380
+ inputSchema: {
381
+ type: 'object',
382
+ properties: {
383
+ session_key: { type: 'string' },
384
+ ticket_id: {
385
+ type: 'string',
386
+ description: 'Ticket identifier (e.g. 1:899). Also accepts UUID.'
387
+ },
388
+ phase: {
389
+ type: 'string',
390
+ enum: ['draft', 'execute', 'review', 'deliver', 'complete', 'blocked', 'cancelled']
391
+ },
392
+ percent: { type: 'number' },
393
+ note: { type: 'string' },
394
+ external_url: { type: ['string', 'null'] },
395
+ external_session_id: { type: ['string', 'null'] }
396
+ },
397
+ required: ['session_key', 'ticket_id']
398
+ },
399
+ toCliFlags: args => ({
400
+ 'session-key': args.session_key,
401
+ 'ticket-id': args.ticket_id,
402
+ phase: args.phase,
403
+ percent: args.percent,
404
+ note: args.note,
405
+ 'external-url': args.external_url,
406
+ 'external-session-id': args.external_session_id
407
+ }),
408
+ subcommand: 'heartbeat'
409
+ },
376
410
  {
377
411
  name: 'record_change_rationales',
378
412
  description: 'Persist structured change rationale rows without posting a separate update.',
@@ -15,6 +15,7 @@ Use this mode when the prompt already contains a ticket ID or explicitly says th
15
15
  2. The attach response prints JSON to stdout containing `session.sessionKey`. The CLI also persists this key automatically so subsequent `ovld protocol` commands in the same working directory resolve it without `--session-key`. If auto-resolution fails, pass `--session-key <sessionKey>` explicitly on every subsequent call.
16
16
  3. Treat the Overlord ticket prompt as authoritative for the objective, constraints, and delivery target.
17
17
  4. Post updates while working: `ovld protocol update --session-key <sessionKey> --ticket-id <ticket_id> --summary "..." --phase execute`.
18
+ During long mechanical stretches with nothing meaningful to post, send `ovld protocol heartbeat --session-key <sessionKey> --ticket-id <ticket_id> [--phase execute] [--percent <0-100>] [--note "..."]` instead of an empty update.
18
19
  5. Follow-up messages after the initial ticket are captured automatically by the installed `UserPromptSubmit` hook and stay in discussion intent while the ticket is in review. Do not post `user_follow_up` manually unless the hook is unavailable.
19
20
  6. If blocked, call `ovld protocol ask --session-key <sessionKey> --ticket-id <ticket_id> --question "..."` and stop.
20
21
  7. Deliver last with `ovld protocol deliver --session-key <sessionKey> --ticket-id <ticket_id> --summary "..."`, including `changeRationales` for each meaningful behavioral file change.
@@ -114,5 +115,5 @@ For the `record-change-rationales` command and full payload shape with optional
114
115
  - [reference/context.md](reference/context.md) — Shared state, attachments, and large artifact policy
115
116
  - [reference/shell-escaping.md](reference/shell-escaping.md) — Heredoc stdin piping for special characters in summaries and payloads
116
117
 
117
- <!-- version: 0.5.8 -->
118
+ <!-- version: 0.5.9 -->
118
119
 
@@ -14,6 +14,14 @@ In a git workspace, `attach` automatically creates a local git checkpoint for ea
14
14
  ovld protocol update --session-key <sessionKey> --ticket-id $TICKET_ID --summary "What you did and why." --phase execute
15
15
  ```
16
16
 
17
+ ## Heartbeat
18
+
19
+ ```bash
20
+ ovld protocol heartbeat --session-key <sessionKey> --ticket-id $TICKET_ID --phase execute --percent 40 --note "Running the integration suite"
21
+ ```
22
+
23
+ Use `heartbeat` for liveness pings and transient UI telemetry when you have no meaningful narrative summary to post. It updates the attached session without creating a ticket event.
24
+
17
25
  Supported `--phase` values:
18
26
 
19
27
  - `draft`
@@ -34,7 +42,7 @@ Event types:
34
42
  - `discussion_summary` for important discussion outcomes that should remain visible on the ticket
35
43
  - `decision` for explicit non-file decisions made during follow-up discussion
36
44
 
37
- Post-delivery follow-up modes:
45
+ - Post-delivery follow-up modes:
38
46
 
39
47
  - User follow-up messages default to `discussion` intent while the ticket is in review.
40
48
  - Use `ovld protocol update --begin-follow-up-work --follow-up-intent execution --summary "Beginning follow-up work."` before moving a delivered/review ticket back to execution.