@atollhq/skill-codex 0.4.23 → 0.4.25
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 +21 -7
- package/bin/install.mjs +179 -43
- package/package.json +1 -1
- package/skill/SKILL.md +93 -0
- package/skill/references/api-endpoints.md +70 -4
- package/skill/references/api-fields.md +78 -1
package/README.md
CHANGED
|
@@ -6,13 +6,27 @@ Gives your Codex agent the ability to manage tasks, goals, KPIs, initiatives, mi
|
|
|
6
6
|
|
|
7
7
|
## Install
|
|
8
8
|
|
|
9
|
+
Install or refresh the local skill files without configuring credentials:
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npx --yes @atollhq/skill-codex@latest
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Bare invocation and `--install-only` only update `~/.codex/skills/atoll/`, the profile-neutral routing hint, and compatibility references. They do not inspect or change Atoll credentials, profiles, shell files, or repo configuration, even when `ATOLL_*` variables are present.
|
|
16
|
+
|
|
17
|
+
Configure a named profile explicitly:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npx --yes @atollhq/skill-codex@latest --profile agent-a --key sk_atoll_... --org org-uuid --project project-id --team team-id
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
For intentional environment configuration, use `--configure`:
|
|
24
|
+
|
|
9
25
|
```bash
|
|
10
|
-
npx @atollhq/skill-codex@latest --
|
|
11
|
-
# or
|
|
12
|
-
ATOLL_API_KEY=sk_atoll_... ATOLL_ORG_ID=your-org-id npx @atollhq/skill-codex@latest
|
|
26
|
+
ATOLL_API_KEY=sk_atoll_... ATOLL_ORG_ID=org-uuid npx --yes @atollhq/skill-codex@latest --configure
|
|
13
27
|
```
|
|
14
28
|
|
|
15
|
-
|
|
29
|
+
Configuration mode supports `--project`, `--team`, and `--base-url`. Use `--no-project`, `--no-team`, or `--no-base-url` to clear saved defaults. Pass `--profile` to store credentials and defaults only in that named Atoll CLI profile. The installer does not write global `ATOLL_*` exports in profile mode. Use `atoll --profile agent-a ...` for profile-scoped commands.
|
|
16
30
|
|
|
17
31
|
For multi-org setups, keep global Codex instructions neutral and bind profiles per repo:
|
|
18
32
|
|
|
@@ -25,16 +39,16 @@ npx @atollhq/skill-codex@latest --profile agent-a --key sk_atoll_... --org your-
|
|
|
25
39
|
|
|
26
40
|
Get an agent API key from **Agents** in the Atoll app. Integration keys are managed from **Settings > Integrations**.
|
|
27
41
|
|
|
28
|
-
|
|
42
|
+
Every invocation installs the local skill assets, routing hint, and compatibility references. Configuration mode additionally:
|
|
29
43
|
|
|
30
44
|
1. Installs the `atoll` skill to `~/.codex/skills/atoll/`
|
|
31
45
|
2. Appends (or updates) a small profile-neutral Atoll skill routing hint in `~/.codex/AGENTS.md`
|
|
32
46
|
3. Copies API reference files to `~/.codex/atoll-references/`
|
|
33
47
|
4. Creates or updates the named Atoll CLI profile when `--profile` is provided
|
|
34
|
-
5. Appends Atoll env var exports to your shell profile (`~/.zshrc` or `~/.bashrc`)
|
|
48
|
+
5. Appends Atoll env var exports to your shell profile (`~/.zshrc` or `~/.bashrc`) when `--configure` is used without a profile
|
|
35
49
|
6. Optionally writes repo-local profile guidance when `--write-project-instructions` is provided
|
|
36
50
|
|
|
37
|
-
For profile mode, Codex has the Atoll skill immediately, global Codex guidance points to that skill without embedding the full Atoll guide, and terminal commands can use `atoll --profile agent-a ...`. For env-var mode, the installer writes `ATOLL_ENV_MODE=1` with the credential exports; open a fresh shell or `source` your profile.
|
|
51
|
+
For profile mode, Codex has the Atoll skill immediately, global Codex guidance points to that skill without embedding the full Atoll guide, and terminal commands can use `atoll --profile agent-a ...`. For explicitly requested env-var mode, the installer writes `ATOLL_ENV_MODE=1` with the credential exports; open a fresh shell or `source` your profile.
|
|
38
52
|
|
|
39
53
|
Use `@latest` in the `npx` command so npm does not reuse a stale cached installer. In profile mode, the installer prints its package version and a verification command; run `atoll --profile agent-a agent-context --json` if you need to confirm the profile was created.
|
|
40
54
|
|
package/bin/install.mjs
CHANGED
|
@@ -22,45 +22,86 @@ import { fileURLToPath } from 'node:url'
|
|
|
22
22
|
|
|
23
23
|
const __dirname = dirname(fileURLToPath(import.meta.url))
|
|
24
24
|
const packageJson = JSON.parse(readFileSync(join(__dirname, '..', 'package.json'), 'utf-8'))
|
|
25
|
+
const configurationFlags = new Set([
|
|
26
|
+
'--configure',
|
|
27
|
+
'--profile',
|
|
28
|
+
'--key',
|
|
29
|
+
'--org',
|
|
30
|
+
'--project',
|
|
31
|
+
'--no-project',
|
|
32
|
+
'--team',
|
|
33
|
+
'--no-team',
|
|
34
|
+
'--base-url',
|
|
35
|
+
'--no-base-url',
|
|
36
|
+
'--write-project-instructions',
|
|
37
|
+
'--project-dir',
|
|
38
|
+
'--instruction-files',
|
|
39
|
+
'--force-project-instructions',
|
|
40
|
+
])
|
|
41
|
+
const valueFlags = {
|
|
42
|
+
'--profile': 'profile',
|
|
43
|
+
'--key': 'key',
|
|
44
|
+
'--org': 'org',
|
|
45
|
+
'--project': 'project',
|
|
46
|
+
'--team': 'team',
|
|
47
|
+
'--base-url': 'baseUrl',
|
|
48
|
+
'--project-dir': 'projectDir',
|
|
49
|
+
'--instruction-files': 'instructionFiles',
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function hasConfigurationIntent(argv) {
|
|
53
|
+
return argv.slice(2).some((arg) => configurationFlags.has(arg.split('=', 1)[0]))
|
|
54
|
+
}
|
|
25
55
|
|
|
26
56
|
function parseArgs(argv) {
|
|
27
57
|
const args = {}
|
|
28
58
|
for (let i = 2; i < argv.length; i++) {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
else if (
|
|
42
|
-
else if (
|
|
59
|
+
const argument = argv[i]
|
|
60
|
+
const separator = argument.indexOf('=')
|
|
61
|
+
const flag = separator === -1 ? argument : argument.slice(0, separator)
|
|
62
|
+
const inlineValue = separator === -1 ? undefined : argument.slice(separator + 1)
|
|
63
|
+
const nextValue = inlineValue ?? argv[i + 1]
|
|
64
|
+
const valueKey = valueFlags[flag]
|
|
65
|
+
if (valueKey) {
|
|
66
|
+
if (!nextValue || nextValue.startsWith('-')) {
|
|
67
|
+
throw new Error(`${flag} requires a non-empty value`)
|
|
68
|
+
}
|
|
69
|
+
args[valueKey] = nextValue
|
|
70
|
+
if (inlineValue === undefined) i++
|
|
71
|
+
} else if (flag === '--no-project') args.clearProject = true
|
|
72
|
+
else if (flag === '--no-team') args.clearTeam = true
|
|
73
|
+
else if (flag === '--no-base-url') args.clearBaseUrl = true
|
|
74
|
+
else if (flag === '--install-only') args.installOnly = true
|
|
75
|
+
else if (flag === '--configure') args.configure = true
|
|
76
|
+
else if (flag === '--write-project-instructions') args.writeProjectInstructions = true
|
|
77
|
+
else if (flag === '--force-project-instructions') args.forceProjectInstructions = true
|
|
78
|
+
else if (flag === '--help' || flag === '-h') args.help = true
|
|
79
|
+
else throw new Error(`Unknown option: ${flag}`)
|
|
43
80
|
}
|
|
44
81
|
return args
|
|
45
82
|
}
|
|
46
83
|
|
|
47
84
|
function printUsage() {
|
|
48
85
|
console.log(`
|
|
49
|
-
Usage: npx @atollhq/skill-codex@latest
|
|
50
|
-
or:
|
|
86
|
+
Usage: npx @atollhq/skill-codex@latest --install-only
|
|
87
|
+
or: npx @atollhq/skill-codex@latest --configure [--profile <name>] --key <api-key> --org <org-id> [--project <id>] [--team <id-or-slug>] [--base-url <url>]
|
|
88
|
+
or: ATOLL_API_KEY=<api-key> ATOLL_ORG_ID=<org-id> npx @atollhq/skill-codex@latest --configure
|
|
51
89
|
|
|
52
90
|
Options:
|
|
53
|
-
--profile Atoll CLI profile name to create/update.
|
|
54
|
-
--key Atoll API key (sk_atoll_...).
|
|
55
|
-
--org Organization ID.
|
|
56
|
-
--project Default project ID.
|
|
91
|
+
--profile Atoll CLI profile name to create/update. Enables configuration mode.
|
|
92
|
+
--key Atoll API key (sk_atoll_...). Used in configuration mode; defaults to ATOLL_API_KEY.
|
|
93
|
+
--org Organization ID. Used in configuration mode; defaults to ATOLL_ORG_ID.
|
|
94
|
+
--project Default project ID. Used in configuration mode; defaults to ATOLL_PROJECT.
|
|
57
95
|
--no-project Clear any saved default project.
|
|
58
|
-
--team Default team ID or slug.
|
|
96
|
+
--team Default team ID or slug. Used in configuration mode; defaults to ATOLL_TEAM.
|
|
59
97
|
--no-team Clear any saved default team.
|
|
60
|
-
--base-url Atoll base URL.
|
|
98
|
+
--base-url Atoll base URL. Used in configuration mode; defaults to ATOLL_BASE_URL.
|
|
61
99
|
--no-base-url Clear any saved custom base URL.
|
|
100
|
+
--install-only
|
|
101
|
+
Install or refresh local skill files without reading or changing credentials.
|
|
102
|
+
--configure Explicitly enable profile or environment credential configuration.
|
|
62
103
|
--write-project-instructions
|
|
63
|
-
Write a small repo-local Atoll profile block. Requires --profile.
|
|
104
|
+
Write a small repo-local Atoll profile block. Requires --configure and --profile.
|
|
64
105
|
--project-dir
|
|
65
106
|
Directory for repo-local instructions. Defaults to the current directory.
|
|
66
107
|
--instruction-files
|
|
@@ -72,24 +113,35 @@ Options:
|
|
|
72
113
|
Installs the Atoll integration for Codex CLI:
|
|
73
114
|
- Installs the atoll skill to ~/.codex/skills/atoll/
|
|
74
115
|
- Writes a small AGENTS.md routing hint to ~/.codex/
|
|
75
|
-
-
|
|
116
|
+
- Leaves authentication and profile configuration unchanged by default
|
|
117
|
+
- Creates/updates credentials only when --configure or another configuration flag is provided
|
|
76
118
|
- Optionally writes repo-local AGENTS.md/CLAUDE.md profile guidance with --write-project-instructions
|
|
77
|
-
- Otherwise writes Atoll env vars to your shell profile for env-var mode
|
|
78
119
|
`)
|
|
79
120
|
}
|
|
80
121
|
|
|
81
122
|
const args = parseArgs(process.argv)
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
if (args.
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
else args.baseUrl ??= process.env.ATOLL_BASE_URL
|
|
123
|
+
const configurationIntent = hasConfigurationIntent(process.argv)
|
|
124
|
+
|
|
125
|
+
if (args.installOnly && configurationIntent) {
|
|
126
|
+
console.error('Error: --install-only cannot be combined with credential or profile configuration flags')
|
|
127
|
+
printUsage()
|
|
128
|
+
process.exit(1)
|
|
129
|
+
}
|
|
90
130
|
|
|
91
131
|
if (args.help) { printUsage(); process.exit(0) }
|
|
92
132
|
|
|
133
|
+
const configureMode = configurationIntent
|
|
134
|
+
if (configureMode) {
|
|
135
|
+
args.key ??= process.env.ATOLL_API_KEY
|
|
136
|
+
args.org ??= process.env.ATOLL_ORG_ID
|
|
137
|
+
if (args.clearProject) delete args.project
|
|
138
|
+
else args.project ??= process.env.ATOLL_PROJECT
|
|
139
|
+
if (args.clearTeam) delete args.team
|
|
140
|
+
else args.team ??= process.env.ATOLL_TEAM
|
|
141
|
+
if (args.clearBaseUrl) delete args.baseUrl
|
|
142
|
+
else args.baseUrl ??= process.env.ATOLL_BASE_URL
|
|
143
|
+
}
|
|
144
|
+
|
|
93
145
|
console.log(`Running @atollhq/skill-codex installer v${packageJson.version}`)
|
|
94
146
|
|
|
95
147
|
const instructionFileChoices = (args.instructionFiles ?? 'agents')
|
|
@@ -118,13 +170,13 @@ if (args.writeProjectInstructions && !/^[A-Za-z0-9][A-Za-z0-9._-]*$/.test(args.p
|
|
|
118
170
|
process.exit(1)
|
|
119
171
|
}
|
|
120
172
|
|
|
121
|
-
if (!args.key || !args.org) {
|
|
173
|
+
if (configureMode && (!args.key || !args.org)) {
|
|
122
174
|
console.error('Error: provide --key and --org, or set ATOLL_API_KEY and ATOLL_ORG_ID\n')
|
|
123
175
|
printUsage()
|
|
124
176
|
process.exit(1)
|
|
125
177
|
}
|
|
126
178
|
|
|
127
|
-
if (!args.key.startsWith('sk_atoll_')) {
|
|
179
|
+
if (configureMode && !args.key.startsWith('sk_atoll_')) {
|
|
128
180
|
console.error('Error: API key must start with sk_atoll_')
|
|
129
181
|
process.exit(1)
|
|
130
182
|
}
|
|
@@ -164,6 +216,52 @@ function ensurePrivateDirectory(path) {
|
|
|
164
216
|
chmodSync(path, 0o700)
|
|
165
217
|
}
|
|
166
218
|
|
|
219
|
+
function prepareSkillDirectory(path, source) {
|
|
220
|
+
const existing = lstatIfExists(path)
|
|
221
|
+
if (existing) {
|
|
222
|
+
if (existing.isSymbolicLink()) {
|
|
223
|
+
throw new Error(`Refusing symbolic link for skill directory: ${path}`)
|
|
224
|
+
}
|
|
225
|
+
if (!existing.isDirectory()) {
|
|
226
|
+
throw new Error(`Refusing non-directory skill path: ${path}`)
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
const parent = dirname(path)
|
|
231
|
+
mkdirSync(parent, { recursive: true })
|
|
232
|
+
const tempPath = join(parent, `.${basename(path)}.atoll-${process.pid}-${Date.now()}-${Math.random().toString(16).slice(2)}.tmp`)
|
|
233
|
+
const backupPath = `${tempPath}.backup`
|
|
234
|
+
let movedExisting = false
|
|
235
|
+
let installed = false
|
|
236
|
+
try {
|
|
237
|
+
cpSync(source, tempPath, { recursive: true })
|
|
238
|
+
|
|
239
|
+
const current = lstatIfExists(path)
|
|
240
|
+
if (current) {
|
|
241
|
+
if (current.isSymbolicLink()) {
|
|
242
|
+
throw new Error(`Refusing symbolic link for skill directory: ${path}`)
|
|
243
|
+
}
|
|
244
|
+
if (!current.isDirectory()) {
|
|
245
|
+
throw new Error(`Refusing non-directory skill path: ${path}`)
|
|
246
|
+
}
|
|
247
|
+
renameSync(path, backupPath)
|
|
248
|
+
movedExisting = true
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
renameSync(tempPath, path)
|
|
252
|
+
installed = true
|
|
253
|
+
if (movedExisting) rmSync(backupPath, { recursive: true, force: true })
|
|
254
|
+
} catch (error) {
|
|
255
|
+
if (!installed) {
|
|
256
|
+
if (lstatIfExists(tempPath)) rmSync(tempPath, { recursive: true, force: true })
|
|
257
|
+
if (movedExisting && !lstatIfExists(path) && lstatIfExists(backupPath)) {
|
|
258
|
+
renameSync(backupPath, path)
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
throw error
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
|
|
167
265
|
function readJson(path) {
|
|
168
266
|
assertSafeFile(path)
|
|
169
267
|
if (!existsSync(path)) return {}
|
|
@@ -198,10 +296,27 @@ function writePrivateFile(path, content) {
|
|
|
198
296
|
}
|
|
199
297
|
}
|
|
200
298
|
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
299
|
+
const codexDir = resolve(process.env.CODEX_HOME || join(homedir(), '.codex'))
|
|
300
|
+
const defaultInstallerLockTarget = join(homedir(), '.atoll', 'installer.lock-target')
|
|
301
|
+
const sharedInstallerLockTarget = join(
|
|
302
|
+
homedir(),
|
|
303
|
+
'.atoll-skill-installer.lock-target',
|
|
304
|
+
)
|
|
305
|
+
const codexSkillLockTarget = join(codexDir, '.atoll-skill-installer.lock-target')
|
|
306
|
+
|
|
307
|
+
function ensureLockDirectory(path) {
|
|
308
|
+
const entry = lstatIfExists(path)
|
|
309
|
+
if (entry) {
|
|
310
|
+
const stat = entry.isSymbolicLink() ? statSync(path) : entry
|
|
311
|
+
if (!stat.isDirectory()) throw new Error(`Refusing non-directory installer lock path: ${path}`)
|
|
312
|
+
} else {
|
|
313
|
+
mkdirSync(path, { recursive: true, mode: 0o700 })
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
function acquireInstallerLock(target = defaultInstallerLockTarget) {
|
|
318
|
+
if (target === defaultInstallerLockTarget) ensurePrivateDirectory(dirname(target))
|
|
319
|
+
else ensureLockDirectory(dirname(target))
|
|
205
320
|
try {
|
|
206
321
|
writeFileSync(target, '', { flag: 'wx', mode: 0o600 })
|
|
207
322
|
} catch (error) {
|
|
@@ -257,7 +372,23 @@ function acquireInstallerLock() {
|
|
|
257
372
|
}
|
|
258
373
|
}
|
|
259
374
|
|
|
260
|
-
const
|
|
375
|
+
const releaseSharedInstallerLock = acquireInstallerLock(sharedInstallerLockTarget)
|
|
376
|
+
let releaseCodexSkillInstallerLock = null
|
|
377
|
+
let releaseConfigInstallerLock = null
|
|
378
|
+
try {
|
|
379
|
+
releaseCodexSkillInstallerLock = acquireInstallerLock(codexSkillLockTarget)
|
|
380
|
+
if (configureMode) releaseConfigInstallerLock = acquireInstallerLock()
|
|
381
|
+
} catch (error) {
|
|
382
|
+
releaseCodexSkillInstallerLock?.()
|
|
383
|
+
releaseSharedInstallerLock()
|
|
384
|
+
throw error
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
function releaseInstallerLock() {
|
|
388
|
+
releaseConfigInstallerLock?.()
|
|
389
|
+
releaseCodexSkillInstallerLock?.()
|
|
390
|
+
releaseSharedInstallerLock()
|
|
391
|
+
}
|
|
261
392
|
|
|
262
393
|
function writeAtollProfile() {
|
|
263
394
|
if (!args.profile) return null
|
|
@@ -422,14 +553,12 @@ function writeGlobalInstructions(targetPath) {
|
|
|
422
553
|
}
|
|
423
554
|
|
|
424
555
|
// 1. Install the Codex skill to ~/.codex/skills/atoll/
|
|
425
|
-
const codexDir = join(homedir(), '.codex')
|
|
426
556
|
mkdirSync(codexDir, { recursive: true })
|
|
427
557
|
|
|
428
558
|
const skillDir = join(__dirname, '..', 'skill')
|
|
429
559
|
const skillDest = join(codexDir, 'skills', 'atoll')
|
|
430
560
|
const legacySkillDest = join(codexDir, 'skills', 'atoll-api')
|
|
431
|
-
|
|
432
|
-
cpSync(skillDir, skillDest, { recursive: true })
|
|
561
|
+
prepareSkillDirectory(skillDest, skillDir)
|
|
433
562
|
console.log(`Installed Atoll skill to ${skillDest}`)
|
|
434
563
|
if (existsSync(legacySkillDest)) {
|
|
435
564
|
rmSync(legacySkillDest, { recursive: true, force: true })
|
|
@@ -449,6 +578,13 @@ for (const file of ['api-endpoints.md', 'api-fields.md']) {
|
|
|
449
578
|
}
|
|
450
579
|
console.log(`Copied API references to ${refsDir}`)
|
|
451
580
|
|
|
581
|
+
if (!configureMode) {
|
|
582
|
+
console.log('Authentication/profile configuration left unchanged.')
|
|
583
|
+
console.log('\nDone! Codex has the Atoll skill installed.')
|
|
584
|
+
releaseInstallerLock()
|
|
585
|
+
process.exit(0)
|
|
586
|
+
}
|
|
587
|
+
|
|
452
588
|
const shell = process.env.SHELL || '/bin/bash'
|
|
453
589
|
const profilePath = shell.includes('zsh')
|
|
454
590
|
? join(homedir(), '.zshrc')
|
package/package.json
CHANGED
package/skill/SKILL.md
CHANGED
|
@@ -364,6 +364,7 @@ atoll dependency bulk-add --file ./dependencies.json --continue-on-error
|
|
|
364
364
|
|
|
365
365
|
Dependency reads include a target issue `identifier` and `projectSlug` when the target belongs to a project. Inaccessible targets remain `issue: null`; projectless targets have both fields set to `null`.
|
|
366
366
|
Dependencies persist a release point in the blocking project's ordered board columns. Add `releaseColumnId` when creating an edge, or omit it to default to that project's `done` column. Use the dependency API PATCH route to change the release point; reads include `releaseColumnId`, `releaseColumn`, and `satisfied`.
|
|
367
|
+
Archiving a blocker preserves the dependency edge and configured release column while satisfying the dependency. Restoring it re-evaluates the same release point and can block the dependent again. Configurable release-point and cancelled-blocker behavior are unchanged.
|
|
367
368
|
The blocking issue must belong to a project because its release point is a board
|
|
368
369
|
column there; a projectless issue may be the blocked target.
|
|
369
370
|
The dependency-release migration backfills existing dependencies to the
|
|
@@ -429,6 +430,9 @@ CLI JSON conventions:
|
|
|
429
430
|
- `atoll heartbeat --json` includes the same structured `cli` update metadata for agents, plus `attention_items`, `attention_summary`, and `recommended_action` when Atoll can propose one concrete strategy-backed next action. `atoll heartbeat --signals-only --json` preserves filtered `signals`, `attention_items`, `attention_summary`, and `recommended_action` for short polling. Handle direct attention items first, then call each handled item's `ack_endpoint`. Follow `recommended_action.usage_guidance`: prefer `suggested_write.operation` when it still matches the board, preserve KPI/initiative/initiative_target/why-now/expected-impact/first-step/success-criteria evidence, and avoid copying deferred busywork into issue or comment payloads. If a `start_work` recommendation uses `issue.update` with a body, update the issue status and preserve that body as an issue comment; `PATCH /issues/{issueId}` accepts `comment_body` for this same-request progress note.
|
|
430
431
|
- Authorized humans can configure an agent's included heartbeat sections and generated-signal focus in the Atoll **Heartbeats** UI. The saved policy is applied by the API before CLI or MCP request-level narrowing; it never changes project access, and existing heartbeat commands require no new arguments.
|
|
431
432
|
- GitHub `workflow_run` signals are accepted only when HMAC-signed and completed, then reread and matched exactly by repository, PR, workflow path, run attempt, and head SHA. Workflow verification is disabled by default and observe-only until an owner/admin enables it in **Settings > Integrations > GitHub**. `attention` mode can add one bounded `verification.completed` attention item through authorized REST or CLI heartbeat for exactly one eligible current agent assignee or, when there is no unambiguous assignee, an eligible configured delivery agent. The public MCP heartbeat excludes this private event type. Unresolved recipients and cancelled, obsolete, superseded, mismatched, or unreadable runs create no attention. Owners and admins can configure 1–10 workflow paths of at most 255 characters each; the bounded evidence list defaults to 25 items and accepts a maximum `limit` of 100. Signed pull-request writes and reconciliation bind PR links to the stable GitHub repository ID, so repository renames keep existing workflow evidence linked. Do not expect raw payloads, secrets, logs, or thread IDs in evidence; owner/admin reconciliation retries pending evidence after current GitHub and PR-link readback.
|
|
433
|
+
- Release-added required GitHub hook events mark existing reconciled and already-pending connections pending. The bounded 15-minute service sweep verifies immutable repository identity and upgrades hooks automatically; transient failures remain pending for retry, and owners/admins can reconcile manually.
|
|
434
|
+
- Issue delivery context selects an open PR first, then the latest updated link, then the highest PR number. `pending` review/workflow state with null provenance means no current-head observation and does not by itself set `partial`. Disabled GitHub verification stops new projections. Workflow conclusions map success/neutral to passed, cancelled/stale/skipped to cancelled, and other supported terminal conclusions to failed.
|
|
435
|
+
- Aggregate review state keeps each reviewer's latest exact-head opinion, ignores comments, and removes dismissed opinions. Change requests win. `approved` means at least one effective approval and no effective change request; it does not prove required-review counts or branch protection.
|
|
432
436
|
- `atoll plan validate/apply` consumes `schemaVersion: "atoll.plan.v1"` files with `milestones`, `issues`, `dependencies`, `initiativeLinks`, and `milestoneLinks`; local `key` values can be referenced by `milestoneKey`, `issueKey`, `dependsOn`, `blockedBy`, or `blocks`.
|
|
433
437
|
|
|
434
438
|
## KPI HTTP Sync Drafts
|
|
@@ -620,6 +624,64 @@ atoll() {
|
|
|
620
624
|
atoll "/api/orgs/$ATOLL_ORG_ID/issues?status=todo"
|
|
621
625
|
```
|
|
622
626
|
|
|
627
|
+
## Execution and attention CLI workflow
|
|
628
|
+
|
|
629
|
+
Use `atoll execution list|get|create|transition`, `execution evidence list|add`,
|
|
630
|
+
and `atoll attention create|list|get|cancel` with the selected profile and `--json`.
|
|
631
|
+
Creation requires `--issue`, `--agent <member-id|self>`, and an explicit
|
|
632
|
+
`--idempotency-key`; it returns `assigned` at state version 1. Start with a
|
|
633
|
+
separate `execution transition <id> --to running --expected-state-version 1
|
|
634
|
+
--idempotency-key <start-key>`. Atoll records state; it does not start a harness.
|
|
635
|
+
|
|
636
|
+
Generic transition targets are `running|waiting|succeeded|failed|cancelled`.
|
|
637
|
+
For `succeeded`, supply `--outcome-summary` unless the execution already has
|
|
638
|
+
linked evidence. The server validates this requirement.
|
|
639
|
+
Use `attention create` to move `running|waiting` to `needs_human`; generic
|
|
640
|
+
transitions cannot enter or leave `needs_human`. Attention kinds are exactly
|
|
641
|
+
`approval|clarification|access|decision|destructive_action|other`. Supply the
|
|
642
|
+
execution's expected state version, title, request summary, why needed, resume
|
|
643
|
+
condition, exactly one member/team/project-admin target, and an idempotency key.
|
|
644
|
+
Never put credentials, access tokens, private paths, prompts, logs, or other
|
|
645
|
+
secrets in attention text. Server permissions and concealed 404 responses remain
|
|
646
|
+
authoritative; do not try another identity to bypass them.
|
|
647
|
+
|
|
648
|
+
Read `attention get <id>` for the human's resolution and current attention and
|
|
649
|
+
execution versions. Human resolution returns the execution to `waiting`; it
|
|
650
|
+
does not resume a model or harness. Requester `attention cancel` also returns it
|
|
651
|
+
to `waiting` and requires `--expected-attention-version`,
|
|
652
|
+
`--expected-state-version`, and `--idempotency-key`. Human resolve, administrator
|
|
653
|
+
retarget/cancel, and recovery discovery are REST/UI operations, not CLI commands.
|
|
654
|
+
Harness acceptance and the later explicitly fenced `waiting -> running` resume
|
|
655
|
+
remain the separate AH-2122 integration.
|
|
656
|
+
|
|
657
|
+
Every write uses the caller's explicit idempotency key; transitions and attention
|
|
658
|
+
writes use the caller's expected versions. Never silently fetch a new version
|
|
659
|
+
and write against it. After a POST timeout, network failure, or HTTP 5xx, the
|
|
660
|
+
outcome is uncertain and the CLI does not retry. Read `execution get <id>`,
|
|
661
|
+
`attention get <id>` (or `attention list --execution <id>` when create returned no
|
|
662
|
+
attention ID), or `execution evidence list <id>`. Stop if the result is visible.
|
|
663
|
+
For execution create without an ID, replay the identical create command with
|
|
664
|
+
the same key, then read the returned ID. If replay is needed for another write,
|
|
665
|
+
keep the exact body and key. Stop for operator reconciliation if changed state
|
|
666
|
+
or versions make the outcome ambiguous; never use a new key to force progress.
|
|
667
|
+
|
|
668
|
+
Evidence add links only an existing authorized issue object using
|
|
669
|
+
`--type <comment|activity_event|issue_pr_link|attachment> --target-id <uuid>
|
|
670
|
+
--idempotency-key <key>`. It does not upload files, URLs, text, or raw logs.
|
|
671
|
+
|
|
672
|
+
## Human attention
|
|
673
|
+
|
|
674
|
+
When an execution needs a human, use the attention contract. `POST
|
|
675
|
+
/api/orgs/{id}/attention` records a bounded request and atomically moves the
|
|
676
|
+
execution to `needs_human`; generic execution transitions cannot perform this
|
|
677
|
+
edge. Poll `GET /api/orgs/{id}/attention` or use the exact item endpoint.
|
|
678
|
+
Resolve, cancel, or retarget with both expected versions and an idempotency
|
|
679
|
+
key. Reuse the same key only with the same input. Use `mode=recovery` only as
|
|
680
|
+
an authorized human administrator when the original target is no longer
|
|
681
|
+
eligible. Keep request text concise and never include secrets, credentials,
|
|
682
|
+
logs, prompts, or local paths. The public projection provides current and
|
|
683
|
+
snapshot actor/target fields, execution state, issue, and project context.
|
|
684
|
+
|
|
623
685
|
## The Heartbeat Loop
|
|
624
686
|
|
|
625
687
|
The primary pattern for autonomous agents. Prefer `atoll heartbeat --json` when the CLI is available; it wraps `GET /api/orgs/{id}/heartbeat` and returns the same computed briefing:
|
|
@@ -791,6 +853,20 @@ Owners/admins can read billing state with `GET /api/orgs/{id}/billing` and start
|
|
|
791
853
|
|
|
792
854
|
Creation endpoints can return `402` with `code: "PLAN_LIMIT_REACHED"` when an org reaches limits for humans, agents/integrations, active projects, or active issues.
|
|
793
855
|
|
|
856
|
+
## Agent execution REST API
|
|
857
|
+
|
|
858
|
+
Use the canonical org-scoped execution routes for lifecycle management:
|
|
859
|
+
`GET|POST /api/orgs/{id}/executions`, `GET
|
|
860
|
+
/api/orgs/{id}/executions/{executionId}`, `POST
|
|
861
|
+
/api/orgs/{id}/executions/{executionId}/transitions`, and `GET|POST` on the
|
|
862
|
+
matching `/evidence` route. Create starts in `assigned`; transition writes
|
|
863
|
+
require `expected_state_version` and an idempotency key. Generic transitions
|
|
864
|
+
cannot enter or leave `needs_human`; use the attention contract. Reads follow
|
|
865
|
+
the issue's current project access. Non-guest organization members may also read
|
|
866
|
+
projectless executions; setup-scoped agents and guest members cannot. Creation-
|
|
867
|
+
project metadata does not grant access, and unreadable records are concealed.
|
|
868
|
+
Responses are bounded management projections, not logs or harness controls.
|
|
869
|
+
|
|
794
870
|
## API Reference
|
|
795
871
|
|
|
796
872
|
Full endpoint tables and field schemas:
|
|
@@ -827,6 +903,12 @@ default 50) and `offset`, and returns `hasMore`; removing the final link
|
|
|
827
903
|
requires owner or admin access. Linked issues and projects cannot be deleted
|
|
828
904
|
until the Artifact is unlinked or reassigned.
|
|
829
905
|
|
|
906
|
+
Artifact list and detail responses include `can_edit`, which is true when the
|
|
907
|
+
current member can create a revision, and `can_unlink`, which is true when the
|
|
908
|
+
current member can remove a visible link. Members with write access can remove
|
|
909
|
+
a link when another link remains; removing a final link requires owner or admin
|
|
910
|
+
access.
|
|
911
|
+
|
|
830
912
|
Private CLI issue reads request the opt-in metadata-only manifest. Inspect
|
|
831
913
|
`.artifacts`, then use `atoll artifact get <id> --issue <issue>` only when the
|
|
832
914
|
full current body is required. Create and update accept `--body-file -` for
|
|
@@ -861,6 +943,17 @@ otherwise the API returns `422` with `code: "github_identity_unavailable"`.
|
|
|
861
943
|
Reads return bounded display metadata, provenance, observation timestamps, and
|
|
862
944
|
resolvability. Reads require project visibility; writes require project
|
|
863
945
|
`edit`/`admin`, with eligible non-guests allowed for projectless issues.
|
|
946
|
+
For compact implementation evidence, the private REST endpoint
|
|
947
|
+
`GET /api/orgs/{id}/issues/{issueId}/external-operational-signals` returns the
|
|
948
|
+
selected PR, stable repository identity, exact current head SHA, current-head
|
|
949
|
+
review and configured workflow states, bounded provenance, freshness, and a
|
|
950
|
+
safe strongest blocker. Older-head evidence is historical. Configured
|
|
951
|
+
workflows are not GitHub branch-protection required checks. This namespace is
|
|
952
|
+
separate from heartbeat `signals[]` and never changes tasks or dispatches
|
|
953
|
+
agents.
|
|
954
|
+
The selected PR-link state is authoritative. If a same-head PR observation
|
|
955
|
+
disagrees, Atoll clears its observation/provider provenance, falls back to the
|
|
956
|
+
link URL, excludes it from freshness, and sets `partial`.
|
|
864
957
|
Organization-wide templates are readable by non-guests and manageable only by
|
|
865
958
|
organization owners/admins; guest/project-scoped agents never receive them.
|
|
866
959
|
Avatar mutations require both caller and target to belong to the organization
|
|
@@ -220,6 +220,7 @@ bodies, projects only declared public issue fields, preserves nullable
|
|
|
220
220
|
Add with `{ "blockedByIssueId": "uuid" }` or `{ "blockingIssueId": "uuid" }`; snake_case aliases `{ "blocked_by_issue_id": "uuid" }` and `{ "blocking_issue_id": "uuid" }` are also accepted. The blocking issue must belong to a project; a projectless issue may be the blocked target. Optionally include `releaseColumnId` from the blocking project's board columns. Omit it to use the blocking project's `done` column. PATCH the dependency with `{ "releaseColumnId": "uuid" }`. Circular dependencies rejected (400). Duplicates return 409.
|
|
221
221
|
|
|
222
222
|
Dependency reads include each authorized target issue's canonical `identifier` and `projectSlug` when it belongs to a project. Projectless targets have both fields `null`; inaccessible targets remain `issue: null`. Release fields include `releaseColumnId` and the compatibility alias `release_column_id`; POST and PATCH accept either camelCase or snake_case release-column input. Release metadata is present when the blocking issue is authorized; a `blocking` target projection may still be `issue: null` independently.
|
|
223
|
+
Archiving a blocker preserves the dependency edge and configured release column while satisfying the dependency. Restoring it re-evaluates the same release point and can block the dependent again. Configurable release-point and cancelled-blocker behavior are unchanged.
|
|
223
224
|
The dependency-release migration backfills existing dependencies to the
|
|
224
225
|
blocking project's `done` column. During a rolling deployment, compatibility
|
|
225
226
|
reads may omit release fields from older rows; treat missing release metadata as
|
|
@@ -296,10 +297,10 @@ Artifacts.
|
|
|
296
297
|
|
|
297
298
|
| Method | Endpoint | Description |
|
|
298
299
|
| --- | --- | --- |
|
|
299
|
-
| `GET` | `/api/orgs/{id}/artifacts` | List readable artifact metadata and visible links; revision content is omitted; supports `limit` (1-100, default 50) and `offset` (0-10000), and returns `hasMore` |
|
|
300
|
+
| `GET` | `/api/orgs/{id}/artifacts` | List readable artifact metadata and visible links; revision content is omitted; includes `can_edit` and `can_unlink` capabilities; supports `limit` (1-100, default 50) and `offset` (0-10000), and returns `hasMore` |
|
|
300
301
|
| `POST` | `/api/orgs/{id}/artifacts` | Create artifact and immutable revision 1 atomically |
|
|
301
|
-
| `GET` | `/api/orgs/{id}/artifacts/{artifactId}` | Read artifact metadata and visible links |
|
|
302
|
-
| `GET` | `/api/orgs/{id}/artifacts/{artifactId}/revisions` | List immutable revision summaries without content; supports `limit` (1-100, default 50) and `offset
|
|
302
|
+
| `GET` | `/api/orgs/{id}/artifacts/{artifactId}` | Read artifact metadata and visible links, including `can_edit` and `can_unlink` capabilities |
|
|
303
|
+
| `GET` | `/api/orgs/{id}/artifacts/{artifactId}/revisions` | List immutable revision summaries without content; supports `limit` (1-100, default 50) and `offset` (0-10000), and returns `hasMore` |
|
|
303
304
|
| `POST` | `/api/orgs/{id}/artifacts/{artifactId}/revisions` | Create a content revision or title-aware full snapshot with an expected current revision |
|
|
304
305
|
| `GET` | `/api/orgs/{id}/artifacts/{artifactId}/revisions/{revisionId}` | Read one sanitized revision including content |
|
|
305
306
|
| `POST` | `/api/orgs/{id}/artifacts/{artifactId}/links` | Link to an authorized issue or project |
|
|
@@ -425,6 +426,20 @@ references return `409`, and resolver failures return `500`.
|
|
|
425
426
|
|
|
426
427
|
Returns findings only (not the full graph). Use it for a high-level review — orphaned initiatives/KPIs (no goal), goals with no KPI or no initiative, dangling initiative execution links, KPIs missing targets/stale/off-pace, initiatives missing impact/execution or stalled, blocked/overdue work — then remediate with the goal/KPI/initiative write endpoints above. Owners/admins receive organization-wide execution evidence. Other non-guests receive project-bound issues, milestones, target links, and target findings only for readable projects. A restricted member with no readable projects receives no issue or target execution evidence. Forbidden for guests. CLI: `atoll strategy audit [--severity critical|warning|info] [--json]`.
|
|
427
428
|
|
|
429
|
+
## Human attention
|
|
430
|
+
|
|
431
|
+
| Method | Endpoint | Description |
|
|
432
|
+
| --- | --- | --- |
|
|
433
|
+
| `GET` | `/api/orgs/{id}/attention` | List relevant open or closed attention items; supports status, execution, kind, recovery mode, target filters, bounded pagination, and envelope/CLI shape |
|
|
434
|
+
| `POST` | `/api/orgs/{id}/attention` | Request human attention and atomically pause the execution in `needs_human` |
|
|
435
|
+
| `GET` | `/api/orgs/{id}/attention/{attentionId}` | Read one safe attention detail projection |
|
|
436
|
+
| `POST` | `/api/orgs/{id}/attention/{attentionId}/resolve` | Resolve an open item for its eligible human target and leave the execution in `waiting`; a trusted harness performs any later resume |
|
|
437
|
+
| `POST` | `/api/orgs/{id}/attention/{attentionId}/cancel` | Cancel an item as its requesting agent and leave the execution in `waiting`; a trusted harness performs any later resume |
|
|
438
|
+
| `POST` | `/api/orgs/{id}/attention/{attentionId}/admin-cancel` | Cancel an item as an authorized human administrator and leave the execution in `waiting`; a trusted harness performs any later resume |
|
|
439
|
+
| `POST` | `/api/orgs/{id}/attention/{attentionId}/retarget` | Retarget an open item as an authorized human administrator |
|
|
440
|
+
|
|
441
|
+
The create body is strict and requires `execution_id`, `expected_state_version`, `kind`, `title`, `request_summary`, `why_needed`, `resume_condition`, one exact target shape, and `idempotency_key`. Close and retarget bodies require both expected versions. Mutations are idempotent and return `409` for stale versions, invalid lifecycle edges, conflicting keys, or ineligible targets. `mode=recovery` is restricted to authorized human administrators. Text is bounded and secret-safe; public projections omit provenance, hashes, prompts, logs, credentials, and paths.
|
|
442
|
+
|
|
428
443
|
## Heartbeat
|
|
429
444
|
|
|
430
445
|
| Method | Endpoint | Description |
|
|
@@ -455,6 +470,25 @@ atoll heartbeat --severity critical
|
|
|
455
470
|
`atoll heartbeat --signals-only --json` returns filtered `signals`, direct `attention_items`, `attention_summary`, and `recommended_action` for polling agents.
|
|
456
471
|
KPI stale/off-pace signal metadata includes `linked_initiatives` and `recent_attributed_snapshots`; `--explain-kpi` returns that movement context under `kpi_explanation`.
|
|
457
472
|
|
|
473
|
+
## Agent executions
|
|
474
|
+
|
|
475
|
+
| Method | Endpoint | Description |
|
|
476
|
+
| --- | --- | --- |
|
|
477
|
+
| GET | `/api/orgs/{id}/executions` | List executions in the caller's current issue-project scope; non-guest members may also read projectless executions, except setup agents and guests; filters: `issue_id`, `agent_member_id`, `state`, `active`, `harness_kind`, `updated_after`, `limit`, `offset` (maximum 10,000), `shape` |
|
|
478
|
+
| POST | `/api/orgs/{id}/executions` | Create an execution. Strict body; required `idempotency_key`; starts in `assigned` |
|
|
479
|
+
| GET | `/api/orgs/{id}/executions/{executionId}` | Read safe detail, transitions, and evidence projections |
|
|
480
|
+
| POST | `/api/orgs/{id}/executions/{executionId}/transitions` | Version-fenced transition through the shipped lifecycle RPC |
|
|
481
|
+
| GET/POST | `/api/orgs/{id}/executions/{executionId}/evidence` | List or link existing authorized issue evidence |
|
|
482
|
+
|
|
483
|
+
Use `expected_state_version` for follow-up transitions. Generic transitions cannot enter
|
|
484
|
+
or leave `needs_human`; those edges return `ATTENTION_CONTRACT_REQUIRED` and
|
|
485
|
+
belong to the attention contract. Reads use the issue's current project access;
|
|
486
|
+
non-guest members may also read projectless executions, except setup agents and
|
|
487
|
+
guests. Creation-project metadata does not grant access. Unreadable records are
|
|
488
|
+
concealed as `404`; public projections omit hashes, provenance, logs,
|
|
489
|
+
prompts, credentials, and paths. This API records state and does not start or
|
|
490
|
+
resume an underlying harness. There is no issue-specific execution route.
|
|
491
|
+
|
|
458
492
|
## Activity
|
|
459
493
|
|
|
460
494
|
| Method | Endpoint | Description |
|
|
@@ -600,6 +634,10 @@ requests also sweep a small due batch. Uploads over 2MB return `413`.
|
|
|
600
634
|
|
|
601
635
|
Attach PRs manually with a canonical GitHub pull request URL such as `https://github.com/owner/repo/pull/123`; malformed or non-PR URLs return `400`. On attach, Atoll refreshes GitHub metadata when available so title/status/head SHA reflect the PR instead of only the submitted URL. PR links can also be created or refreshed automatically via the GitHub webhook integration.
|
|
602
636
|
|
|
637
|
+
GET returns `id`, `pr_number`, `github_repo`, nullable
|
|
638
|
+
`github_repository_id`, nullable `external_reference_id`, `pr_url`, `pr_title`,
|
|
639
|
+
`pr_status`, nullable `head_sha`, and `updated_at` for each link.
|
|
640
|
+
|
|
603
641
|
For project-bound issues, listing requires project access and attaching requires
|
|
604
642
|
`edit` or `admin` access. Eligible non-guests may list and attach links for
|
|
605
643
|
projectless issues. Authorization is bound to the issue's current parent before
|
|
@@ -613,12 +651,35 @@ child reads or writes and occurs before URL parsing or GitHub metadata lookup.
|
|
|
613
651
|
| POST | `/api/orgs/{id}/issues/{issueId}/external-references` | Resolve and link a GitHub PR |
|
|
614
652
|
| GET | `/api/orgs/{id}/issues/{issueId}/external-references/{referenceId}` | Inspect a linked reference |
|
|
615
653
|
| DELETE | `/api/orgs/{id}/issues/{issueId}/external-references/{referenceId}` | Unlink a reference |
|
|
654
|
+
| GET | `/api/orgs/{id}/issues/{issueId}/external-operational-signals` | Read current exact-head GitHub delivery context |
|
|
616
655
|
| GET | `/api/orgs/{id}/projects/{projectId}/external-references` | List project external references |
|
|
617
656
|
| POST | `/api/orgs/{id}/projects/{projectId}/external-references` | Resolve and link a GitHub PR |
|
|
618
657
|
| GET | `/api/orgs/{id}/projects/{projectId}/external-references/{referenceId}` | Inspect a linked reference |
|
|
619
658
|
| DELETE | `/api/orgs/{id}/projects/{projectId}/external-references/{referenceId}` | Unlink a reference |
|
|
620
659
|
|
|
621
|
-
External Reference POST requests accept `{ "url": "https://github.com/owner/repo/pull/123" }`. They require an authorized GitHub connection and store a reference only when the live response proves numeric immutable repository and pull-request IDs. Missing proof returns `422` with `code: "github_identity_unavailable"`. URLs and caller owner/repo fields are not identity or authorization inputs.
|
|
660
|
+
External Reference POST requests accept `{ "url": "https://github.com/owner/repo/pull/123" }`. They require an authorized GitHub connection and store a reference only when the live response proves numeric immutable repository and pull-request IDs. Missing proof returns `422` with `code: "github_identity_unavailable"`. URLs and caller owner/repo fields are not identity or authorization inputs. Manual PR-link operations remain available without an External Reference; verified delivery projection creates and binds the immutable PR reference. CLI/MCP tools are deferred to a later slice.
|
|
661
|
+
|
|
662
|
+
The external-operational-signals GET returns `{ deliveryContext }` for the
|
|
663
|
+
selected current PR or `null` when there is no PR link. Selection prefers an
|
|
664
|
+
open link, then the latest `updated_at`, then the highest PR number. It contains stable
|
|
665
|
+
repository identity, exact head SHA, current PR/review/configured-workflow
|
|
666
|
+
state, bounded source and provider-event provenance, freshness, a safe strongest
|
|
667
|
+
blocker, and `partial`. Older-head signals are historical. Configured workflows
|
|
668
|
+
are not GitHub branch-protection required checks and report `required: false`.
|
|
669
|
+
Missing current-head review or configured-workflow evidence appears as
|
|
670
|
+
`pending` with null provenance and does not by itself set `partial`. Disabled
|
|
671
|
+
verification stops new projections. Workflow conclusions map `success` or
|
|
672
|
+
`neutral` to `passed`; `cancelled`, `stale`, or `skipped` to `cancelled`; and
|
|
673
|
+
other supported terminal conclusions to `failed`.
|
|
674
|
+
The selected PR-link state is authoritative. If a same-head PR observation
|
|
675
|
+
disagrees, Atoll clears its observation/provider provenance, uses the link URL
|
|
676
|
+
as `source_url`, excludes it from freshness, and sets `partial`.
|
|
677
|
+
Review aggregation keeps each reviewer's latest exact-head opinion, ignores
|
|
678
|
+
comments, and removes dismissed opinions. Change requests win; `approved`
|
|
679
|
+
means at least one effective approval and no effective change request. It does
|
|
680
|
+
not prove required-review counts or branch protection.
|
|
681
|
+
This read-only namespace is separate from heartbeat `signals[]` and does not
|
|
682
|
+
dispatch agents or change tasks.
|
|
622
683
|
|
|
623
684
|
## Project Status Updates
|
|
624
685
|
|
|
@@ -798,6 +859,11 @@ The default new-agent local path (without `setupAgentMemberId`) atomically creat
|
|
|
798
859
|
| POST | `/api/integrations/github/connect` | Connect a repo |
|
|
799
860
|
| POST | `/api/integrations/github/disconnect` | Disconnect a repo |
|
|
800
861
|
|
|
862
|
+
Release-added required hook events mark existing reconciled and already-pending connections pending. A bounded
|
|
863
|
+
15-minute service sweep verifies immutable repository identity and upgrades the
|
|
864
|
+
hooks automatically. Transient failures remain pending for retry; owners and
|
|
865
|
+
admins can also use the reconciliation endpoint.
|
|
866
|
+
|
|
801
867
|
## Platform Feedback
|
|
802
868
|
|
|
803
869
|
### Feedback error contract
|
|
@@ -782,6 +782,30 @@ The opt-in issue manifest contains only `id`, `type`, `title`,
|
|
|
782
782
|
Implementation Plan links are limited to one slot per issue, and each such
|
|
783
783
|
Artifact can be authoritative for only one issue.
|
|
784
784
|
|
|
785
|
+
Artifact list and detail responses also include `can_edit` and `can_unlink`.
|
|
786
|
+
`can_edit` is true when the current member can create a revision. `can_unlink`
|
|
787
|
+
is true when the current member can remove a visible link; removing a final link
|
|
788
|
+
requires owner or admin access, while a member with write access can remove a
|
|
789
|
+
link when another link remains.
|
|
790
|
+
|
|
791
|
+
## Agent execution fields
|
|
792
|
+
|
|
793
|
+
Execution projections contain `id`, `issue_id`, `current_project_id`,
|
|
794
|
+
`project_id_at_creation` (provenance only), normalized `state`, `state_version`,
|
|
795
|
+
bounded lifecycle summaries, safe harness/external-run metadata, timestamps,
|
|
796
|
+
and actor objects `{ id, display_name, type, deleted }`. `harness_kind` and
|
|
797
|
+
`external_run_id` reject credentials, tokens, and local filesystem paths;
|
|
798
|
+
legacy unsafe values are redacted as `null` in projections. Deleted agent or actor
|
|
799
|
+
rows use immutable AH-2095 snapshots. Detail adds ordered `transitions` and
|
|
800
|
+
existing `evidence` references `{ id, issue_id, link_type, target_id,
|
|
801
|
+
created_by, created_at }`.
|
|
802
|
+
|
|
803
|
+
Create requires `issue_id`, `agent_member_id`, and `idempotency_key`; it always
|
|
804
|
+
returns state `assigned`. Transition requires `expected_state_version`,
|
|
805
|
+
`to_state`, and `idempotency_key`. HTTP bodies are strict and omit actor
|
|
806
|
+
provenance; the server derives safe OAuth provenance. The generic transition
|
|
807
|
+
enum excludes `needs_human`.
|
|
808
|
+
|
|
785
809
|
## Analytics Response
|
|
786
810
|
|
|
787
811
|
```json
|
|
@@ -795,6 +819,28 @@ Artifact can be authoritative for only one issue.
|
|
|
795
819
|
|
|
796
820
|
---
|
|
797
821
|
|
|
822
|
+
## Human attention fields
|
|
823
|
+
|
|
824
|
+
Attention list/detail projections contain `id`, `status` (`open`, `resolved`, or
|
|
825
|
+
`cancelled`), `kind` (`approval`, `clarification`, `access`, `decision`,
|
|
826
|
+
`destructive_action`, or `other`), bounded `title`, `request_summary`,
|
|
827
|
+
`why_needed`, `resume_condition`, `requested_at`, `closed_at`,
|
|
828
|
+
`resolution_outcome`, `resolution_summary`, `attention_version`, and the
|
|
829
|
+
execution, issue, and project projections. `target` contains the exact target
|
|
830
|
+
type plus a live member/team projection when it still exists and immutable
|
|
831
|
+
snapshot fields. `requester` and `closed_by` contain `{ id, display_name,
|
|
832
|
+
type, deleted }` snapshots. Detail adds
|
|
833
|
+
`execution_state_version_at_request` and `execution_state_version_at_close`.
|
|
834
|
+
|
|
835
|
+
Create targets are one of `{ target_type: "member", target_member_id }`,
|
|
836
|
+
`{ target_type: "team", target_team_id }`, or
|
|
837
|
+
`{ target_type: "project_admins" }`. Mutation requests use
|
|
838
|
+
`expected_attention_version`, `expected_state_version`, and
|
|
839
|
+
`idempotency_key`; resolve also accepts `resolution_outcome` and an optional
|
|
840
|
+
bounded `resolution_summary`. Free-form text rejects secret-like values.
|
|
841
|
+
Internal requester/actor provenance, hashes, response snapshots, and mutation
|
|
842
|
+
metadata are never returned by the public API.
|
|
843
|
+
|
|
798
844
|
## Enums
|
|
799
845
|
|
|
800
846
|
| Domain | Field | Values |
|
|
@@ -876,7 +922,9 @@ be the blocked target when the caller has permission to use it.
|
|
|
876
922
|
| `releaseColumnId` | UUID | Persistent release column in the blocking issue's project; present when the blocking issue is authorized |
|
|
877
923
|
| `release_column_id` | UUID | Compatibility alias for `releaseColumnId`; present with the canonical field |
|
|
878
924
|
| `releaseColumn` | object or null | `{ id, key, label, position, projectId }` release column projection |
|
|
879
|
-
| `satisfied` | boolean or null | Whether the blocker reached the release column position
|
|
925
|
+
| `satisfied` | boolean or null | Whether the blocker is archived or cancelled, or reached the release column position |
|
|
926
|
+
|
|
927
|
+
Archiving a blocker preserves the dependency edge and configured release column while satisfying the dependency. Restoring it re-evaluates that same release point and can block the dependent again. Configurable release-point and cancelled-blocker behavior are unchanged.
|
|
880
928
|
|
|
881
929
|
The dependency-release migration backfills existing dependencies to the
|
|
882
930
|
blocking project's `done` column. During a rolling deployment, compatibility
|
|
@@ -898,6 +946,35 @@ provider response or return `422` with
|
|
|
898
946
|
metadata-only Activity actions `external_reference.linked`,
|
|
899
947
|
`external_reference.updated`, or `external_reference.unlinked`.
|
|
900
948
|
|
|
949
|
+
### External operational delivery context
|
|
950
|
+
|
|
951
|
+
`GET /api/orgs/{id}/issues/{issueId}/external-operational-signals` returns
|
|
952
|
+
`{ deliveryContext }`. The value is `null` without a linked PR. With several
|
|
953
|
+
links, selection prefers an open PR, then the latest `updated_at`, then the
|
|
954
|
+
highest PR number. Otherwise it
|
|
955
|
+
contains `repository`, `pull_request`, nullable `review`, `workflows`,
|
|
956
|
+
`freshness`, nullable `strongest_blocker`, and `partial`. PR, review, and
|
|
957
|
+
workflow evidence includes nullable `observed_at`, `provider_updated_at`,
|
|
958
|
+
`provider_event_id`, and `source_url`. The PR includes the exact `head_sha`.
|
|
959
|
+
Review state is `pending`, `approved`, or `changes_requested`; workflow state is
|
|
960
|
+
`pending`, `passed`, `failed`, or `cancelled`. Older-head evidence is not
|
|
961
|
+
current. Workflow `required` is always `false` because configured workflow
|
|
962
|
+
paths do not prove GitHub branch protection. Raw payloads, review bodies,
|
|
963
|
+
actors, logs, and credentials are excluded. A `pending` review or workflow with
|
|
964
|
+
null provenance has no current-head observation; this absence does not by
|
|
965
|
+
itself set `partial`. Disabled verification stops new projections. Workflow
|
|
966
|
+
conclusions map `success`/`neutral` to `passed`,
|
|
967
|
+
`cancelled`/`stale`/`skipped` to `cancelled`, and other supported terminal
|
|
968
|
+
conclusions to `failed`.
|
|
969
|
+
The selected PR-link state is authoritative. If a same-head PR observation
|
|
970
|
+
disagrees, its `observed_at`, `provider_updated_at`, and `provider_event_id` are
|
|
971
|
+
null, `source_url` uses the link URL, the observation is excluded from
|
|
972
|
+
`freshness`, and `partial` is true.
|
|
973
|
+
Review aggregation keeps each reviewer's latest exact-head opinion, ignores
|
|
974
|
+
comments, and removes dismissed opinions. Change requests win; `approved`
|
|
975
|
+
means at least one effective approval and no effective change request. It does
|
|
976
|
+
not prove required-review counts or branch protection.
|
|
977
|
+
|
|
901
978
|
## Task Activity
|
|
902
979
|
|
|
903
980
|
`GET /api/orgs/{id}/activity` returns `{ data, currentMemberId, limit, offset,
|