@atollhq/skill-codex 0.4.9 → 0.4.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -14,15 +14,25 @@ ATOLL_API_KEY=sk_atoll_... ATOLL_ORG_ID=your-org-id npx @atollhq/skill-codex@lat
14
14
 
15
15
  Optional defaults: `--project`, `--team`, and `--base-url` are stored with the selected mode. Use `--no-project`, `--no-team`, or `--no-base-url` to clear previously saved defaults. Pass `--profile` to store credentials and defaults only in that named Atoll CLI profile. The installer does not write global `ATOLL_*` exports to `~/.zshrc` or `~/.bashrc` in profile mode. Use `atoll --profile agent-a ...` for profile-scoped commands, or omit `--profile` to use env-var mode.
16
16
 
17
+ For multi-org setups, keep global Codex instructions neutral and bind profiles per repo:
18
+
19
+ ```bash
20
+ npx @atollhq/skill-codex@latest --profile agent-a --key sk_atoll_... --org your-org-id \
21
+ --write-project-instructions --project-dir /path/to/repo --instruction-files agents,claude
22
+ ```
23
+
24
+ `--write-project-instructions` writes a small managed block to repo-local instruction files. It requires `--profile`, defaults to the current directory, writes `AGENTS.md` by default, and can also write `CLAUDE.md` with `--instruction-files agents,claude`. If the target file already has unmanaged Atoll profile guidance, pass `--force-project-instructions` after reviewing the replacement.
25
+
17
26
  Get an agent API key from **Agents** in the Atoll app. Integration keys are still managed from **Settings > Members**.
18
27
 
19
- This does five things:
28
+ This does six things:
20
29
 
21
30
  1. Installs the `atoll-api` skill to `~/.codex/skills/atoll-api/`
22
- 2. Appends (or updates) an `# Atoll Integration` section in `~/.codex/AGENTS.md`
31
+ 2. Appends (or updates) a neutral `# Atoll Integration` section in `~/.codex/AGENTS.md`
23
32
  3. Copies API reference files to `~/.codex/atoll-references/`
24
33
  4. Creates or updates the named Atoll CLI profile when `--profile` is provided
25
34
  5. Appends Atoll env var exports to your shell profile (`~/.zshrc` or `~/.bashrc`) only when no profile is provided
35
+ 6. Optionally writes repo-local profile guidance when `--write-project-instructions` is provided
26
36
 
27
37
  For profile mode, Codex has the Atoll skill immediately 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.
28
38
 
@@ -48,9 +58,9 @@ For terminal-first work, see [`@atollhq/cli`](https://www.npmjs.com/package/@ato
48
58
  npm install -g @atollhq/cli
49
59
  atoll auth login --profile agent-a --key sk_atoll_... --org-id org-uuid --project project-id --team team-id
50
60
  atoll auth login --profile agent-a --key sk_atoll_... --org-id org-uuid --project project-id --no-team --no-base-url
51
- atoll heartbeat
52
- atoll issue list --json
53
- atoll agent-context
61
+ atoll --profile agent-a heartbeat
62
+ atoll --profile agent-a issue list --json
63
+ atoll --profile agent-a agent-context
54
64
  ```
55
65
 
56
66
  For multiple agents or orgs, use CLI auth profiles:
package/bin/install.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- import { cpSync, existsSync, mkdirSync, readFileSync, writeFileSync, copyFileSync } from 'node:fs'
4
- import { join, dirname } from 'node:path'
3
+ import { cpSync, existsSync, mkdirSync, readFileSync, writeFileSync, copyFileSync, statSync, renameSync, rmSync } from 'node:fs'
4
+ import { join, dirname, resolve, basename } from 'node:path'
5
5
  import { homedir } from 'node:os'
6
6
  import { fileURLToPath } from 'node:url'
7
7
 
@@ -20,6 +20,10 @@ function parseArgs(argv) {
20
20
  else if (argv[i] === '--no-team') args.clearTeam = true
21
21
  else if (argv[i] === '--base-url' && argv[i + 1]) args.baseUrl = argv[++i]
22
22
  else if (argv[i] === '--no-base-url') args.clearBaseUrl = true
23
+ else if (argv[i] === '--write-project-instructions') args.writeProjectInstructions = true
24
+ else if (argv[i] === '--project-dir' && argv[i + 1]) args.projectDir = argv[++i]
25
+ else if (argv[i] === '--instruction-files' && argv[i + 1]) args.instructionFiles = argv[++i]
26
+ else if (argv[i] === '--force-project-instructions') args.forceProjectInstructions = true
23
27
  else if (argv[i] === '--help' || argv[i] === '-h') args.help = true
24
28
  }
25
29
  return args
@@ -40,12 +44,21 @@ Options:
40
44
  --no-team Clear any saved default team.
41
45
  --base-url Atoll base URL. Defaults to ATOLL_BASE_URL.
42
46
  --no-base-url Clear any saved custom base URL.
47
+ --write-project-instructions
48
+ Write a small repo-local Atoll profile block. Requires --profile.
49
+ --project-dir
50
+ Directory for repo-local instructions. Defaults to the current directory.
51
+ --instruction-files
52
+ Comma-separated files to update: agents, claude, or agents,claude. Defaults to agents.
53
+ --force-project-instructions
54
+ Replace existing unmanaged Atoll profile guidance in repo-local instruction files.
43
55
  --help Show this help message
44
56
 
45
57
  Installs the Atoll integration for Codex CLI:
46
58
  - Installs the atoll-api skill to ~/.codex/skills/atoll-api/
47
- - Writes AGENTS.md with API reference to ~/.codex/
59
+ - Writes neutral AGENTS.md API guidance to ~/.codex/
48
60
  - Creates/updates an Atoll CLI profile when --profile is provided
61
+ - Optionally writes repo-local AGENTS.md/CLAUDE.md profile guidance with --write-project-instructions
49
62
  - Otherwise writes Atoll env vars to your shell profile for env-var mode
50
63
  `)
51
64
  }
@@ -64,6 +77,32 @@ if (args.help) { printUsage(); process.exit(0) }
64
77
 
65
78
  console.log(`Running @atollhq/skill-codex installer v${packageJson.version}`)
66
79
 
80
+ const instructionFileChoices = (args.instructionFiles ?? 'agents')
81
+ .split(',')
82
+ .map((entry) => entry.trim().toLowerCase())
83
+ .filter(Boolean)
84
+ const allowedInstructionFiles = new Set(['agents', 'claude'])
85
+ if (instructionFileChoices.some((entry) => !allowedInstructionFiles.has(entry))) {
86
+ console.error('Error: --instruction-files must be agents, claude, or agents,claude')
87
+ process.exit(1)
88
+ }
89
+
90
+ const projectInstructionFiles = [...new Set(instructionFileChoices)]
91
+ if (args.writeProjectInstructions && projectInstructionFiles.length === 0) {
92
+ console.error('Error: --instruction-files must include agents, claude, or agents,claude')
93
+ process.exit(1)
94
+ }
95
+
96
+ if (args.writeProjectInstructions && !args.profile) {
97
+ console.error('Error: --write-project-instructions requires --profile so the repo-local guidance can name a profile')
98
+ process.exit(1)
99
+ }
100
+
101
+ if (args.writeProjectInstructions && !/^[A-Za-z0-9][A-Za-z0-9._-]*$/.test(args.profile)) {
102
+ console.error('Error: --write-project-instructions requires a profile name that starts with a letter or number and contains only letters, numbers, dots, underscores, or hyphens')
103
+ process.exit(1)
104
+ }
105
+
67
106
  if (!args.key || !args.org) {
68
107
  console.error('Error: provide --key and --org, or set ATOLL_API_KEY and ATOLL_ORG_ID\n')
69
108
  printUsage()
@@ -104,7 +143,6 @@ function writeAtollProfile() {
104
143
  else delete profile.defaultTeam
105
144
  if (args.baseUrl) profile.baseUrl = args.baseUrl
106
145
  else delete profile.baseUrl
107
- config.activeProfile = args.profile
108
146
 
109
147
  mkdirSync(atollDir, { recursive: true })
110
148
  writeFileSync(configPath, JSON.stringify(config, null, 2) + '\n')
@@ -112,6 +150,107 @@ function writeAtollProfile() {
112
150
  return configPath
113
151
  }
114
152
 
153
+ const projectInstructionsStart = '<!-- ATOLL:PROJECT-INSTRUCTIONS:START -->'
154
+ const projectInstructionsEnd = '<!-- ATOLL:PROJECT-INSTRUCTIONS:END -->'
155
+ const projectInstructionsPattern = new RegExp(`${projectInstructionsStart}[\\s\\S]*?${projectInstructionsEnd}`)
156
+
157
+ function projectInstructionBlock(profileName) {
158
+ return `${projectInstructionsStart}
159
+ ## Atoll
160
+
161
+ For this workspace, use Atoll CLI profile \`${profileName}\`:
162
+
163
+ \`\`\`bash
164
+ atoll --profile ${profileName} ...
165
+ \`\`\`
166
+ ${projectInstructionsEnd}`
167
+ }
168
+
169
+ function removeUnmanagedAtollProfileGuidance(content) {
170
+ return content
171
+ .split('\n')
172
+ .filter((line) => !/atoll\s+--profile\s+\S+/i.test(line) && !/Atoll CLI profile/i.test(line))
173
+ .join('\n')
174
+ .replace(/\n{3,}/g, '\n\n')
175
+ .trimEnd()
176
+ }
177
+
178
+ function buildProjectInstructionUpdate(targetPath, block) {
179
+ const existing = existsSync(targetPath) ? readFileSync(targetPath, 'utf-8') : ''
180
+
181
+ if (projectInstructionsPattern.test(existing)) {
182
+ return {
183
+ targetPath,
184
+ content: existing.replace(projectInstructionsPattern, block),
185
+ }
186
+ }
187
+
188
+ if (/atoll\s+--profile\s+\S+/i.test(existing) || /Atoll CLI profile/i.test(existing)) {
189
+ if (!args.forceProjectInstructions) {
190
+ console.error(`Error: ${targetPath} already contains unmanaged Atoll profile guidance. Re-run with --force-project-instructions to replace it.`)
191
+ process.exit(1)
192
+ }
193
+ const cleaned = removeUnmanagedAtollProfileGuidance(existing)
194
+ return {
195
+ targetPath,
196
+ content: cleaned ? `${cleaned}\n\n${block}\n` : `${block}\n`,
197
+ }
198
+ }
199
+
200
+ return {
201
+ targetPath,
202
+ content: existing.trimEnd() ? `${existing.trimEnd()}\n\n${block}\n` : `${block}\n`,
203
+ }
204
+ }
205
+
206
+ function writeProjectInstructionUpdates(updates) {
207
+ const prepared = []
208
+
209
+ try {
210
+ for (const [index, { targetPath, content }] of updates.entries()) {
211
+ const tmpPath = join(dirname(targetPath), `.${basename(targetPath)}.atoll-${process.pid}-${Date.now()}-${index}.tmp`)
212
+ const normalized = content.endsWith('\n') ? content : `${content}\n`
213
+ writeFileSync(tmpPath, normalized, { flag: 'wx' })
214
+ prepared.push({ targetPath, tmpPath })
215
+ }
216
+
217
+ for (const { targetPath, tmpPath } of prepared) {
218
+ renameSync(tmpPath, targetPath)
219
+ console.log(`Wrote Atoll project instructions to ${targetPath}`)
220
+ }
221
+ } catch (error) {
222
+ for (const { tmpPath } of prepared) {
223
+ if (existsSync(tmpPath)) rmSync(tmpPath, { force: true })
224
+ }
225
+ console.error(`Error: failed to write Atoll project instructions: ${error.message}`)
226
+ process.exit(1)
227
+ }
228
+ }
229
+
230
+ function writeProjectInstructions() {
231
+ if (!args.writeProjectInstructions) return
232
+
233
+ const projectDir = resolve(args.projectDir ?? process.cwd())
234
+ if (!existsSync(projectDir) || !statSync(projectDir).isDirectory()) {
235
+ console.error(`Error: --project-dir must be an existing directory: ${projectDir}`)
236
+ process.exit(1)
237
+ }
238
+
239
+ const block = projectInstructionBlock(args.profile)
240
+ const fileNames = {
241
+ agents: 'AGENTS.md',
242
+ claude: 'CLAUDE.md',
243
+ }
244
+
245
+ const updates = []
246
+ for (const choice of projectInstructionFiles) {
247
+ const targetPath = join(projectDir, fileNames[choice])
248
+ updates.push(buildProjectInstructionUpdate(targetPath, block))
249
+ }
250
+
251
+ writeProjectInstructionUpdates(updates)
252
+ }
253
+
115
254
  // 1. Install the Codex skill to ~/.codex/skills/atoll-api/
116
255
  const codexDir = join(homedir(), '.codex')
117
256
  mkdirSync(codexDir, { recursive: true })
@@ -126,27 +265,9 @@ console.log(`Installed Atoll skill to ${skillDest}`)
126
265
  const skillMd = readFileSync(join(skillDir, 'SKILL.md'), 'utf-8')
127
266
  // Strip YAML frontmatter for AGENTS.md
128
267
  const body = skillMd.replace(/^---[\s\S]*?---\n*/, '')
129
- const profileModeInstructions = args.profile ? `## Profile-scoped CLI configuration
130
-
131
- This Codex install is scoped to Atoll CLI profile \`${args.profile}\`. No global \`ATOLL_API_KEY\`, \`ATOLL_ORG_ID\`, \`ATOLL_PROJECT\`, \`ATOLL_TEAM\`, or \`ATOLL_BASE_URL\` shell exports were written. Use \`atoll --profile ${args.profile} ...\` for direct Atoll CLI commands. Direct API snippets below use \`ATOLL_API_KEY\` / \`ATOLL_ORG_ID\` only when you intentionally choose env-var mode.
132
-
133
- ` : ''
134
- const optionalCredentialLines = [
135
- args.profile ? `- Atoll CLI profile: ${args.profile}` : null,
136
- args.project ? `- Default project ID: ${args.project}` : null,
137
- args.team ? `- Default team: ${args.team}` : null,
138
- args.baseUrl ? `- Base URL: ${args.baseUrl}` : null,
139
- ].filter(Boolean).join('\n')
140
-
141
268
  const agentsMd = `# Atoll Integration
142
269
 
143
- ${profileModeInstructions}
144
270
  ${body}
145
-
146
- ## Credentials
147
-
148
- - API Key: ${args.profile ? `stored in Atoll CLI profile \`${args.profile}\`` : 'set as ATOLL_API_KEY environment variable'}
149
- - Org ID: ${args.org}${optionalCredentialLines ? `\n${optionalCredentialLines}` : ''}
150
271
  `
151
272
 
152
273
  const agentsPath = join(codexDir, 'AGENTS.md')
@@ -193,10 +314,11 @@ if (args.profile) {
193
314
  console.log(`Removed stale Atoll shell exports from ${profilePath}`)
194
315
  }
195
316
  writeAtollProfile()
317
+ writeProjectInstructions()
196
318
  console.log('No Atoll shell exports were written.')
197
319
  console.log(`Run profile-scoped commands with: atoll --profile ${args.profile} ...`)
198
320
  console.log(`Verify the profile with: atoll --profile ${args.profile} agent-context --json`)
199
- console.log(`\nDone! Codex has the Atoll skill installed, and the Atoll CLI profile "${args.profile}" is active.`)
321
+ console.log(`\nDone! Codex has the Atoll skill installed, and the Atoll CLI profile "${args.profile}" is configured.`)
200
322
  process.exit(0)
201
323
  }
202
324
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atollhq/skill-codex",
3
- "version": "0.4.9",
3
+ "version": "0.4.10",
4
4
  "description": "Install the Atoll project management integration for Codex CLI",
5
5
  "bin": {
6
6
  "skill-codex": "bin/install.mjs"
package/skill/SKILL.md CHANGED
@@ -186,7 +186,7 @@ CLI JSON conventions:
186
186
 
187
187
  When a human asks you to help automate a KPI from a third-party API, use this Atoll skill. If the current agent environment does not have the `atoll-api` skill installed, tell the user to install it before continuing or use the Atoll CLI/MCP tools directly if they are available.
188
188
 
189
- Agents may create draft syncs and validate proposed configs only after a human admin has allowlisted the exact destination host in Atoll. Human admins must review the draft in Atoll, enter secrets, dry-run, publish, disable, or run-now with snapshot writing.
189
+ Agents may create draft syncs and validate proposed configs only after a human admin has allowlisted the exact destination host in Atoll. Human admins must create or review the draft in Settings > Integrations > KPI syncs, edit supported request/extraction fields and secrets through structured UI, dry-run, publish, disable, or run-now with snapshot writing.
190
190
 
191
191
  ```bash
192
192
  atoll kpi sync validate <kpi-id> \
@@ -203,6 +203,7 @@ Roles: `owner`, `admin`, `member`, `guest`.
203
203
  | POST | `/api/orgs/{id}/kpis/{kpiId}/snapshots` | Record a snapshot |
204
204
  | GET | `/api/orgs/{id}/kpi-http-sync-policy` | List exact-host KPI HTTP sync allowlist policy |
205
205
  | POST | `/api/orgs/{id}/kpi-http-sync-policy` | Add an allowed exact host (human admin only) |
206
+ | GET | `/api/orgs/{id}/kpi-http-syncs` | List org-wide KPI HTTP sync review rows for Settings; admins get config/secret metadata, members get redacted status rows |
206
207
  | GET | `/api/orgs/{id}/kpis/{kpiId}/http-syncs` | List KPI HTTP syncs |
207
208
  | POST | `/api/orgs/{id}/kpis/{kpiId}/http-syncs` | Create a draft KPI HTTP sync |
208
209
  | PUT | `/api/orgs/{id}/kpis/{kpiId}/http-syncs` | Validate a proposed KPI HTTP sync config without storing or running it |