overlord-cli 0.2605211850.0 → 0.2605221356.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 +2 -0
- package/bin/_cli/protocol.mjs +39 -25
- package/bin/_cli/runner.mjs +14 -6
- package/bin/_cli/setup.mjs +80 -4
- package/package.json +1 -1
- package/plugins/antigravity/scripts/overlord-mcp.mjs +137 -8
- package/plugins/antigravity/skills/overlord-ticket/SKILL.md +14 -11
- package/plugins/claude/skills/overlord-ticket/SKILL.md +24 -1
- package/plugins/claude/skills/overlord-ticket/reference/cli.md +6 -4
- package/plugins/claude/skills/overlord-ticket/reference/context.md +4 -4
- package/plugins/claude/skills/overlord-ticket/reference/mcp.md +3 -2
- package/plugins/cursor/skills/overlord-ticket/SKILL.md +24 -1
- package/plugins/cursor/skills/overlord-ticket/reference/cli.md +6 -4
- package/plugins/cursor/skills/overlord-ticket/reference/context.md +4 -4
- package/plugins/cursor/skills/overlord-ticket/reference/mcp.md +3 -2
- package/plugins/overlord/README.md +1 -0
- package/plugins/overlord/scripts/overlord-mcp.mjs +137 -8
- package/plugins/overlord/skills/overlord-ticket/SKILL.md +24 -1
- package/plugins/overlord/skills/overlord-ticket/reference/cli.md +6 -4
- package/plugins/overlord/skills/overlord-ticket/reference/context.md +4 -4
- package/plugins/overlord/skills/overlord-ticket/reference/mcp.md +3 -2
package/README.md
CHANGED
|
@@ -65,6 +65,8 @@ ovld prompt "Draft a fix for the onboarding flow"
|
|
|
65
65
|
ovld version
|
|
66
66
|
ovld update
|
|
67
67
|
ovld protocol discover-project
|
|
68
|
+
ovld protocol discover-project --project-id <project-id>
|
|
69
|
+
ovld protocol discover-project --working-directory /path/to/repo --device-fingerprint "$OVERLORD_DEVICE_FINGERPRINT"
|
|
68
70
|
ovld protocol attach --ticket-id <ticket_id>
|
|
69
71
|
ovld protocol search-tickets --query "auth refactor" --status next-up,execute
|
|
70
72
|
ovld protocol update --session-key <session-key> --ticket-id <ticket_id> --summary "Working on it" --phase execute
|
package/bin/_cli/protocol.mjs
CHANGED
|
@@ -1367,8 +1367,11 @@ async function protocolDeliver(args) {
|
|
|
1367
1367
|
async function protocolAttachmentList(args) {
|
|
1368
1368
|
const flags = parseFlags(args);
|
|
1369
1369
|
const { sessionKey, ticketId } = resolveSessionFlags(flags);
|
|
1370
|
+
const objectiveId = flags['objective-id'] ? String(flags['objective-id']) : '';
|
|
1370
1371
|
if (!sessionKey) throw new Error('--session-key is required (or set SESSION_KEY)');
|
|
1371
|
-
if (!ticketId
|
|
1372
|
+
if (!ticketId && !objectiveId) {
|
|
1373
|
+
throw new Error('--objective-id or --ticket-id is required');
|
|
1374
|
+
}
|
|
1372
1375
|
|
|
1373
1376
|
const { platformUrl, bearerToken, localSecret, organizationId } =
|
|
1374
1377
|
await resolveProtocolAuthForFlags(flags, ticketId);
|
|
@@ -1376,8 +1379,8 @@ async function protocolAttachmentList(args) {
|
|
|
1376
1379
|
|
|
1377
1380
|
const body = {
|
|
1378
1381
|
sessionKey,
|
|
1379
|
-
ticketId,
|
|
1380
|
-
...(
|
|
1382
|
+
...(ticketId ? { ticketId } : {}),
|
|
1383
|
+
...(objectiveId ? { objectiveId } : {})
|
|
1381
1384
|
};
|
|
1382
1385
|
|
|
1383
1386
|
const data = await apiPost(
|
|
@@ -1396,7 +1399,6 @@ async function protocolAttachmentPrepareUpload(args) {
|
|
|
1396
1399
|
const flags = parseFlags(args);
|
|
1397
1400
|
const { sessionKey, ticketId } = resolveSessionFlags(flags);
|
|
1398
1401
|
if (!sessionKey) throw new Error('--session-key is required (or set SESSION_KEY)');
|
|
1399
|
-
if (!ticketId) throw new Error('--ticket-id is required (or set TICKET_ID)');
|
|
1400
1402
|
const objectiveId = requireFlag(flags, 'objective-id', undefined);
|
|
1401
1403
|
const fileName = requireFlag(flags, 'file-name', undefined);
|
|
1402
1404
|
|
|
@@ -1406,7 +1408,7 @@ async function protocolAttachmentPrepareUpload(args) {
|
|
|
1406
1408
|
|
|
1407
1409
|
const body = {
|
|
1408
1410
|
sessionKey,
|
|
1409
|
-
ticketId,
|
|
1411
|
+
...(ticketId ? { ticketId } : {}),
|
|
1410
1412
|
objectiveId,
|
|
1411
1413
|
fileName,
|
|
1412
1414
|
...(flags.label ? { label: String(flags.label) } : {}),
|
|
@@ -1433,7 +1435,6 @@ async function protocolAttachmentFinalizeUpload(args) {
|
|
|
1433
1435
|
const flags = parseFlags(args);
|
|
1434
1436
|
const { sessionKey, ticketId } = resolveSessionFlags(flags);
|
|
1435
1437
|
if (!sessionKey) throw new Error('--session-key is required (or set SESSION_KEY)');
|
|
1436
|
-
if (!ticketId) throw new Error('--ticket-id is required (or set TICKET_ID)');
|
|
1437
1438
|
const objectiveId = requireFlag(flags, 'objective-id', undefined);
|
|
1438
1439
|
const storagePath = requireFlag(flags, 'storage-path', undefined);
|
|
1439
1440
|
const label = requireFlag(flags, 'label', undefined);
|
|
@@ -1444,7 +1445,7 @@ async function protocolAttachmentFinalizeUpload(args) {
|
|
|
1444
1445
|
|
|
1445
1446
|
const body = {
|
|
1446
1447
|
sessionKey,
|
|
1447
|
-
ticketId,
|
|
1448
|
+
...(ticketId ? { ticketId } : {}),
|
|
1448
1449
|
objectiveId,
|
|
1449
1450
|
storagePath,
|
|
1450
1451
|
label,
|
|
@@ -1471,7 +1472,6 @@ async function protocolAttachmentGetDownloadUrl(args) {
|
|
|
1471
1472
|
const flags = parseFlags(args);
|
|
1472
1473
|
const { sessionKey, ticketId } = resolveSessionFlags(flags);
|
|
1473
1474
|
if (!sessionKey) throw new Error('--session-key is required (or set SESSION_KEY)');
|
|
1474
|
-
if (!ticketId) throw new Error('--ticket-id is required (or set TICKET_ID)');
|
|
1475
1475
|
if (!flags['attachment-id'] && !flags['storage-path']) {
|
|
1476
1476
|
throw new Error('--attachment-id or --storage-path is required');
|
|
1477
1477
|
}
|
|
@@ -1485,7 +1485,7 @@ async function protocolAttachmentGetDownloadUrl(args) {
|
|
|
1485
1485
|
|
|
1486
1486
|
const body = {
|
|
1487
1487
|
sessionKey,
|
|
1488
|
-
ticketId,
|
|
1488
|
+
...(ticketId ? { ticketId } : {}),
|
|
1489
1489
|
...(flags['objective-id'] ? { objectiveId: String(flags['objective-id']) } : {}),
|
|
1490
1490
|
...(flags['attachment-id'] ? { attachmentId: String(flags['attachment-id']) } : {}),
|
|
1491
1491
|
...(flags['storage-path'] ? { storagePath: String(flags['storage-path']) } : {}),
|
|
@@ -1508,7 +1508,6 @@ async function protocolAttachmentUploadFile(args) {
|
|
|
1508
1508
|
const flags = parseFlags(args);
|
|
1509
1509
|
const { sessionKey, ticketId } = resolveSessionFlags(flags);
|
|
1510
1510
|
if (!sessionKey) throw new Error('--session-key is required (or set SESSION_KEY)');
|
|
1511
|
-
if (!ticketId) throw new Error('--ticket-id is required (or set TICKET_ID)');
|
|
1512
1511
|
const objectiveId = requireFlag(flags, 'objective-id', undefined);
|
|
1513
1512
|
const filePath = requireFlag(flags, 'file', undefined);
|
|
1514
1513
|
|
|
@@ -1537,7 +1536,7 @@ async function protocolAttachmentUploadFile(args) {
|
|
|
1537
1536
|
'/api/protocol/attachments/prepare-upload',
|
|
1538
1537
|
{
|
|
1539
1538
|
sessionKey,
|
|
1540
|
-
ticketId,
|
|
1539
|
+
...(ticketId ? { ticketId } : {}),
|
|
1541
1540
|
objectiveId,
|
|
1542
1541
|
fileName,
|
|
1543
1542
|
label,
|
|
@@ -1564,7 +1563,7 @@ async function protocolAttachmentUploadFile(args) {
|
|
|
1564
1563
|
'/api/protocol/attachments/finalize-upload',
|
|
1565
1564
|
{
|
|
1566
1565
|
sessionKey,
|
|
1567
|
-
ticketId,
|
|
1566
|
+
...(ticketId ? { ticketId } : {}),
|
|
1568
1567
|
objectiveId,
|
|
1569
1568
|
storagePath,
|
|
1570
1569
|
label,
|
|
@@ -1588,7 +1587,8 @@ async function protocolDiscoverProject(args) {
|
|
|
1588
1587
|
await resolveProtocolAuthForFlags(flags);
|
|
1589
1588
|
const timeoutMs = resolveTimeout(flags);
|
|
1590
1589
|
|
|
1591
|
-
const workingDirectory =
|
|
1590
|
+
const workingDirectory =
|
|
1591
|
+
flags['working-directory'] !== undefined ? String(flags['working-directory']) : process.cwd();
|
|
1592
1592
|
|
|
1593
1593
|
const data = await apiPost(
|
|
1594
1594
|
platformUrl,
|
|
@@ -1596,7 +1596,14 @@ async function protocolDiscoverProject(args) {
|
|
|
1596
1596
|
localSecret,
|
|
1597
1597
|
organizationId,
|
|
1598
1598
|
'/api/protocol/discover-project',
|
|
1599
|
-
{
|
|
1599
|
+
{
|
|
1600
|
+
...(flags['project-id'] ? { projectId: String(flags['project-id']) } : { workingDirectory }),
|
|
1601
|
+
...(flags['device-fingerprint']
|
|
1602
|
+
? { deviceFingerprint: String(flags['device-fingerprint']) }
|
|
1603
|
+
: {}),
|
|
1604
|
+
...(flags['device-hostname'] ? { deviceHostname: String(flags['device-hostname']) } : {}),
|
|
1605
|
+
...(flags['device-platform'] ? { devicePlatform: String(flags['device-platform']) } : {})
|
|
1606
|
+
},
|
|
1600
1607
|
timeoutMs
|
|
1601
1608
|
);
|
|
1602
1609
|
console.log(JSON.stringify(data, null, 2));
|
|
@@ -2493,9 +2500,10 @@ Project discovery:
|
|
|
2493
2500
|
You can also discover the project explicitly:
|
|
2494
2501
|
|
|
2495
2502
|
ovld protocol discover-project
|
|
2503
|
+
ovld protocol discover-project --project-id <project-uuid>
|
|
2496
2504
|
ovld protocol discover-project --working-directory /path/to/repo
|
|
2497
2505
|
|
|
2498
|
-
Use --project-id to override automatic resolution on prompt or ticket creation.
|
|
2506
|
+
Use --project-id to override automatic resolution on discover, prompt, or ticket creation.
|
|
2499
2507
|
Use --personal to create a private ticket without assigning any project.
|
|
2500
2508
|
|
|
2501
2509
|
Subcommands:
|
|
@@ -2563,7 +2571,11 @@ discover-project:
|
|
|
2563
2571
|
Resolve the Overlord project that corresponds to the current (or given) working directory.
|
|
2564
2572
|
Uses the caller's configured "Local working directory" for matching.
|
|
2565
2573
|
Optional:
|
|
2574
|
+
--project-id <uuid> Resolve this project directly; skips working-directory matching
|
|
2566
2575
|
--working-directory <path> Directory to match (default: current working directory)
|
|
2576
|
+
--device-fingerprint <fp> Prefer resource directories for this registered device
|
|
2577
|
+
--device-hostname <name> Register/update device metadata when fingerprint is provided
|
|
2578
|
+
--device-platform <platform>
|
|
2567
2579
|
Returns:
|
|
2568
2580
|
Project JSON with id, name, organizationId. Prints PROJECT_ID=<id> on stderr.
|
|
2569
2581
|
Notes:
|
|
@@ -2860,19 +2872,20 @@ record-work:
|
|
|
2860
2872
|
attachment-list:
|
|
2861
2873
|
Required:
|
|
2862
2874
|
--session-key <key>
|
|
2863
|
-
--ticket-id <ticket_id>
|
|
2875
|
+
one of: --objective-id <id> | --ticket-id <ticket_id>
|
|
2864
2876
|
Optional:
|
|
2865
|
-
--objective-id <id> Filter to a single objective
|
|
2877
|
+
--objective-id <id> Filter to a single objective (also acts as ticket scope)
|
|
2878
|
+
--ticket-id <ticket_id> List every attachment for a ticket
|
|
2866
2879
|
Returns:
|
|
2867
2880
|
JSON array of { id, label, content_type, file_size, objective_id, storage_path, created_at }
|
|
2868
2881
|
|
|
2869
2882
|
attachment-prepare-upload:
|
|
2870
2883
|
Required:
|
|
2871
2884
|
--session-key <key>
|
|
2872
|
-
--ticket-id <ticket_id>
|
|
2873
2885
|
--objective-id <id>
|
|
2874
2886
|
--file-name <name>
|
|
2875
2887
|
Optional:
|
|
2888
|
+
--ticket-id <ticket_id> Derived from --objective-id when omitted
|
|
2876
2889
|
--label <text>
|
|
2877
2890
|
--content-type <mime>
|
|
2878
2891
|
--file-size <bytes>
|
|
@@ -2881,11 +2894,11 @@ attachment-prepare-upload:
|
|
|
2881
2894
|
attachment-finalize-upload:
|
|
2882
2895
|
Required:
|
|
2883
2896
|
--session-key <key>
|
|
2884
|
-
--ticket-id <ticket_id>
|
|
2885
2897
|
--objective-id <id>
|
|
2886
2898
|
--storage-path <path>
|
|
2887
2899
|
--label <text>
|
|
2888
2900
|
Optional:
|
|
2901
|
+
--ticket-id <ticket_id> Derived from --objective-id when omitted
|
|
2889
2902
|
--content-type <mime>
|
|
2890
2903
|
--file-size <bytes>
|
|
2891
2904
|
--metadata-json <json>
|
|
@@ -2893,19 +2906,19 @@ attachment-finalize-upload:
|
|
|
2893
2906
|
attachment-download-url:
|
|
2894
2907
|
Required:
|
|
2895
2908
|
--session-key <key>
|
|
2896
|
-
--ticket-id <ticket_id>
|
|
2897
2909
|
one of: --attachment-id <id> | --storage-path <path>
|
|
2898
2910
|
Optional:
|
|
2911
|
+
--ticket-id <ticket_id> Derived from --attachment-id / --objective-id when omitted
|
|
2899
2912
|
--objective-id <id> Required when using --storage-path
|
|
2900
2913
|
--expires-in <seconds>
|
|
2901
2914
|
|
|
2902
2915
|
attachment-upload-file:
|
|
2903
2916
|
Required:
|
|
2904
2917
|
--session-key <key>
|
|
2905
|
-
--ticket-id <ticket_id>
|
|
2906
2918
|
--objective-id <id>
|
|
2907
2919
|
--file <path>
|
|
2908
2920
|
Optional:
|
|
2921
|
+
--ticket-id <ticket_id> Derived from --objective-id when omitted
|
|
2909
2922
|
--file-name <name> Defaults to basename of --file
|
|
2910
2923
|
--label <text> Defaults to file name
|
|
2911
2924
|
--content-type <mime> Defaults to application/octet-stream
|
|
@@ -2993,6 +3006,7 @@ fail-execution-launch:
|
|
|
2993
3006
|
Examples:
|
|
2994
3007
|
ovld protocol auth-status
|
|
2995
3008
|
ovld protocol discover-project
|
|
3009
|
+
ovld protocol discover-project --project-id <project-uuid>
|
|
2996
3010
|
ovld protocol discover-project --working-directory /path/to/repo
|
|
2997
3011
|
ovld protocol prompt --agent codex --objective "Implement feature X" # auto-resolves project from cwd
|
|
2998
3012
|
ovld protocol attach --ticket-id 1:899
|
|
@@ -3015,10 +3029,10 @@ Examples:
|
|
|
3015
3029
|
ovld protocol hook-event --hook-type UserPromptSubmit --ticket-id <ticket_id> --prompt "User follow-up" --turn-index 1
|
|
3016
3030
|
ovld protocol read-context --session-key <key> --ticket-id <ticket_id> --query arch --limit 5
|
|
3017
3031
|
ovld protocol write-context --session-key <key> --ticket-id <ticket_id> --key "arch" --value '"monorepo"' --tags repo,agent
|
|
3018
|
-
ovld protocol attachment-list --session-key <key> --
|
|
3019
|
-
ovld protocol attachment-prepare-upload --session-key <key> --
|
|
3020
|
-
ovld protocol attachment-upload-file --session-key <key> --
|
|
3021
|
-
ovld protocol attachment-download-url --session-key <key> --
|
|
3032
|
+
ovld protocol attachment-list --session-key <key> --objective-id <objective-id>
|
|
3033
|
+
ovld protocol attachment-prepare-upload --session-key <key> --objective-id <objective-id> --file-name spec.pdf --content-type application/pdf
|
|
3034
|
+
ovld protocol attachment-upload-file --session-key <key> --objective-id <objective-id> --file ./spec.pdf
|
|
3035
|
+
ovld protocol attachment-download-url --session-key <key> --attachment-id <attachment-id>
|
|
3022
3036
|
ovld protocol request-execution --ticket-id 1:899 --agent codex --requested-from manual_run
|
|
3023
3037
|
ovld protocol claim-execution --device-fingerprint $OVERLORD_DEVICE_FINGERPRINT
|
|
3024
3038
|
ovld protocol deliver --session-key <key> --ticket-id <ticket_id> --summary "Done"
|
package/bin/_cli/runner.mjs
CHANGED
|
@@ -9,6 +9,12 @@ import path from 'node:path';
|
|
|
9
9
|
const OVLD_ENTRY = process.argv[1];
|
|
10
10
|
const DEVICE_FILE = path.join(os.homedir(), '.ovld', 'device.json');
|
|
11
11
|
|
|
12
|
+
/** @internal Test-only overrides for protocol/launch subprocess calls. */
|
|
13
|
+
export const runnerTestHooks = {
|
|
14
|
+
execFileSync: null,
|
|
15
|
+
spawn: null
|
|
16
|
+
};
|
|
17
|
+
|
|
12
18
|
function printRunnerHelp(primaryCommand = 'ovld') {
|
|
13
19
|
console.log(`Usage:
|
|
14
20
|
${primaryCommand} runner once [options]
|
|
@@ -45,7 +51,7 @@ function parseFlags(args) {
|
|
|
45
51
|
return flags;
|
|
46
52
|
}
|
|
47
53
|
|
|
48
|
-
function readOrCreateDeviceFingerprint(flags) {
|
|
54
|
+
export function readOrCreateDeviceFingerprint(flags) {
|
|
49
55
|
const explicit =
|
|
50
56
|
typeof flags['device-fingerprint'] === 'string'
|
|
51
57
|
? flags['device-fingerprint'].trim()
|
|
@@ -69,7 +75,8 @@ function readOrCreateDeviceFingerprint(flags) {
|
|
|
69
75
|
}
|
|
70
76
|
|
|
71
77
|
function runOvld(args, env = {}) {
|
|
72
|
-
|
|
78
|
+
const exec = runnerTestHooks.execFileSync ?? execFileSync;
|
|
79
|
+
return exec(process.execPath, [OVLD_ENTRY, ...args], {
|
|
73
80
|
encoding: 'utf8',
|
|
74
81
|
env: { ...process.env, ...env }
|
|
75
82
|
});
|
|
@@ -111,7 +118,7 @@ function failLaunch(requestId, deviceFingerprint, error) {
|
|
|
111
118
|
);
|
|
112
119
|
}
|
|
113
120
|
|
|
114
|
-
function buildLaunchArgs(launch) {
|
|
121
|
+
export function buildLaunchArgs(launch) {
|
|
115
122
|
const args = ['launch', launch.agent, '--ticket-id', launch.ticketId];
|
|
116
123
|
if (launch.workingDirectory) args.push('--working-directory', launch.workingDirectory);
|
|
117
124
|
if (launch.launchMode === 'ask') args.push('--launch-mode', 'ask');
|
|
@@ -127,7 +134,7 @@ function buildLaunchArgs(launch) {
|
|
|
127
134
|
return args;
|
|
128
135
|
}
|
|
129
136
|
|
|
130
|
-
async function launchClaimedRequest(claim, deviceFingerprint) {
|
|
137
|
+
export async function launchClaimedRequest(claim, deviceFingerprint) {
|
|
131
138
|
const requestId = claim.request?.id;
|
|
132
139
|
if (!requestId || !claim.launch?.agent || !claim.launch?.ticketId) return false;
|
|
133
140
|
|
|
@@ -137,7 +144,8 @@ async function launchClaimedRequest(claim, deviceFingerprint) {
|
|
|
137
144
|
);
|
|
138
145
|
|
|
139
146
|
await new Promise((resolve, reject) => {
|
|
140
|
-
const
|
|
147
|
+
const spawnImpl = runnerTestHooks.spawn ?? spawn;
|
|
148
|
+
const child = spawnImpl(process.execPath, [OVLD_ENTRY, ...args], {
|
|
141
149
|
stdio: 'inherit',
|
|
142
150
|
env: { ...process.env, OVERLORD_DEVICE_FINGERPRINT: deviceFingerprint }
|
|
143
151
|
});
|
|
@@ -170,7 +178,7 @@ async function launchClaimedRequest(claim, deviceFingerprint) {
|
|
|
170
178
|
return true;
|
|
171
179
|
}
|
|
172
180
|
|
|
173
|
-
async function runOnce(flags, deviceFingerprint) {
|
|
181
|
+
export async function runOnce(flags, deviceFingerprint) {
|
|
174
182
|
const claim = claimExecution(flags, deviceFingerprint);
|
|
175
183
|
if (!claim.request) {
|
|
176
184
|
process.stderr.write('[runner] no queued execution requests\n');
|
package/bin/_cli/setup.mjs
CHANGED
|
@@ -14,10 +14,86 @@ import os from 'node:os';
|
|
|
14
14
|
import path from 'node:path';
|
|
15
15
|
import { fileURLToPath } from 'node:url';
|
|
16
16
|
import { checkForCliUpdate, getCurrentCliVersion, printCliUpdateNotice } from './cli-update.mjs';
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
17
|
+
|
|
18
|
+
// ---------------------------------------------------------------------------
|
|
19
|
+
// Legacy Gemini connector (inlined — the lib/ directory is not published with
|
|
20
|
+
// the npm package, so the old relative import broke on global installs)
|
|
21
|
+
// ---------------------------------------------------------------------------
|
|
22
|
+
|
|
23
|
+
const GEMINI_LEGACY_COMMANDS_DIR = path.join(os.homedir(), '.gemini', 'commands');
|
|
24
|
+
|
|
25
|
+
function geminiLegacyCommandFiles() {
|
|
26
|
+
const base = GEMINI_LEGACY_COMMANDS_DIR;
|
|
27
|
+
return [
|
|
28
|
+
{
|
|
29
|
+
path: path.join(base, 'connect.toml'),
|
|
30
|
+
content: `description = "Connect this session to another Overlord ticket (requires: ticket-id)."\nprompt = """\nConnect this session to another Overlord ticket.\n\nTreat \`{{args}}\` as the target ticket ID.\nIf no ticket ID was provided, ask the user for one and stop.\n\nRun:\n\`ovld protocol connect --ticket-id <ticket_id>\`\n\nRules:\n- Use \`connect\`, not \`attach\`.\n- Do not load extra ticket context unless the user explicitly asks for it.\n- After the command succeeds, report the returned \`SESSION_KEY\` and confirm that future updates should use that ticket.\n"""`
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
path: path.join(base, 'load.toml'),
|
|
34
|
+
content: `description = "Load Overlord ticket context (requires: ticket-id)."\nprompt = """\nLoad Overlord ticket context without attaching to the ticket.\n\nTreat \`{{args}}\` as the target ticket ID.\nIf no ticket ID was provided, ask the user for one and stop.\n\nRun:\n\`ovld protocol load-context --ticket-id <ticket_id>\`\n\nRules:\n- Use \`load-context\`, not \`attach\`.\n- Do not create or switch sessions.\n- Summarize the returned ticket details, history, artifacts, and shared context for the user.\n"""`
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
path: path.join(base, 'attach.toml'),
|
|
38
|
+
content: `description = "Attach this session to an Overlord ticket (requires: ticket-id)."\nprompt = """\nAttach this session to an Overlord ticket.\n\nTreat \`{{args}}\` as the target ticket ID.\nIf no ticket ID was provided, ask the user for one and stop.\n\nRun:\n\`ovld protocol attach --ticket-id <ticket_id>\`\n\nRules:\n- Use \`attach\` to establish a persistent session with a ticket.\n- After the command succeeds, report the returned \`SESSION_KEY\` and confirm that future updates should use that ticket.\n"""`
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
path: path.join(base, 'discuss-objective.toml'),
|
|
42
|
+
content: `description = "Mark a ticket's draft objective as submitted (in discussion)."\nprompt = """\nMark a draft objective as "submitted", indicating the ticket is in active discussion with an agent.\n\nTreat \`{{args}}\` as the target ticket ID.\nIf no ticket ID was provided, ask the user for one and stop.\n\nRun:\n\`ovld protocol discuss-objective --ticket-id <ticket_id>\`\n\nRules:\n- This does NOT start execution. Use \`attach\` for that.\n- After the command succeeds, confirm the objective was submitted.\n"""`
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
path: path.join(base, 'add-objectives.toml'),
|
|
46
|
+
content: `description = "Append ordered objectives to an existing Overlord ticket."\nprompt = """\nAppend ordered objectives to an existing ticket.\n\nUse this when prompts are sequential steps toward the same feature or goal. Create separate tickets when prompts represent different features or goals.\n\nRun:\n\`ovld protocol add-objectives --ticket-id <ticket_id> --objectives-json '[{"objective":"Step one"},{"objective":"Step two"}]'\`\n\nIndex 0 is the first newly added objective to execute; later indexes queue after it.\n"""`
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
path: path.join(base, 'create.toml'),
|
|
50
|
+
content: `description = "Create a draft Overlord ticket from the current conversation."\nprompt = """\nCreate a draft Overlord ticket from the user's request.\n\nUse \`{{args}}\` as the input.\nIf it already contains flags such as \`--title\`, \`--priority\`, \`--project-id\`, or \`--execution-target\`, pass those flags through after \`ovld protocol create --agent gemini\`.\nOtherwise, treat \`{{args}}\` as the objective text and run:\n\`ovld protocol create --agent gemini --objective "<objective>"\`\n\nIf no objective was provided, ask the user for one and stop.\n\nAfter the command succeeds, report the new \`TICKET_ID\`.\n"""`
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
path: path.join(base, 'prompt.toml'),
|
|
54
|
+
content: `description = "Create a new Overlord ticket from the current conversation."\nprompt = """\nCreate a new Overlord ticket from the user's request.\n\nUse \`{{args}}\` as the input.\nIf it already contains flags such as \`--title\`, \`--priority\`, \`--project-id\`, or \`--execution-target\`, pass those flags through after \`ovld protocol prompt --agent gemini\`.\nOtherwise, treat \`{{args}}\` as the objective text and run:\n\`ovld protocol prompt --agent gemini --objective "<objective>"\`\n\nIf no objective was provided, ask the user for one and stop.\n\nAfter the command succeeds, report the new \`TICKET_ID\` and \`SESSION_KEY\`.\n"""`
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
path: path.join(base, 'record-work.toml'),
|
|
58
|
+
content: `description = "Record completed-from-chat work as a ticket in review + feed post (no attach)."\nprompt = """\nImmediately record the work you just completed in this chat as a new Overlord ticket via \`ovld protocol record-work\`. No agent session is opened — the work is already done.\n\nSynthesize from the current conversation:\n- \`objective\`: what was asked / what was done.\n- \`summary\`: reviewer-friendly narrative for the feed.\n- \`changeRationales\`: one entry per meaningful git-tracked file change (\`label\`, \`file_path\`, \`summary\`, \`why\`, \`impact\`, optional \`hunks\`). Use \`git status\` and \`git diff\` to enumerate changed files.\n- \`artifacts\` (optional): \`next_steps\`, \`test_results\`, \`decision\`, \`note\`, \`url\`.\n\nIf \`{{args}}\` is non-empty, treat it as additional context to weave into the summary.\n\nRun \`ovld protocol record-work --payload-file -\` and stream a JSON object \`{ "objective": "...", "summary": "...", "artifacts": [...], "changeRationales": [...] }\` on stdin via a single-quoted heredoc.\n\nAfter the command succeeds, report the new \`TICKET_ID\`.\n\nRules:\n- Do NOT use this for in-progress work. Use \`/prompt\` for that.\n- The CLI validates that every changed git-tracked file is represented in \`changeRationales\` unless \`--skip-file-change-check\` is passed.\n- If project resolution fails, re-run with \`--project-id <id>\` or \`--personal\`.\n"""`
|
|
59
|
+
}
|
|
60
|
+
];
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function isRemovableLegacyGeminiCommandFile({ filePath, content, manifestFiles }) {
|
|
64
|
+
if (manifestFiles.has(filePath)) return true;
|
|
65
|
+
const managed = geminiLegacyCommandFiles().find(file => file.path === filePath);
|
|
66
|
+
if (!managed) return false;
|
|
67
|
+
return content.trim() === managed.content.trim();
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function removeLegacyGeminiConnectorFiles({ readManifest, writeManifest, readTextFile, existsSync = fs.existsSync.bind(fs), rmSync = fs.rmSync.bind(fs) }) {
|
|
71
|
+
const removed = [];
|
|
72
|
+
const manifest = readManifest();
|
|
73
|
+
const manifestFiles = new Set(manifest.gemini?.files ?? []);
|
|
74
|
+
|
|
75
|
+
for (const file of geminiLegacyCommandFiles()) {
|
|
76
|
+
if (!existsSync(file.path)) continue;
|
|
77
|
+
const existing = readTextFile(file.path);
|
|
78
|
+
if (!isRemovableLegacyGeminiCommandFile({ filePath: file.path, content: existing, manifestFiles })) continue;
|
|
79
|
+
rmSync(file.path, { force: true });
|
|
80
|
+
removed.push(file.path);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
for (const filePath of manifestFiles) {
|
|
84
|
+
if (removed.includes(filePath) || !existsSync(filePath)) continue;
|
|
85
|
+
if (!filePath.includes('.gemini/commands') || !filePath.endsWith('.toml')) continue;
|
|
86
|
+
rmSync(filePath, { force: true });
|
|
87
|
+
removed.push(filePath);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (manifest.gemini) {
|
|
91
|
+
delete manifest.gemini;
|
|
92
|
+
writeManifest(manifest);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return removed;
|
|
96
|
+
}
|
|
21
97
|
|
|
22
98
|
const BUNDLE_VERSION = '1.12.0';
|
|
23
99
|
const MD_MARKER_START = '<!-- overlord:managed:start -->';
|
package/package.json
CHANGED
|
@@ -57,18 +57,40 @@ function execFileWithOptionalInput(file, args, options, input) {
|
|
|
57
57
|
const tools = [
|
|
58
58
|
{
|
|
59
59
|
name: 'discover_project',
|
|
60
|
-
description:
|
|
60
|
+
description:
|
|
61
|
+
'Resolve an Overlord project by explicit project_id or by matching a working directory.',
|
|
61
62
|
inputSchema: {
|
|
62
63
|
type: 'object',
|
|
63
64
|
properties: {
|
|
65
|
+
project_id: {
|
|
66
|
+
type: 'string',
|
|
67
|
+
description: 'Project UUID to resolve directly. Skips working-directory matching.'
|
|
68
|
+
},
|
|
64
69
|
working_directory: {
|
|
65
70
|
type: 'string',
|
|
66
71
|
description: 'Directory to match. Defaults to the current workspace.'
|
|
72
|
+
},
|
|
73
|
+
device_fingerprint: {
|
|
74
|
+
type: 'string',
|
|
75
|
+
description:
|
|
76
|
+
'Optional stable device fingerprint. When provided, matching prefers resource directories for this registered device.'
|
|
77
|
+
},
|
|
78
|
+
device_hostname: {
|
|
79
|
+
type: 'string',
|
|
80
|
+
description: 'Optional hostname to register/update with device_fingerprint.'
|
|
81
|
+
},
|
|
82
|
+
device_platform: {
|
|
83
|
+
type: 'string',
|
|
84
|
+
description: 'Optional platform string, e.g. darwin, linux, or windows.'
|
|
67
85
|
}
|
|
68
86
|
}
|
|
69
87
|
},
|
|
70
88
|
toCliFlags: args => ({
|
|
71
|
-
'
|
|
89
|
+
'project-id': args.project_id,
|
|
90
|
+
'working-directory': args.working_directory,
|
|
91
|
+
'device-fingerprint': args.device_fingerprint,
|
|
92
|
+
'device-hostname': args.device_hostname,
|
|
93
|
+
'device-platform': args.device_platform
|
|
72
94
|
}),
|
|
73
95
|
subcommand: 'discover-project'
|
|
74
96
|
},
|
|
@@ -437,7 +459,7 @@ const tools = [
|
|
|
437
459
|
query: { type: 'string' },
|
|
438
460
|
limit: { type: 'number' }
|
|
439
461
|
},
|
|
440
|
-
required: ['session_key'
|
|
462
|
+
required: ['session_key']
|
|
441
463
|
},
|
|
442
464
|
toCliFlags: args => ({
|
|
443
465
|
'session-key': args.session_key,
|
|
@@ -584,7 +606,7 @@ const tools = [
|
|
|
584
606
|
},
|
|
585
607
|
objective_id: { type: 'string' }
|
|
586
608
|
},
|
|
587
|
-
required: ['session_key'
|
|
609
|
+
required: ['session_key']
|
|
588
610
|
},
|
|
589
611
|
toCliFlags: args => ({
|
|
590
612
|
'session-key': args.session_key,
|
|
@@ -611,7 +633,7 @@ const tools = [
|
|
|
611
633
|
file_size: { type: 'number' },
|
|
612
634
|
metadata: { type: 'object' }
|
|
613
635
|
},
|
|
614
|
-
required: ['session_key', '
|
|
636
|
+
required: ['session_key', 'objective_id', 'file_name']
|
|
615
637
|
},
|
|
616
638
|
toCliFlags: args => ({
|
|
617
639
|
'session-key': args.session_key,
|
|
@@ -644,7 +666,7 @@ const tools = [
|
|
|
644
666
|
file_size: { type: 'number' },
|
|
645
667
|
metadata: { type: 'object' }
|
|
646
668
|
},
|
|
647
|
-
required: ['session_key', '
|
|
669
|
+
required: ['session_key', 'objective_id', 'storage_path', 'label']
|
|
648
670
|
},
|
|
649
671
|
toCliFlags: args => ({
|
|
650
672
|
'session-key': args.session_key,
|
|
@@ -674,7 +696,7 @@ const tools = [
|
|
|
674
696
|
storage_path: { type: 'string' },
|
|
675
697
|
expires_in: { type: 'number' }
|
|
676
698
|
},
|
|
677
|
-
required: ['session_key'
|
|
699
|
+
required: ['session_key']
|
|
678
700
|
},
|
|
679
701
|
toCliFlags: args => ({
|
|
680
702
|
'session-key': args.session_key,
|
|
@@ -705,7 +727,7 @@ const tools = [
|
|
|
705
727
|
content_type: { type: 'string' },
|
|
706
728
|
metadata: { type: 'object' }
|
|
707
729
|
},
|
|
708
|
-
required: ['session_key', '
|
|
730
|
+
required: ['session_key', 'objective_id', 'file']
|
|
709
731
|
},
|
|
710
732
|
toCliFlags: args => ({
|
|
711
733
|
'session-key': args.session_key,
|
|
@@ -862,6 +884,113 @@ const tools = [
|
|
|
862
884
|
: {})
|
|
863
885
|
}),
|
|
864
886
|
subcommand: 'update-project-resource'
|
|
887
|
+
},
|
|
888
|
+
{
|
|
889
|
+
name: 'request_execution',
|
|
890
|
+
description:
|
|
891
|
+
'Queue an objective for local or remote runner execution. Manual Run and auto-advance use this durable queue.',
|
|
892
|
+
inputSchema: {
|
|
893
|
+
type: 'object',
|
|
894
|
+
properties: {
|
|
895
|
+
ticket_id: { type: 'string' },
|
|
896
|
+
objective_id: { type: 'string' },
|
|
897
|
+
requested_from: { type: 'string' },
|
|
898
|
+
idempotency_key: { type: 'string' },
|
|
899
|
+
agent: { type: 'string' },
|
|
900
|
+
model: { type: 'string' },
|
|
901
|
+
thinking: { type: 'string' },
|
|
902
|
+
launch_mode: { type: 'string', enum: ['run', 'ask'] },
|
|
903
|
+
working_directory: { type: 'string' },
|
|
904
|
+
ssh_command: { type: 'string' },
|
|
905
|
+
remote_working_directory: { type: 'string' },
|
|
906
|
+
server_multiplexer: { type: 'string', enum: ['none', 'tmux'] },
|
|
907
|
+
tmux_command: { type: 'string' },
|
|
908
|
+
target_kind: { type: 'string', enum: ['any', 'local', 'ssh'] },
|
|
909
|
+
target_device_id: { type: 'string' },
|
|
910
|
+
target_resource_id: { type: 'string' }
|
|
911
|
+
},
|
|
912
|
+
required: ['ticket_id']
|
|
913
|
+
},
|
|
914
|
+
toCliFlags: args => ({
|
|
915
|
+
'ticket-id': args.ticket_id,
|
|
916
|
+
'objective-id': args.objective_id,
|
|
917
|
+
'requested-from': args.requested_from,
|
|
918
|
+
'idempotency-key': args.idempotency_key,
|
|
919
|
+
agent: args.agent,
|
|
920
|
+
model: args.model,
|
|
921
|
+
thinking: args.thinking,
|
|
922
|
+
'launch-mode': args.launch_mode,
|
|
923
|
+
'working-directory': args.working_directory,
|
|
924
|
+
'ssh-command': args.ssh_command,
|
|
925
|
+
'remote-working-directory': args.remote_working_directory,
|
|
926
|
+
'server-multiplexer': args.server_multiplexer,
|
|
927
|
+
'tmux-command': args.tmux_command,
|
|
928
|
+
'target-kind': args.target_kind,
|
|
929
|
+
'target-device-id': args.target_device_id,
|
|
930
|
+
'target-resource-id': args.target_resource_id
|
|
931
|
+
}),
|
|
932
|
+
subcommand: 'request-execution'
|
|
933
|
+
},
|
|
934
|
+
{
|
|
935
|
+
name: 'claim_execution',
|
|
936
|
+
description: 'Claim one queued execution request for this device.',
|
|
937
|
+
inputSchema: {
|
|
938
|
+
type: 'object',
|
|
939
|
+
properties: {
|
|
940
|
+
device_fingerprint: { type: 'string' },
|
|
941
|
+
device_hostname: { type: 'string' },
|
|
942
|
+
device_platform: { type: 'string' },
|
|
943
|
+
lease_seconds: { type: 'number' },
|
|
944
|
+
project_id: { type: 'string' }
|
|
945
|
+
},
|
|
946
|
+
required: ['device_fingerprint']
|
|
947
|
+
},
|
|
948
|
+
toCliFlags: args => ({
|
|
949
|
+
'device-fingerprint': args.device_fingerprint,
|
|
950
|
+
'device-hostname': args.device_hostname,
|
|
951
|
+
'device-platform': args.device_platform,
|
|
952
|
+
'lease-seconds': args.lease_seconds,
|
|
953
|
+
'project-id': args.project_id
|
|
954
|
+
}),
|
|
955
|
+
subcommand: 'claim-execution'
|
|
956
|
+
},
|
|
957
|
+
{
|
|
958
|
+
name: 'complete_execution_launch',
|
|
959
|
+
description: 'Mark a claimed execution request as launched.',
|
|
960
|
+
inputSchema: {
|
|
961
|
+
type: 'object',
|
|
962
|
+
properties: {
|
|
963
|
+
request_id: { type: 'string' },
|
|
964
|
+
device_fingerprint: { type: 'string' },
|
|
965
|
+
launched_session_id: { type: 'string' }
|
|
966
|
+
},
|
|
967
|
+
required: ['request_id', 'device_fingerprint']
|
|
968
|
+
},
|
|
969
|
+
toCliFlags: args => ({
|
|
970
|
+
'request-id': args.request_id,
|
|
971
|
+
'device-fingerprint': args.device_fingerprint,
|
|
972
|
+
'launched-session-id': args.launched_session_id
|
|
973
|
+
}),
|
|
974
|
+
subcommand: 'complete-execution-launch'
|
|
975
|
+
},
|
|
976
|
+
{
|
|
977
|
+
name: 'fail_execution_launch',
|
|
978
|
+
description: 'Mark a claimed execution request failed and record the launch error.',
|
|
979
|
+
inputSchema: {
|
|
980
|
+
type: 'object',
|
|
981
|
+
properties: {
|
|
982
|
+
request_id: { type: 'string' },
|
|
983
|
+
device_fingerprint: { type: 'string' },
|
|
984
|
+
error: { type: 'string' }
|
|
985
|
+
},
|
|
986
|
+
required: ['request_id', 'device_fingerprint', 'error']
|
|
987
|
+
},
|
|
988
|
+
toCliFlags: args => ({
|
|
989
|
+
'request-id': args.request_id,
|
|
990
|
+
'device-fingerprint': args.device_fingerprint,
|
|
991
|
+
error: args.error
|
|
992
|
+
}),
|
|
993
|
+
subcommand: 'fail-execution-launch'
|
|
865
994
|
}
|
|
866
995
|
];
|
|
867
996
|
|
|
@@ -176,9 +176,11 @@ To inspect project resolution explicitly:
|
|
|
176
176
|
|
|
177
177
|
```bash
|
|
178
178
|
ovld protocol discover-project
|
|
179
|
+
ovld protocol discover-project --project-id <project_uuid>
|
|
180
|
+
ovld protocol discover-project --working-directory /path/to/repo
|
|
179
181
|
```
|
|
180
182
|
|
|
181
|
-
|
|
183
|
+
Use `--project-id` when the project id is already known. Use `--working-directory` to override cwd path matching. If the runtime has an `OVERLORD_DEVICE_FINGERPRINT`, pass `--device-fingerprint "$OVERLORD_DEVICE_FINGERPRINT"` so resource-directory matching prefers the current device.
|
|
182
184
|
|
|
183
185
|
### Resolving the project ID when you don't have one
|
|
184
186
|
|
|
@@ -192,9 +194,9 @@ When you need a project ID for a protocol command and the ticket prompt did not
|
|
|
192
194
|
|
|
193
195
|
**Over MCP (web agents and hosted tools, where the server cannot see the agent's cwd):**
|
|
194
196
|
|
|
195
|
-
1.
|
|
196
|
-
2. Read `overlord.json` from the directory the user is accessing and pass its project id as `projectId`.
|
|
197
|
-
3. As a last resort, try `workingDirectory` resolution.
|
|
197
|
+
1. `projectId` (hosted MCP) or `project_id` (local shim) if explicitly provided or found in the ticket/context.
|
|
198
|
+
2. Read `overlord.json` from the directory the user is accessing and pass its project id as `projectId` / `project_id`.
|
|
199
|
+
3. As a last resort, try `workingDirectory` / `working_directory` resolution. If a device fingerprint is available, include `deviceFingerprint` / `device_fingerprint`.
|
|
198
200
|
|
|
199
201
|
If `overlord.json` contains more than one project, show the user the project **names** from that file and ask which one to use before calling any protocol command — never silently pick one.
|
|
200
202
|
|
|
@@ -221,12 +223,12 @@ When in doubt, ask yourself: _can this be done entirely inside a terminal or bro
|
|
|
221
223
|
```bash
|
|
222
224
|
ovld protocol read-context --session-key <sessionKey> --ticket-id $TICKET_ID
|
|
223
225
|
ovld protocol write-context --session-key <sessionKey> --ticket-id $TICKET_ID --key "key" --value '"json-value"'
|
|
224
|
-
ovld protocol attachment-list --session-key <sessionKey> --
|
|
225
|
-
ovld protocol attachment-upload-file --session-key <sessionKey> --
|
|
226
|
-
ovld protocol attachment-download-url --session-key <sessionKey> --
|
|
226
|
+
ovld protocol attachment-list --session-key <sessionKey> --objective-id <objective-id>
|
|
227
|
+
ovld protocol attachment-upload-file --session-key <sessionKey> --objective-id <objective-id> --file ./spec.pdf --content-type application/pdf
|
|
228
|
+
ovld protocol attachment-download-url --session-key <sessionKey> --attachment-id <attachment-id>
|
|
227
229
|
```
|
|
228
230
|
|
|
229
|
-
The `attach` and `load-context` responses already include `attachments` and `objectives` arrays — use those for `<attachment-id>` and `<objective-id>` values. Run `attachment-list` mid-session if new files have been uploaded since attach.
|
|
231
|
+
The `attach` and `load-context` responses already include `attachments` and `objectives` arrays — use those for `<attachment-id>` and `<objective-id>` values. Run `attachment-list` mid-session if new files have been uploaded since attach. `--ticket-id` is optional for attachment calls when `--objective-id` or `--attachment-id` lets the server derive the ticket.
|
|
230
232
|
|
|
231
233
|
## Large Artifacts
|
|
232
234
|
|
|
@@ -241,9 +243,10 @@ This keeps the ticket feed readable while preserving the full document in versio
|
|
|
241
243
|
## Defaults And Notes
|
|
242
244
|
|
|
243
245
|
- API requires `agentIdentifier` and `connectionMethod` on attach/connect/prompt. The CLI defaults them to `antigravity`/`cli`; the MCP tool defaults to `mcp`. Override with `--agent` / `--method` when calling from a different runtime.
|
|
244
|
-
- Hosted Overlord MCP (`/functions/v1/mcp`) uses
|
|
246
|
+
- 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.
|
|
247
|
+
- `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.
|
|
245
248
|
- `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`.
|
|
246
|
-
- 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
|
|
249
|
+
- 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.
|
|
247
250
|
- "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.
|
|
248
251
|
- Antigravity CLI does not expose `--model`, `--thinking-level`, or `--temperature` flags. Model selection is managed by the Antigravity platform; do not attempt to pass these at launch.
|
|
249
252
|
- The Overlord plugin is installed by `ovld setup antigravity`. Run this once to install the bundle into `~/.gemini/antigravity-cli/plugins/` and wire the MCP server path.
|
|
@@ -261,4 +264,4 @@ This keeps the ticket feed readable while preserving the full document in versio
|
|
|
261
264
|
- Do not add or commit changes unless the user explicitly asks you to commit.
|
|
262
265
|
- Delivery is the concluding step. After delivering, stop unless the user follows up or the ticket is reopened.
|
|
263
266
|
|
|
264
|
-
<!-- version: 0.1.
|
|
267
|
+
<!-- version: 0.1.1 -->
|
|
@@ -21,6 +21,28 @@ Use this mode when the prompt already contains a ticket ID or explicitly says th
|
|
|
21
21
|
|
|
22
22
|
For full command syntax, flags, phase values, and event types see [reference/cli.md](reference/cli.md).
|
|
23
23
|
|
|
24
|
+
## Tickets vs Objectives
|
|
25
|
+
|
|
26
|
+
**Tickets** represent whole features or goals. **Objectives** are the individual steps to implement that goal — one objective equals one agent prompt.
|
|
27
|
+
|
|
28
|
+
Example:
|
|
29
|
+
```
|
|
30
|
+
Ticket: add CLI command for editing user profile
|
|
31
|
+
- Objective 1: draft plan for this command
|
|
32
|
+
- Objective 2: implement phase 1 of plan
|
|
33
|
+
- Objective 3: implement phase 2 of plan
|
|
34
|
+
- Objective 4: update documentation
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
When to create a ticket vs an objective:
|
|
38
|
+
- **Create a new ticket** when the user describes a distinct feature, bug, or goal that stands on its own.
|
|
39
|
+
- **Add objectives to an existing ticket** when the work is a sequential step toward the same feature or goal already tracked in a ticket.
|
|
40
|
+
|
|
41
|
+
To add further objectives to an existing ticket (Mode 2):
|
|
42
|
+
```
|
|
43
|
+
ovld protocol add-objectives --ticket-id <ticket_id> --objectives-json '[{"objective":"..."},{"objective":"..."}]'
|
|
44
|
+
```
|
|
45
|
+
|
|
24
46
|
## Objective Submission vs Execution
|
|
25
47
|
|
|
26
48
|
Discussing or otherwise opening a ticket from within a chat should cause the draft objective to be marked **submitted** — this signals the ticket is in active discussion with an agent, but not yet being executed. Only an explicit order to execute (e.g. "execute this", "do this", "start working on it") should cause you to **attach** to the ticket and trigger execution.
|
|
@@ -39,6 +61,7 @@ Use this mode when the conversation starts normally and the user asks Claude to
|
|
|
39
61
|
- When `--session-key` and `--ticket-id` are provided, it creates a follow-up draft.
|
|
40
62
|
- When session flags are omitted, it resolves the project by matching current working directory (or `--working-directory`) to Overlord `local_working_directory`, then creates a standalone draft.
|
|
41
63
|
- Pass multiple items in `--objectives-json` when creating ordered steps for the same feature or goal.
|
|
64
|
+
- If the user wants to **add more objectives to an existing ticket** (not create a new ticket), use `ovld protocol add-objectives --ticket-id <ticket_id> --objectives-json '[{"objective":"..."}]'` instead.
|
|
42
65
|
2. Default to `create` for new tickets. Only use `/overlord:prompt` or `ovld protocol prompt --agent claude-code --objectives-json '[{"objective":"..."}]'` when the user explicitly asks to create and execute immediately.
|
|
43
66
|
`prompt` creates the ticket in `execute` status and attaches immediately.
|
|
44
67
|
3. If the user already has a ticket ID and only wants to inspect it, use `/overlord:load` or run `ovld protocol load-context --ticket-id <ticket_id>`.
|
|
@@ -86,5 +109,5 @@ For the `record-change-rationales` command and full payload shape with optional
|
|
|
86
109
|
- [reference/context.md](reference/context.md) — Shared state, attachments, and large artifact policy
|
|
87
110
|
- [reference/shell-escaping.md](reference/shell-escaping.md) — Heredoc stdin piping for special characters in summaries and payloads
|
|
88
111
|
|
|
89
|
-
<!-- version: 0.5.
|
|
112
|
+
<!-- version: 0.5.5 -->
|
|
90
113
|
|
|
@@ -118,9 +118,11 @@ To inspect project resolution explicitly:
|
|
|
118
118
|
|
|
119
119
|
```bash
|
|
120
120
|
ovld protocol discover-project
|
|
121
|
+
ovld protocol discover-project --project-id <project_uuid>
|
|
122
|
+
ovld protocol discover-project --working-directory /path/to/repo
|
|
121
123
|
```
|
|
122
124
|
|
|
123
|
-
|
|
125
|
+
Use `--project-id` when the project id is already known. Use `--working-directory` to override cwd path matching. If the runtime has an `OVERLORD_DEVICE_FINGERPRINT`, pass `--device-fingerprint "$OVERLORD_DEVICE_FINGERPRINT"` so resource-directory matching prefers the current device.
|
|
124
126
|
|
|
125
127
|
### Resolving the project ID when you don't have one
|
|
126
128
|
|
|
@@ -134,9 +136,9 @@ When you need a project ID for a protocol command and the ticket prompt did not
|
|
|
134
136
|
|
|
135
137
|
**Over MCP (web agents and hosted tools, where the server cannot see the agent's cwd):**
|
|
136
138
|
|
|
137
|
-
1.
|
|
138
|
-
2. Read `overlord.json` from the directory the user is accessing and pass its project id as `projectId`.
|
|
139
|
-
3. As a last resort, try `workingDirectory` resolution.
|
|
139
|
+
1. `projectId` (hosted MCP) or `project_id` (local shim) if explicitly provided or found in the ticket/context.
|
|
140
|
+
2. Read `overlord.json` from the directory the user is accessing and pass its project id as `projectId` / `project_id`.
|
|
141
|
+
3. As a last resort, try `workingDirectory` / `working_directory` resolution. If a device fingerprint is available, include `deviceFingerprint` / `device_fingerprint`.
|
|
140
142
|
|
|
141
143
|
If `overlord.json` contains more than one project, show the user the project **names** from that file and ask which one to use before calling any protocol command — never silently pick one.
|
|
142
144
|
|
|
@@ -3,12 +3,12 @@
|
|
|
3
3
|
```bash
|
|
4
4
|
ovld protocol read-context --session-key <sessionKey> --ticket-id $TICKET_ID
|
|
5
5
|
ovld protocol write-context --session-key <sessionKey> --ticket-id $TICKET_ID --key "key" --value '"json-value"'
|
|
6
|
-
ovld protocol attachment-list --session-key <sessionKey> --
|
|
7
|
-
ovld protocol attachment-upload-file --session-key <sessionKey> --
|
|
8
|
-
ovld protocol attachment-download-url --session-key <sessionKey> --
|
|
6
|
+
ovld protocol attachment-list --session-key <sessionKey> --objective-id <objective-id>
|
|
7
|
+
ovld protocol attachment-upload-file --session-key <sessionKey> --objective-id <objective-id> --file ./spec.pdf --content-type application/pdf
|
|
8
|
+
ovld protocol attachment-download-url --session-key <sessionKey> --attachment-id <attachment-id>
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
-
The `attach` and `load-context` responses already include `attachments` and `objectives` arrays — use those for `<attachment-id>` and `<objective-id>` values. Run `attachment-list` mid-session if new files have been uploaded since attach.
|
|
11
|
+
The `attach` and `load-context` responses already include `attachments` and `objectives` arrays — use those for `<attachment-id>` and `<objective-id>` values. Run `attachment-list` mid-session if new files have been uploaded since attach. `--ticket-id` is optional for attachment calls when `--objective-id` or `--attachment-id` lets the server derive the ticket.
|
|
12
12
|
|
|
13
13
|
## Large Artifacts
|
|
14
14
|
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
# MCP And API Defaults
|
|
2
2
|
|
|
3
3
|
- API requires `agentIdentifier` and `connectionMethod` on attach/connect/prompt. The CLI defaults them to `claude-code`/`cli`; the MCP tool defaults to `mcp`. Override with `--agent` / `--method` when calling from a different runtime.
|
|
4
|
-
- Hosted Overlord MCP (`/functions/v1/mcp`) uses
|
|
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
|
+
- `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.
|
|
5
6
|
- `permission-request` is invoked by the Claude Code permission hook installed by the bundle. Agents do not normally call it directly.
|
|
6
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
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`.
|
|
8
|
-
- 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
|
|
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.
|
|
9
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.
|
|
10
11
|
|
|
@@ -21,6 +21,28 @@ Use this mode when the prompt already contains a ticket ID or explicitly says th
|
|
|
21
21
|
|
|
22
22
|
For full command syntax, flags, phase values, and event types see [reference/cli.md](reference/cli.md).
|
|
23
23
|
|
|
24
|
+
## Tickets vs Objectives
|
|
25
|
+
|
|
26
|
+
**Tickets** represent whole features or goals. **Objectives** are the individual steps to implement that goal — one objective equals one agent prompt.
|
|
27
|
+
|
|
28
|
+
Example:
|
|
29
|
+
```
|
|
30
|
+
Ticket: add CLI command for editing user profile
|
|
31
|
+
- Objective 1: draft plan for this command
|
|
32
|
+
- Objective 2: implement phase 1 of plan
|
|
33
|
+
- Objective 3: implement phase 2 of plan
|
|
34
|
+
- Objective 4: update documentation
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
When to create a ticket vs an objective:
|
|
38
|
+
- **Create a new ticket** when the user describes a distinct feature, bug, or goal that stands on its own.
|
|
39
|
+
- **Add objectives to an existing ticket** when the work is a sequential step toward the same feature or goal already tracked in a ticket.
|
|
40
|
+
|
|
41
|
+
To add further objectives to an existing ticket (Mode 2):
|
|
42
|
+
```
|
|
43
|
+
ovld protocol add-objectives --ticket-id <ticket_id> --objectives-json '[{"objective":"..."},{"objective":"..."}]'
|
|
44
|
+
```
|
|
45
|
+
|
|
24
46
|
## Objective Submission vs Execution
|
|
25
47
|
|
|
26
48
|
Discussing or otherwise opening a ticket from within a chat should cause the draft objective to be marked **submitted** — this signals the ticket is in active discussion with an agent, but not yet being executed. Only an explicit order to execute (e.g. "execute this", "do this", "start working on it") should cause you to **attach** to the ticket and trigger execution.
|
|
@@ -39,6 +61,7 @@ Use this mode when the conversation starts normally and the user asks Cursor to
|
|
|
39
61
|
- When `--session-key` and `--ticket-id` are provided, it creates a follow-up draft.
|
|
40
62
|
- When session flags are omitted, it resolves the project by matching current working directory (or `--working-directory`) to Overlord `local_working_directory`, then creates a standalone draft.
|
|
41
63
|
- Pass multiple items in `--objectives-json` when creating ordered steps for the same feature or goal.
|
|
64
|
+
- If the user wants to **add more objectives to an existing ticket** (not create a new ticket), use `ovld protocol add-objectives --ticket-id <ticket_id> --objectives-json '[{"objective":"..."}]'` instead.
|
|
42
65
|
2. Default to `create` for new tickets. Only use `/prompt` or `ovld protocol prompt --agent cursor --objectives-json '[{"objective":"..."}]'` when the user explicitly asks to create and execute immediately.
|
|
43
66
|
`prompt` creates the ticket in `execute` status and attaches immediately.
|
|
44
67
|
3. If the user already has a ticket ID and only wants to inspect it, use `/load` or run `ovld protocol load-context --ticket-id <ticket_id>`.
|
|
@@ -86,5 +109,5 @@ For the `record-change-rationales` command and full payload shape with optional
|
|
|
86
109
|
- [reference/context.md](reference/context.md) — Shared state, attachments, and large artifact policy
|
|
87
110
|
- [reference/shell-escaping.md](reference/shell-escaping.md) — Heredoc stdin piping for special characters in summaries and payloads
|
|
88
111
|
|
|
89
|
-
<!-- version: 0.5.
|
|
112
|
+
<!-- version: 0.5.5 -->
|
|
90
113
|
|
|
@@ -118,9 +118,11 @@ To inspect project resolution explicitly:
|
|
|
118
118
|
|
|
119
119
|
```bash
|
|
120
120
|
ovld protocol discover-project
|
|
121
|
+
ovld protocol discover-project --project-id <project_uuid>
|
|
122
|
+
ovld protocol discover-project --working-directory /path/to/repo
|
|
121
123
|
```
|
|
122
124
|
|
|
123
|
-
|
|
125
|
+
Use `--project-id` when the project id is already known. Use `--working-directory` to override cwd path matching. If the runtime has an `OVERLORD_DEVICE_FINGERPRINT`, pass `--device-fingerprint "$OVERLORD_DEVICE_FINGERPRINT"` so resource-directory matching prefers the current device.
|
|
124
126
|
|
|
125
127
|
### Resolving the project ID when you don't have one
|
|
126
128
|
|
|
@@ -134,9 +136,9 @@ When you need a project ID for a protocol command and the ticket prompt did not
|
|
|
134
136
|
|
|
135
137
|
**Over MCP (web agents and hosted tools, where the server cannot see the agent's cwd):**
|
|
136
138
|
|
|
137
|
-
1.
|
|
138
|
-
2. Read `overlord.json` from the directory the user is accessing and pass its project id as `projectId`.
|
|
139
|
-
3. As a last resort, try `workingDirectory` resolution.
|
|
139
|
+
1. `projectId` (hosted MCP) or `project_id` (local shim) if explicitly provided or found in the ticket/context.
|
|
140
|
+
2. Read `overlord.json` from the directory the user is accessing and pass its project id as `projectId` / `project_id`.
|
|
141
|
+
3. As a last resort, try `workingDirectory` / `working_directory` resolution. If a device fingerprint is available, include `deviceFingerprint` / `device_fingerprint`.
|
|
140
142
|
|
|
141
143
|
If `overlord.json` contains more than one project, show the user the project **names** from that file and ask which one to use before calling any protocol command — never silently pick one.
|
|
142
144
|
|
|
@@ -3,12 +3,12 @@
|
|
|
3
3
|
```bash
|
|
4
4
|
ovld protocol read-context --session-key <sessionKey> --ticket-id $TICKET_ID
|
|
5
5
|
ovld protocol write-context --session-key <sessionKey> --ticket-id $TICKET_ID --key "key" --value '"json-value"'
|
|
6
|
-
ovld protocol attachment-list --session-key <sessionKey> --
|
|
7
|
-
ovld protocol attachment-upload-file --session-key <sessionKey> --
|
|
8
|
-
ovld protocol attachment-download-url --session-key <sessionKey> --
|
|
6
|
+
ovld protocol attachment-list --session-key <sessionKey> --objective-id <objective-id>
|
|
7
|
+
ovld protocol attachment-upload-file --session-key <sessionKey> --objective-id <objective-id> --file ./spec.pdf --content-type application/pdf
|
|
8
|
+
ovld protocol attachment-download-url --session-key <sessionKey> --attachment-id <attachment-id>
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
-
The `attach` and `load-context` responses already include `attachments` and `objectives` arrays — use those for `<attachment-id>` and `<objective-id>` values. Run `attachment-list` mid-session if new files have been uploaded since attach.
|
|
11
|
+
The `attach` and `load-context` responses already include `attachments` and `objectives` arrays — use those for `<attachment-id>` and `<objective-id>` values. Run `attachment-list` mid-session if new files have been uploaded since attach. `--ticket-id` is optional for attachment calls when `--objective-id` or `--attachment-id` lets the server derive the ticket.
|
|
12
12
|
|
|
13
13
|
## Large Artifacts
|
|
14
14
|
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
# MCP And API Defaults
|
|
2
2
|
|
|
3
3
|
- API requires `agentIdentifier` and `connectionMethod` on attach/connect/prompt. The CLI defaults them to `cursor`/`cli`; the MCP tool defaults to `mcp`. Override with `--agent` / `--method` when calling from a different runtime.
|
|
4
|
-
- Hosted Overlord MCP (`/functions/v1/mcp`) uses
|
|
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
|
+
- `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.
|
|
5
6
|
- `permission-request` is invoked by the Cursor permission hook installed by the bundle. Agents do not normally call it directly.
|
|
6
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
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`.
|
|
8
|
-
- 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
|
|
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.
|
|
9
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.
|
|
10
11
|
|
|
@@ -40,6 +40,7 @@ Tool names match the hosted Overlord MCP server (`supabase/functions/mcp/tools.t
|
|
|
40
40
|
- Progress and review flow: `update`, `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
|
+
- Local runner queue: `request_execution`, `claim_execution`, `complete_execution_launch`, `fail_execution_launch`
|
|
43
44
|
|
|
44
45
|
The MCP server shells into the installed `ovld` binary so the plugin stays aligned with the shipped CLI behavior instead of depending on this repository checkout.
|
|
45
46
|
|
|
@@ -57,18 +57,40 @@ function execFileWithOptionalInput(file, args, options, input) {
|
|
|
57
57
|
const tools = [
|
|
58
58
|
{
|
|
59
59
|
name: 'discover_project',
|
|
60
|
-
description:
|
|
60
|
+
description:
|
|
61
|
+
'Resolve an Overlord project by explicit project_id or by matching a working directory.',
|
|
61
62
|
inputSchema: {
|
|
62
63
|
type: 'object',
|
|
63
64
|
properties: {
|
|
65
|
+
project_id: {
|
|
66
|
+
type: 'string',
|
|
67
|
+
description: 'Project UUID to resolve directly. Skips working-directory matching.'
|
|
68
|
+
},
|
|
64
69
|
working_directory: {
|
|
65
70
|
type: 'string',
|
|
66
71
|
description: 'Directory to match. Defaults to the current workspace.'
|
|
72
|
+
},
|
|
73
|
+
device_fingerprint: {
|
|
74
|
+
type: 'string',
|
|
75
|
+
description:
|
|
76
|
+
'Optional stable device fingerprint. When provided, matching prefers resource directories for this registered device.'
|
|
77
|
+
},
|
|
78
|
+
device_hostname: {
|
|
79
|
+
type: 'string',
|
|
80
|
+
description: 'Optional hostname to register/update with device_fingerprint.'
|
|
81
|
+
},
|
|
82
|
+
device_platform: {
|
|
83
|
+
type: 'string',
|
|
84
|
+
description: 'Optional platform string, e.g. darwin, linux, or windows.'
|
|
67
85
|
}
|
|
68
86
|
}
|
|
69
87
|
},
|
|
70
88
|
toCliFlags: args => ({
|
|
71
|
-
'
|
|
89
|
+
'project-id': args.project_id,
|
|
90
|
+
'working-directory': args.working_directory,
|
|
91
|
+
'device-fingerprint': args.device_fingerprint,
|
|
92
|
+
'device-hostname': args.device_hostname,
|
|
93
|
+
'device-platform': args.device_platform
|
|
72
94
|
}),
|
|
73
95
|
subcommand: 'discover-project'
|
|
74
96
|
},
|
|
@@ -437,7 +459,7 @@ const tools = [
|
|
|
437
459
|
query: { type: 'string' },
|
|
438
460
|
limit: { type: 'number' }
|
|
439
461
|
},
|
|
440
|
-
required: ['session_key'
|
|
462
|
+
required: ['session_key']
|
|
441
463
|
},
|
|
442
464
|
toCliFlags: args => ({
|
|
443
465
|
'session-key': args.session_key,
|
|
@@ -583,7 +605,7 @@ const tools = [
|
|
|
583
605
|
},
|
|
584
606
|
objective_id: { type: 'string' }
|
|
585
607
|
},
|
|
586
|
-
required: ['session_key'
|
|
608
|
+
required: ['session_key']
|
|
587
609
|
},
|
|
588
610
|
toCliFlags: args => ({
|
|
589
611
|
'session-key': args.session_key,
|
|
@@ -610,7 +632,7 @@ const tools = [
|
|
|
610
632
|
file_size: { type: 'number' },
|
|
611
633
|
metadata: { type: 'object' }
|
|
612
634
|
},
|
|
613
|
-
required: ['session_key', '
|
|
635
|
+
required: ['session_key', 'objective_id', 'file_name']
|
|
614
636
|
},
|
|
615
637
|
toCliFlags: args => ({
|
|
616
638
|
'session-key': args.session_key,
|
|
@@ -643,7 +665,7 @@ const tools = [
|
|
|
643
665
|
file_size: { type: 'number' },
|
|
644
666
|
metadata: { type: 'object' }
|
|
645
667
|
},
|
|
646
|
-
required: ['session_key', '
|
|
668
|
+
required: ['session_key', 'objective_id', 'storage_path', 'label']
|
|
647
669
|
},
|
|
648
670
|
toCliFlags: args => ({
|
|
649
671
|
'session-key': args.session_key,
|
|
@@ -673,7 +695,7 @@ const tools = [
|
|
|
673
695
|
storage_path: { type: 'string' },
|
|
674
696
|
expires_in: { type: 'number' }
|
|
675
697
|
},
|
|
676
|
-
required: ['session_key'
|
|
698
|
+
required: ['session_key']
|
|
677
699
|
},
|
|
678
700
|
toCliFlags: args => ({
|
|
679
701
|
'session-key': args.session_key,
|
|
@@ -704,7 +726,7 @@ const tools = [
|
|
|
704
726
|
content_type: { type: 'string' },
|
|
705
727
|
metadata: { type: 'object' }
|
|
706
728
|
},
|
|
707
|
-
required: ['session_key', '
|
|
729
|
+
required: ['session_key', 'objective_id', 'file']
|
|
708
730
|
},
|
|
709
731
|
toCliFlags: args => ({
|
|
710
732
|
'session-key': args.session_key,
|
|
@@ -861,6 +883,113 @@ const tools = [
|
|
|
861
883
|
: {})
|
|
862
884
|
}),
|
|
863
885
|
subcommand: 'update-project-resource'
|
|
886
|
+
},
|
|
887
|
+
{
|
|
888
|
+
name: 'request_execution',
|
|
889
|
+
description:
|
|
890
|
+
'Queue an objective for local or remote runner execution. Manual Run and auto-advance use this durable queue.',
|
|
891
|
+
inputSchema: {
|
|
892
|
+
type: 'object',
|
|
893
|
+
properties: {
|
|
894
|
+
ticket_id: { type: 'string' },
|
|
895
|
+
objective_id: { type: 'string' },
|
|
896
|
+
requested_from: { type: 'string' },
|
|
897
|
+
idempotency_key: { type: 'string' },
|
|
898
|
+
agent: { type: 'string' },
|
|
899
|
+
model: { type: 'string' },
|
|
900
|
+
thinking: { type: 'string' },
|
|
901
|
+
launch_mode: { type: 'string', enum: ['run', 'ask'] },
|
|
902
|
+
working_directory: { type: 'string' },
|
|
903
|
+
ssh_command: { type: 'string' },
|
|
904
|
+
remote_working_directory: { type: 'string' },
|
|
905
|
+
server_multiplexer: { type: 'string', enum: ['none', 'tmux'] },
|
|
906
|
+
tmux_command: { type: 'string' },
|
|
907
|
+
target_kind: { type: 'string', enum: ['any', 'local', 'ssh'] },
|
|
908
|
+
target_device_id: { type: 'string' },
|
|
909
|
+
target_resource_id: { type: 'string' }
|
|
910
|
+
},
|
|
911
|
+
required: ['ticket_id']
|
|
912
|
+
},
|
|
913
|
+
toCliFlags: args => ({
|
|
914
|
+
'ticket-id': args.ticket_id,
|
|
915
|
+
'objective-id': args.objective_id,
|
|
916
|
+
'requested-from': args.requested_from,
|
|
917
|
+
'idempotency-key': args.idempotency_key,
|
|
918
|
+
agent: args.agent,
|
|
919
|
+
model: args.model,
|
|
920
|
+
thinking: args.thinking,
|
|
921
|
+
'launch-mode': args.launch_mode,
|
|
922
|
+
'working-directory': args.working_directory,
|
|
923
|
+
'ssh-command': args.ssh_command,
|
|
924
|
+
'remote-working-directory': args.remote_working_directory,
|
|
925
|
+
'server-multiplexer': args.server_multiplexer,
|
|
926
|
+
'tmux-command': args.tmux_command,
|
|
927
|
+
'target-kind': args.target_kind,
|
|
928
|
+
'target-device-id': args.target_device_id,
|
|
929
|
+
'target-resource-id': args.target_resource_id
|
|
930
|
+
}),
|
|
931
|
+
subcommand: 'request-execution'
|
|
932
|
+
},
|
|
933
|
+
{
|
|
934
|
+
name: 'claim_execution',
|
|
935
|
+
description: 'Claim one queued execution request for this device.',
|
|
936
|
+
inputSchema: {
|
|
937
|
+
type: 'object',
|
|
938
|
+
properties: {
|
|
939
|
+
device_fingerprint: { type: 'string' },
|
|
940
|
+
device_hostname: { type: 'string' },
|
|
941
|
+
device_platform: { type: 'string' },
|
|
942
|
+
lease_seconds: { type: 'number' },
|
|
943
|
+
project_id: { type: 'string' }
|
|
944
|
+
},
|
|
945
|
+
required: ['device_fingerprint']
|
|
946
|
+
},
|
|
947
|
+
toCliFlags: args => ({
|
|
948
|
+
'device-fingerprint': args.device_fingerprint,
|
|
949
|
+
'device-hostname': args.device_hostname,
|
|
950
|
+
'device-platform': args.device_platform,
|
|
951
|
+
'lease-seconds': args.lease_seconds,
|
|
952
|
+
'project-id': args.project_id
|
|
953
|
+
}),
|
|
954
|
+
subcommand: 'claim-execution'
|
|
955
|
+
},
|
|
956
|
+
{
|
|
957
|
+
name: 'complete_execution_launch',
|
|
958
|
+
description: 'Mark a claimed execution request as launched.',
|
|
959
|
+
inputSchema: {
|
|
960
|
+
type: 'object',
|
|
961
|
+
properties: {
|
|
962
|
+
request_id: { type: 'string' },
|
|
963
|
+
device_fingerprint: { type: 'string' },
|
|
964
|
+
launched_session_id: { type: 'string' }
|
|
965
|
+
},
|
|
966
|
+
required: ['request_id', 'device_fingerprint']
|
|
967
|
+
},
|
|
968
|
+
toCliFlags: args => ({
|
|
969
|
+
'request-id': args.request_id,
|
|
970
|
+
'device-fingerprint': args.device_fingerprint,
|
|
971
|
+
'launched-session-id': args.launched_session_id
|
|
972
|
+
}),
|
|
973
|
+
subcommand: 'complete-execution-launch'
|
|
974
|
+
},
|
|
975
|
+
{
|
|
976
|
+
name: 'fail_execution_launch',
|
|
977
|
+
description: 'Mark a claimed execution request failed and record the launch error.',
|
|
978
|
+
inputSchema: {
|
|
979
|
+
type: 'object',
|
|
980
|
+
properties: {
|
|
981
|
+
request_id: { type: 'string' },
|
|
982
|
+
device_fingerprint: { type: 'string' },
|
|
983
|
+
error: { type: 'string' }
|
|
984
|
+
},
|
|
985
|
+
required: ['request_id', 'device_fingerprint', 'error']
|
|
986
|
+
},
|
|
987
|
+
toCliFlags: args => ({
|
|
988
|
+
'request-id': args.request_id,
|
|
989
|
+
'device-fingerprint': args.device_fingerprint,
|
|
990
|
+
error: args.error
|
|
991
|
+
}),
|
|
992
|
+
subcommand: 'fail-execution-launch'
|
|
864
993
|
}
|
|
865
994
|
];
|
|
866
995
|
const searchTicketsTool = {
|
|
@@ -21,6 +21,28 @@ Use this mode when the prompt already contains a ticket ID or explicitly says th
|
|
|
21
21
|
|
|
22
22
|
For full command syntax, flags, phase values, and event types see [reference/cli.md](reference/cli.md).
|
|
23
23
|
|
|
24
|
+
## Tickets vs Objectives
|
|
25
|
+
|
|
26
|
+
**Tickets** represent whole features or goals. **Objectives** are the individual steps to implement that goal — one objective equals one agent prompt.
|
|
27
|
+
|
|
28
|
+
Example:
|
|
29
|
+
```
|
|
30
|
+
Ticket: add CLI command for editing user profile
|
|
31
|
+
- Objective 1: draft plan for this command
|
|
32
|
+
- Objective 2: implement phase 1 of plan
|
|
33
|
+
- Objective 3: implement phase 2 of plan
|
|
34
|
+
- Objective 4: update documentation
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
When to create a ticket vs an objective:
|
|
38
|
+
- **Create a new ticket** when the user describes a distinct feature, bug, or goal that stands on its own.
|
|
39
|
+
- **Add objectives to an existing ticket** when the work is a sequential step toward the same feature or goal already tracked in a ticket.
|
|
40
|
+
|
|
41
|
+
To add further objectives to an existing ticket (Mode 2):
|
|
42
|
+
```
|
|
43
|
+
ovld protocol add-objectives --ticket-id <ticket_id> --objectives-json '[{"objective":"..."},{"objective":"..."}]'
|
|
44
|
+
```
|
|
45
|
+
|
|
24
46
|
## Objective Submission vs Execution
|
|
25
47
|
|
|
26
48
|
Discussing or otherwise opening a ticket from within a chat should cause the draft objective to be marked **submitted** — this signals the ticket is in active discussion with an agent, but not yet being executed. Only an explicit order to execute (e.g. "execute this", "do this", "start working on it") should cause you to **attach** to the ticket and trigger execution.
|
|
@@ -39,6 +61,7 @@ Use this mode when the conversation starts normally and the user asks Codex to c
|
|
|
39
61
|
- When `--session-key` and `--ticket-id` are provided, it creates a follow-up draft.
|
|
40
62
|
- When session flags are omitted, it resolves the project by matching current working directory (or `--working-directory`) to Overlord `local_working_directory`, then creates a standalone draft.
|
|
41
63
|
- Pass multiple items in `--objectives-json` when creating ordered steps for the same feature or goal.
|
|
64
|
+
- If the user wants to **add more objectives to an existing ticket** (not create a new ticket), use `ovld protocol add-objectives --ticket-id <ticket_id> --objectives-json '[{"objective":"..."}]'` instead.
|
|
42
65
|
2. Default to `create` for new tickets. Only use `ovld protocol prompt --agent codex --objectives-json '[{"objective":"..."}]'` when the user explicitly asks to create and execute immediately.
|
|
43
66
|
`prompt` creates the ticket in `execute` status and attaches immediately.
|
|
44
67
|
3. If the user already has a ticket ID and only wants to inspect it, run `ovld protocol load-context --ticket-id <ticket_id>`.
|
|
@@ -87,5 +110,5 @@ For the `record-change-rationales` command and full payload shape with optional
|
|
|
87
110
|
- [reference/context.md](reference/context.md) — Shared state, attachments, and large artifact policy
|
|
88
111
|
- [reference/shell-escaping.md](reference/shell-escaping.md) — Heredoc stdin piping for special characters in summaries and payloads
|
|
89
112
|
|
|
90
|
-
<!-- version: 0.5.
|
|
113
|
+
<!-- version: 0.5.5 -->
|
|
91
114
|
|
|
@@ -118,9 +118,11 @@ To inspect project resolution explicitly:
|
|
|
118
118
|
|
|
119
119
|
```bash
|
|
120
120
|
ovld protocol discover-project
|
|
121
|
+
ovld protocol discover-project --project-id <project_uuid>
|
|
122
|
+
ovld protocol discover-project --working-directory /path/to/repo
|
|
121
123
|
```
|
|
122
124
|
|
|
123
|
-
|
|
125
|
+
Use `--project-id` when the project id is already known. Use `--working-directory` to override cwd path matching. If the runtime has an `OVERLORD_DEVICE_FINGERPRINT`, pass `--device-fingerprint "$OVERLORD_DEVICE_FINGERPRINT"` so resource-directory matching prefers the current device.
|
|
124
126
|
|
|
125
127
|
### Resolving the project ID when you don't have one
|
|
126
128
|
|
|
@@ -134,9 +136,9 @@ When you need a project ID for a protocol command and the ticket prompt did not
|
|
|
134
136
|
|
|
135
137
|
**Over MCP (web agents and hosted tools, where the server cannot see the agent's cwd):**
|
|
136
138
|
|
|
137
|
-
1.
|
|
138
|
-
2. Read `overlord.json` from the directory the user is accessing and pass its project id as `projectId`.
|
|
139
|
-
3. As a last resort, try `workingDirectory` resolution.
|
|
139
|
+
1. `projectId` (hosted MCP) or `project_id` (local shim) if explicitly provided or found in the ticket/context.
|
|
140
|
+
2. Read `overlord.json` from the directory the user is accessing and pass its project id as `projectId` / `project_id`.
|
|
141
|
+
3. As a last resort, try `workingDirectory` / `working_directory` resolution. If a device fingerprint is available, include `deviceFingerprint` / `device_fingerprint`.
|
|
140
142
|
|
|
141
143
|
If `overlord.json` contains more than one project, show the user the project **names** from that file and ask which one to use before calling any protocol command — never silently pick one.
|
|
142
144
|
|
|
@@ -3,12 +3,12 @@
|
|
|
3
3
|
```bash
|
|
4
4
|
ovld protocol read-context --session-key <sessionKey> --ticket-id $TICKET_ID
|
|
5
5
|
ovld protocol write-context --session-key <sessionKey> --ticket-id $TICKET_ID --key "key" --value '"json-value"'
|
|
6
|
-
ovld protocol attachment-list --session-key <sessionKey> --
|
|
7
|
-
ovld protocol attachment-upload-file --session-key <sessionKey> --
|
|
8
|
-
ovld protocol attachment-download-url --session-key <sessionKey> --
|
|
6
|
+
ovld protocol attachment-list --session-key <sessionKey> --objective-id <objective-id>
|
|
7
|
+
ovld protocol attachment-upload-file --session-key <sessionKey> --objective-id <objective-id> --file ./spec.pdf --content-type application/pdf
|
|
8
|
+
ovld protocol attachment-download-url --session-key <sessionKey> --attachment-id <attachment-id>
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
-
The `attach` and `load-context` responses already include `attachments` and `objectives` arrays — use those for `<attachment-id>` and `<objective-id>` values. Run `attachment-list` mid-session if new files have been uploaded since attach.
|
|
11
|
+
The `attach` and `load-context` responses already include `attachments` and `objectives` arrays — use those for `<attachment-id>` and `<objective-id>` values. Run `attachment-list` mid-session if new files have been uploaded since attach. `--ticket-id` is optional for attachment calls when `--objective-id` or `--attachment-id` lets the server derive the ticket.
|
|
12
12
|
|
|
13
13
|
## Large Artifacts
|
|
14
14
|
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
# MCP And API Defaults
|
|
2
2
|
|
|
3
3
|
- API requires `agentIdentifier` and `connectionMethod` on attach/connect/prompt. The CLI defaults them to `codex`/`cli`; the MCP tool defaults to `mcp`. Override with `--agent` / `--method` when calling from a different runtime.
|
|
4
|
-
- Hosted Overlord MCP (`/functions/v1/mcp`) uses
|
|
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
|
+
- `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.
|
|
5
6
|
- `permission-request` is invoked by the Codex permission hook installed by the bundle. Agents do not normally call it directly.
|
|
6
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
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`.
|
|
8
|
-
- 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
|
|
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.
|
|
9
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.
|
|
10
11
|
|