@atollhq/skill-claude 0.4.9 → 0.4.11

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
@@ -12,14 +12,14 @@ npx @atollhq/skill-claude@latest --profile agent-a --key sk_atoll_... --org your
12
12
  ATOLL_API_KEY=sk_atoll_... ATOLL_ORG_ID=your-org-id npx @atollhq/skill-claude@latest
13
13
  ```
14
14
 
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; Claude settings keep only `ATOLL_PROFILE` so direct CLI commands can use the profile safely. Omit `--profile` to use env-var mode, which writes `ATOLL_ENV_MODE=1` with the credential settings.
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 a global `ATOLL_PROFILE` or `ATOLL_*` credential settings in profile mode, so direct CLI commands should use `atoll --profile agent-a ...`. Omit `--profile` to use env-var mode, which writes `ATOLL_ENV_MODE=1` with the credential settings.
16
16
 
17
17
  Get an agent API key from **Agents** in the Atoll app. Integration keys are still managed from **Settings > Members**.
18
18
 
19
19
  This does three things:
20
20
 
21
21
  1. Copies the skill into `~/.claude/skills/atoll-api/`
22
- 2. Stores only `ATOLL_PROFILE` in `~/.claude/settings.json` when profile mode is used
22
+ 2. Removes stale Atoll credential/profile env from `~/.claude/settings.json` when profile mode is used
23
23
  3. Creates or updates the named Atoll CLI profile when `--profile` is provided
24
24
 
25
25
  Restart Claude Code and the `atoll-api` skill is available.
@@ -47,9 +47,9 @@ For terminal-first work, see [`@atollhq/cli`](https://www.npmjs.com/package/@ato
47
47
  ```bash
48
48
  npm install -g @atollhq/cli
49
49
  atoll auth login --profile agent-a --key sk_atoll_... --org-id org-uuid --project project-id --team team-id
50
- atoll heartbeat
51
- atoll issue list --json
52
- atoll agent-context
50
+ atoll --profile agent-a heartbeat
51
+ atoll --profile agent-a issue list --json
52
+ atoll --profile agent-a agent-context
53
53
  ```
54
54
 
55
55
  For multiple agents or orgs, use CLI auth profiles:
package/bin/install.mjs CHANGED
@@ -115,7 +115,6 @@ function writeAtollProfile() {
115
115
  else delete profile.defaultTeam
116
116
  if (args.baseUrl) profile.baseUrl = args.baseUrl
117
117
  else delete profile.baseUrl
118
- config.activeProfile = args.profile
119
118
 
120
119
  mkdirSync(atollDir, { recursive: true })
121
120
  writeFileSync(configPath, JSON.stringify(config, null, 2) + '\n')
@@ -131,14 +130,14 @@ cpSync(skillSrc, skillDest, { recursive: true })
131
130
  console.log(`Installed skill to ${skillDest}`)
132
131
 
133
132
  // 2. Configure ~/.claude/settings.json. Profile mode stores credentials only
134
- // in the Atoll CLI profile and keeps Claude's host env limited to profile
135
- // selection, removing stale credential/default env from earlier installs.
133
+ // in the Atoll CLI profile and removes stale credential/profile env from
134
+ // earlier installs so a new profile install does not become globally active.
136
135
  const settingsPath = join(homedir(), '.claude', 'settings.json')
137
136
  let settings = readJson(settingsPath)
138
137
 
139
138
  if (!settings.env) settings.env = {}
140
139
  if (args.profile) {
141
- settings.env.ATOLL_PROFILE = args.profile
140
+ delete settings.env.ATOLL_PROFILE
142
141
  delete settings.env.ATOLL_API_KEY
143
142
  delete settings.env.ATOLL_ORG_ID
144
143
  delete settings.env.ATOLL_PROJECT
@@ -163,15 +162,17 @@ writeAtollProfile()
163
162
 
164
163
  const configuredVars = []
165
164
  if (args.profile) {
166
- configuredVars.push('ATOLL_PROFILE')
165
+ console.log(`Removed stale Atoll env from ${settingsPath}`)
167
166
  } else {
168
167
  configuredVars.push('ATOLL_API_KEY', 'ATOLL_ORG_ID', 'ATOLL_ENV_MODE')
169
168
  if (args.project) configuredVars.push('ATOLL_PROJECT')
170
169
  if (args.team) configuredVars.push('ATOLL_TEAM')
171
170
  if (args.baseUrl) configuredVars.push('ATOLL_BASE_URL')
171
+ console.log(`Configured ${configuredVars.join(', ')} in ${settingsPath}`)
172
172
  }
173
- console.log(`Configured ${configuredVars.join(', ')} in ${settingsPath}`)
174
173
  if (args.profile) {
174
+ console.log('No global Claude ATOLL_PROFILE was written.')
175
+ console.log(`Run profile-scoped commands with: atoll --profile ${args.profile} ...`)
175
176
  console.log(`Verify the profile with: atoll --profile ${args.profile} agent-context --json`)
176
177
  }
177
178
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atollhq/skill-claude",
3
- "version": "0.4.9",
3
+ "version": "0.4.11",
4
4
  "description": "Install the Atoll project management skill for Claude Code",
5
5
  "bin": {
6
6
  "skill-claude": "bin/install.mjs"
package/skill/SKILL.md CHANGED
@@ -123,6 +123,7 @@ atoll issue bulk-create --file ./issues.json --continue-on-error
123
123
 
124
124
  # Update a task
125
125
  atoll issue update ATOLL-42 --status in_progress
126
+ atoll issue update ATOLL-42 --status in_progress --comment-body "Starting this because the activation KPI is off pace."
126
127
  atoll issue upsert ATOLL-42 --status in_progress
127
128
  atoll issue bulk-update --file ./updates.json --dry-run
128
129
 
@@ -161,6 +162,9 @@ atoll kpi create --name paying_customers --goal "Reach 100 paying customers by Q
161
162
  atoll kpi create --name mvp_tasks_done --goal "Launch MVP" --internal-task-completion
162
163
  atoll initiative create --title "Content pipeline" --goal "Reach 100 paying customers by Q2" --status active
163
164
  atoll initiative kpi link "Content pipeline" paying_customers --impact "+30 customers/mo"
165
+ atoll initiative target create "Content pipeline" --title "Publish 10 comparison posts" --mode progress --target 10 --current 0 --unit count --unit-label posts
166
+ atoll initiative target create "Retailer coverage" --title "Get 5 retailers live by July 5" --mode gate --target 5 --current 0 --unit count --unit-label retailers --target-date 2026-07-05 --due-soon-days 7
167
+ atoll initiative target issue link "Retailer coverage" "Get 5 retailers live by July 5" ATOLL-42
164
168
  atoll kpi snapshot add paying_customers --value 42 --initiative "Content pipeline" --note "End-of-week Stripe check"
165
169
 
166
170
  # Audit the strategy chain for gaps (orphaned initiatives, goals with no KPI, etc.)
@@ -179,14 +183,14 @@ CLI JSON conventions:
179
183
  - Diagnostics and errors go to stderr.
180
184
  - Interactive CLI update notices also go to stderr and are suppressed for JSON/non-TTY/CI/completion flows.
181
185
  - `atoll agent-context` returns a versioned command/flag manifest, available profile context, and structured `cli.update_available` metadata.
182
- - `atoll heartbeat --json` includes the same structured `cli` update metadata for agents.
186
+ - `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.
183
187
  - `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`.
184
188
 
185
189
  ## KPI HTTP Sync Drafts
186
190
 
187
191
  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
192
 
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.
193
+ 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
194
 
191
195
  ```bash
192
196
  atoll kpi sync validate <kpi-id> \
@@ -313,14 +317,18 @@ The primary pattern for autonomous agents. Prefer `atoll heartbeat --json` when
313
317
 
314
318
  - **Goal status** with days remaining
315
319
  - **KPI pace**: `pace_needed` vs `pace_actual`, trend (`accelerating`/`decelerating`/`flat`), staleness
316
- - **Initiative progress**: total/completed/stalled/blocked issue counts, expected KPI impacts
320
+ - **Initiative progress**: total/completed/stalled/blocked issue counts, expected KPI impacts, and initiative targets
317
321
  - **Assigned work** for this agent
318
322
  - **Project context**: relevant board columns, including optional descriptions that explain stage criteria for agents
319
323
  - **Signals** sorted by severity — the agent's prioritized to-do list
324
+ - **Attention items**: direct current-member notifications such as mentions, assignments, assignee comments, and creator-visible status changes, with an `ack_endpoint` to call after handling
325
+ - **Recommended action**: one deterministic strategy-backed next action when Atoll has enough evidence (`create_work`, `start_work`, `escalate_blocker`, or `refresh_metric`), including why-now, expected impact, first step, success criteria, quality warnings, and any suggested write.
320
326
 
321
327
  Heartbeat is org-scoped, but project-bound payload details are filtered by the caller's project access. Owners/admins receive full org context; members/guests only receive project-bound strategy, work health, assigned work, milestone signals, and board context for accessible projects. Non-guest members can also see unprojected org-level strategy. Shared initiatives can appear with counts and signals based only on accessible work.
322
328
 
323
- Signal types: `kpi_off_pace`, `kpi_stale`, `issue_stale`, `issue_blocked`, `milestone_overdue`, `initiative_stalled`, `webhook_failing`. Severity: `info`, `warning`, `critical`.
329
+ Signal types: `kpi_off_pace`, `kpi_stale`, `issue_stale`, `issue_blocked`, `milestone_overdue`, `initiative_stalled`, `initiative_target_due_soon`, `initiative_target_overdue`, `initiative_target_blocked`, `webhook_failing`. Severity: `info`, `warning`, `critical`.
330
+
331
+ Targets under initiatives are commitments, not business KPIs. KPIs measure business outcomes such as MRR, traffic, paying customers, or onboarding success. Use progress targets for initiative outputs such as "publish 10 comparison posts." Use gate targets for launch prerequisites such as "get 5 retailers live by July 5." Gate targets emit stateful due/blocked messages and should not be converted into fractional KPI pace such as "0.07 retailers/day."
324
332
 
325
333
  Useful CLI forms:
326
334
 
@@ -333,10 +341,12 @@ atoll heartbeat --json
333
341
 
334
342
  **The agent loop:**
335
343
  1. Call heartbeat
336
- 2. Read signals (highest severity first)
337
- 3. Reason about highest-leverage action given KPI pace and initiative state
338
- 4. Execute (unblock issues, update KPIs, create work, report progress)
339
- 5. Repeat
344
+ 2. Handle direct `attention_items` that need a reply, task update, or blocker follow-up
345
+ 3. Call each handled item's `ack_endpoint`
346
+ 4. Read remaining signals (highest severity first)
347
+ 5. Reason about highest-leverage action given direct attention, gate targets, KPI pace, and initiative state
348
+ 6. Execute (unblock issues, update KPIs, create work, report progress)
349
+ 7. Repeat
340
350
 
341
351
  ## Other Common Workflows
342
352
 
@@ -345,7 +355,7 @@ atoll heartbeat --json
345
355
  ```bash
346
356
  atoll heartbeat --signals-only # orient first
347
357
  atoll issue list --status todo --assignee self --json # find assigned work
348
- atoll issue update ATOLL-42 --status in_progress # start work
358
+ atoll issue update ATOLL-42 --status in_progress --comment-body "Starting because the linked KPI is off pace." # start work with durable context
349
359
  atoll comment add ATOLL-42 --body "Progress update…" # report progress
350
360
  atoll issue update ATOLL-42 --status done # complete
351
361
  ```
@@ -357,7 +367,8 @@ atoll issue update ATOLL-42 --status done # complete
357
367
  3. `POST /api/orgs/{id}/kpis/{kpiId}/snapshots` -- record measurement (auto-updates `current_value`)
358
368
  4. `POST /api/orgs/{id}/initiatives` -- create initiative linked to goal
359
369
  5. `POST /api/orgs/{id}/initiatives/{id}/kpi-impacts` -- declare expected KPI impact
360
- 6. Link issues and milestones to the initiative
370
+ 6. `POST /api/orgs/{id}/initiatives/{id}/targets` -- create progress or gate targets for initiative commitments
371
+ 7. Link issues and milestones to the initiative and to specific targets when the work exists to satisfy that target
361
372
 
362
373
  CLI equivalent:
363
374
 
@@ -366,6 +377,8 @@ atoll goal create --title "Reach 100 paying customers by Q2" --target-date 2026-
366
377
  atoll kpi create --name paying_customers --goal "Reach 100 paying customers by Q2" --unit count --target 100 --current 34
367
378
  atoll initiative create --title "Content pipeline" --goal "Reach 100 paying customers by Q2" --status active
368
379
  atoll initiative kpi link "Content pipeline" paying_customers --impact "+30 customers/mo"
380
+ atoll initiative target create "Content pipeline" --title "Publish 10 comparison posts" --mode progress --target 10 --current 0 --unit count --unit-label posts
381
+ atoll initiative target create "Retailer coverage" --title "Get 5 retailers live by July 5" --mode gate --target 5 --current 0 --unit count --unit-label retailers --target-date 2026-07-05 --due-soon-days 7
369
382
  atoll kpi snapshot add paying_customers --value 42 --initiative "Content pipeline" --note "End-of-week Stripe check"
370
383
  ```
371
384
 
@@ -412,7 +425,7 @@ Delivery rows expose `delivery_id`, `status`, and `next_retry_at`. Network failu
412
425
 
413
426
  ### Billing and plan limits
414
427
 
415
- Owners/admins can read billing state with `GET /api/orgs/{id}/billing` and start Stripe checkout with `POST /api/orgs/{id}/billing/checkout` using `{ "plan": "starter" }` or `{ "plan": "team" }`.
428
+ Owners/admins can read billing state with `GET /api/orgs/{id}/billing` and start a self-serve Stripe billing flow with `POST /api/orgs/{id}/billing/checkout` using `{ "plan": "starter" }`, `{ "plan": "team" }`, or `{ "plan": "pro" }`. Owner/admin read requests sync Stripe first and return `502` with `Stripe billing sync failed` if that sync cannot complete, rather than serving stale local billing state. New subscribers use Checkout; existing active, trialing, or past-due subscribers use a Billing Portal update confirmation.
416
429
 
417
430
  Creation endpoints can return `402` with `code: "PLAN_LIMIT_REACHED"` when an org reaches limits for humans, agents/integrations, active projects, or active issues.
418
431
 
@@ -440,6 +453,10 @@ Initiative create accepts `title` or legacy `name`, plus camelCase aliases `goal
440
453
 
441
454
  All endpoints are under `/api/orgs/{orgId}/...`.
442
455
 
456
+ Issue comments inherit issue project permissions: listing comments requires access to the issue's project, comment writes (add, edit, delete) require write access to that project, edit/delete still require comment authorship, and guests cannot access comments on unprojected issues.
457
+
458
+ Comment bodies accept Markdown/plain text or existing rich-text HTML. Atoll stores and returns comment bodies as sanitized HTML. If sanitization leaves no visible text or safe media, the request returns `400` with `body is required` for direct comments or `comment_body is required` for issue updates with `comment_body`.
459
+
443
460
  † `DELETE /issues/{id}` requires `owner` or `admin` role — any caller without that role (including member-role agents) gets `403`. If you just need to remove a task, use `POST /api/orgs/{orgId}/issues/{issueId}/archive` (soft delete, no role gate); reverse with `DELETE` on the same path (unarchive). In the CLI, prefer `atoll issue archive <id>`. Permanent `atoll issue delete <id>` requires `--force` and supports `--dry-run`.
444
461
 
445
462
  ### Quick enum reference
@@ -488,7 +505,7 @@ atoll feedback resend fb_123
488
505
  ## Notes
489
506
 
490
507
  - Request bodies accept camelCase; responses use snake_case
491
- - Descriptions and comments support Markdown
508
+ - Descriptions support Markdown; comment bodies accept Markdown/plain text or rich-text HTML and are stored as sanitized HTML
492
509
  - All timestamps are ISO 8601 UTC
493
510
  - Board statuses are customizable per project -- query `/board-columns` for available values and optional column descriptions
494
511
  - API changes appear in real-time on the web board
@@ -89,12 +89,12 @@ Access levels: `view`, `edit`, `admin` (default: `view`).
89
89
 
90
90
  ## Billing
91
91
 
92
- Org billing is managed through Stripe. Owners/admins can create checkout and billing portal sessions.
92
+ Org billing is managed through Stripe. Owners/admins can start self-serve billing flows and create billing portal sessions.
93
93
 
94
94
  | Method | Endpoint | Description |
95
95
  |--------|----------|-------------|
96
- | GET | `/api/orgs/{id}/billing` | Get plan, status, usage, limits, and subscription summary |
97
- | POST | `/api/orgs/{id}/billing/checkout` | Create Stripe Checkout Session (`{ plan: "starter" \| "team" }`) |
96
+ | GET | `/api/orgs/{id}/billing` | Get plan, status, usage, limits, and subscription summary; owner/admin read requests sync Stripe first and return `502` if that sync fails |
97
+ | POST | `/api/orgs/{id}/billing/checkout` | Start Stripe billing flow (`{ plan: "starter" \| "team" \| "pro" }`); new subscribers use Checkout and existing active/trialing/past-due subscribers use Billing Portal update confirmation |
98
98
  | POST | `/api/orgs/{id}/billing/portal` | Create Stripe Billing Portal Session |
99
99
 
100
100
  Plan limits are enforced when creating projects, human members, agents/integrations, and active tasks. Limit errors return `402` with `code: "PLAN_LIMIT_REACHED"`.
@@ -106,7 +106,7 @@ Plan limits are enforced when creating projects, human members, agents/integrati
106
106
  | GET | `/api/orgs/{id}/issues` | List tasks (see filters below) |
107
107
  | POST | `/api/orgs/{id}/issues` | Create task |
108
108
  | GET | `/api/orgs/{id}/issues/{issueId}` | Get task detail |
109
- | PATCH | `/api/orgs/{id}/issues/{issueId}` | Update task |
109
+ | PATCH | `/api/orgs/{id}/issues/{issueId}` | Update task; optional `comment_body` also adds a task comment in the same request |
110
110
  | DELETE | `/api/orgs/{id}/issues/{issueId}` | Delete task (admin/owner only) |
111
111
  | POST | `/api/orgs/{id}/issues/bulk` | Bulk create tasks (up to 50) |
112
112
  | GET | `/api/orgs/{id}/issues/search?q=...` | Search tasks by title |
@@ -120,7 +120,8 @@ Issue-centric initiative links follow task project permissions: reading links re
120
120
  - `status` -- `backlog`, `todo`, `in_progress`, `done`, `cancelled`
121
121
  - `priority` -- `0` (urgent), `1` (high), `2` (medium), `3` (low)
122
122
  - `projectId`, `assigneeId`, `teamId`, `milestoneId`
123
- - `q` -- search title and description (case-insensitive)
123
+ - `q` -- full issue lists search title and description (case-insensitive)
124
+ - Compact views (`view=board` or `view=list`) also support `assignee` (member ID or `unassigned`, including multi-assignee links), `initiativeId`, `scope` (`mine` or `blocked`), and `q` over title plus issue number
124
125
  - `includeArchived` -- `true` to include archived tasks
125
126
  - `orderBy` -- `created_at` (default), `updated_at`, `priority`, `due_date`, `title`, `status`
126
127
  - `orderDir` -- `asc` or `desc` (default)
@@ -149,6 +150,10 @@ Add with `{ "blockedByIssueId": "uuid" }` or `{ "blockingIssueId": "uuid" }`. Ci
149
150
  | PATCH | `/api/orgs/{id}/issues/{issueId}/comments/{commentId}` | Edit comment |
150
151
  | DELETE | `/api/orgs/{id}/issues/{issueId}/comments/{commentId}` | Delete comment |
151
152
 
153
+ Issue comments inherit issue project permissions: listing comments requires access to the issue's project, comment writes (add, edit, delete) require write access to that project, edit/delete still require comment authorship, and guests cannot access comments on unprojected issues.
154
+
155
+ Comment bodies accept Markdown/plain text or existing rich-text HTML. Atoll stores and returns comment bodies as sanitized HTML. If sanitization leaves no visible text or safe media, the request returns `400` with `body is required` for direct comments or `comment_body is required` for issue updates with `comment_body`.
156
+
152
157
  ## Subtasks
153
158
 
154
159
  | Method | Endpoint | Description |
@@ -203,6 +208,7 @@ Roles: `owner`, `admin`, `member`, `guest`.
203
208
  | POST | `/api/orgs/{id}/kpis/{kpiId}/snapshots` | Record a snapshot |
204
209
  | GET | `/api/orgs/{id}/kpi-http-sync-policy` | List exact-host KPI HTTP sync allowlist policy |
205
210
  | POST | `/api/orgs/{id}/kpi-http-sync-policy` | Add an allowed exact host (human admin only) |
211
+ | 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
212
  | GET | `/api/orgs/{id}/kpis/{kpiId}/http-syncs` | List KPI HTTP syncs |
207
213
  | POST | `/api/orgs/{id}/kpis/{kpiId}/http-syncs` | Create a draft KPI HTTP sync |
208
214
  | PUT | `/api/orgs/{id}/kpis/{kpiId}/http-syncs` | Validate a proposed KPI HTTP sync config without storing or running it |
@@ -244,6 +250,19 @@ Create accepts `title` or legacy `name`, plus camelCase aliases `goalId`, `owner
244
250
  | GET | `.../initiatives/{id}/milestones` | List linked milestones |
245
251
  | POST | `.../initiatives/{id}/milestones` | Link milestone (`{ milestone_id }`) |
246
252
  | DELETE | `.../initiatives/{id}/milestones/{milestoneId}` | Unlink milestone |
253
+ | GET | `.../initiatives/{id}/targets` | List initiative targets |
254
+ | POST | `.../initiatives/{id}/targets` | Create target (`{ title, mode?, current_value?, target_value?, unit?, unit_label?, target_date?, due_soon_days? }`) |
255
+ | GET | `.../initiatives/{id}/targets/{targetId}` | Get target |
256
+ | PATCH | `.../initiatives/{id}/targets/{targetId}` | Update target |
257
+ | DELETE | `.../initiatives/{id}/targets/{targetId}` | Delete target |
258
+ | GET | `.../initiatives/{id}/targets/{targetId}/issues` | List target issue links |
259
+ | POST | `.../initiatives/{id}/targets/{targetId}/issues` | Link issue to target (`{ issue_id }`) |
260
+ | DELETE | `.../initiatives/{id}/targets/{targetId}/issues/{issueId}` | Unlink issue from target |
261
+ | GET | `.../initiatives/{id}/targets/{targetId}/milestones` | List target milestone links |
262
+ | POST | `.../initiatives/{id}/targets/{targetId}/milestones` | Link milestone to target (`{ milestone_id }`) |
263
+ | DELETE | `.../initiatives/{id}/targets/{targetId}/milestones/{milestoneId}` | Unlink milestone from target |
264
+
265
+ Targets are initiative-level commitments. Use `mode: "progress"` for normal output tracking and `mode: "gate"` for launch blockers or prerequisites where KPI pace language would be misleading. Targets do not create KPI snapshots.
247
266
 
248
267
  ## Strategy
249
268
 
@@ -259,7 +278,7 @@ Returns findings only (not the full graph). Use it for a high-level review — o
259
278
  |--------|----------|-------------|
260
279
  | GET | `/api/orgs/{id}/heartbeat` | Get heartbeat context for the authenticated agent |
261
280
 
262
- Returns computed briefing with goal status, KPI pace/trend, initiative progress, assigned work, and signals. The endpoint is org-scoped, but project-bound payload details are filtered by the caller's project access; non-guest members can also see unprojected org-level strategy, and shared initiatives can appear with counts and signals based only on accessible work.
281
+ Returns computed briefing with goal status, KPI pace/trend, initiative progress, assigned work, direct `attention_items`, `attention_summary`, signals, and a deterministic `recommended_action` when Atoll can propose one concrete strategy-backed next action. The endpoint is org-scoped, but project-bound payload details are filtered by the caller's project access; non-guest members can also see unprojected org-level strategy, and shared initiatives can appear with counts and signals based only on accessible work.
263
282
 
264
283
  Signal types: `kpi_off_pace`, `kpi_stale`, `issue_stale`, `issue_blocked`, `milestone_overdue`, `initiative_stalled`, `webhook_failing`. Severity: `info`, `warning`, `critical`.
265
284
 
@@ -271,6 +290,8 @@ atoll heartbeat --signals-only
271
290
  atoll heartbeat --severity critical
272
291
  ```
273
292
 
293
+ `atoll heartbeat --signals-only --json` returns filtered `signals`, direct `attention_items`, `attention_summary`, and `recommended_action` for polling agents.
294
+
274
295
  ## Activity
275
296
 
276
297
  | Method | Endpoint | Description |
@@ -419,10 +440,16 @@ URL must be an HTTPS DNS hostname. IP literals, `localhost`, and `.local` hosts
419
440
 
420
441
  | Method | Endpoint | Description |
421
442
  |--------|----------|-------------|
443
+ | GET | `/api/orgs/{id}/notifications` | List unread actionable notifications for current org member |
444
+ | POST | `/api/orgs/{id}/notifications/{notificationId}/ack` | Acknowledge current-member notification |
445
+ | GET | `/api/orgs/{id}/notifications/preferences` | Read current-member notification preferences, including default-on mention notifications |
446
+ | POST | `/api/orgs/{id}/notifications/preferences` | Update current-member notification preferences, including mention opt-out and cleanup |
422
447
  | GET | `/api/notifications` | List notifications (last 50, unread first) |
423
448
  | POST | `/api/notifications/{id}/read` | Mark as read |
424
449
  | POST | `/api/notifications/read-all` | Mark all as read |
425
450
 
451
+ Current-member notifications can include `mention.created`, `issue.assigned`, `comment.added`, and `issue.status_changed`. Notification preferences currently support mention opt-out for `mention.created`. Disabling in-app `mention.created` delivery also attempts to acknowledge that member's currently unread mention notifications; when cleanup succeeds, muted mentions leave both the bell and heartbeat `attention_items`.
452
+
426
453
  ## Agents
427
454
 
428
455
  | Method | Endpoint | Description |
@@ -201,6 +201,27 @@ Use `title` for create/update requests; create also accepts legacy `name`. Atoll
201
201
 
202
202
  Add/remove projects with `{ "project_id": "uuid" }`.
203
203
 
204
+ ## Initiative Target Fields
205
+
206
+ Targets attach to initiatives and track commitments separately from business KPIs. Use `mode: "progress"` for initiative outputs and `mode: "gate"` for hard launch prerequisites. Gate target heartbeat signals use stateful copy such as `0/5 retailers complete`; agents must not convert them into fractional KPI pace.
207
+
208
+ ```json
209
+ {
210
+ "title": "Get 5 retailers live by July 5",
211
+ "description": "Prerequisite before price comparison launch",
212
+ "mode": "gate",
213
+ "unit": "count",
214
+ "unit_label": "retailers",
215
+ "current_value": 0,
216
+ "target_value": 5,
217
+ "target_direction": "increase",
218
+ "target_date": "2026-07-05",
219
+ "due_soon_days": 7
220
+ }
221
+ ```
222
+
223
+ Target work links use `{ "issue_id": "issue-uuid" }` at `.../targets/{targetId}/issues` and `{ "milestone_id": "milestone-uuid" }` at `.../targets/{targetId}/milestones`. Target response rows include linked `issueIds` and `milestoneIds` when returned by the target list/get endpoints.
224
+
204
225
  ## Automation Rule Fields
205
226
 
206
227
  ```json
@@ -233,7 +254,7 @@ Add/remove projects with `{ "project_id": "uuid" }`.
233
254
 
234
255
  ## Board Context Response
235
256
 
236
- `GET /api/orgs/{id}/projects/{projectId}/board-context` returns the strategy data used by the board context rail:
257
+ `GET /api/orgs/{id}/projects/{projectId}/board-context` returns the strategy data used by the board filter toolbar:
237
258
 
238
259
  ```json
239
260
  {
@@ -333,7 +354,20 @@ Proposal JSON currently supports at most one item in each collection: `projects`
333
354
  "total_issues": 8,
334
355
  "completed_issues": 3,
335
356
  "stalled_issues": 2,
336
- "blocked_issues": 1
357
+ "blocked_issues": 1,
358
+ "project_ids": ["..."],
359
+ "linked_issues": [{
360
+ "id": "...",
361
+ "title": "Publish comparison page",
362
+ "status": "todo",
363
+ "priority": 1,
364
+ "assignee_id": "...",
365
+ "project_id": "...",
366
+ "milestone_id": null,
367
+ "number": 42,
368
+ "blocked": false,
369
+ "updated_at": "2026-03-28T12:00:00Z"
370
+ }]
337
371
  }]
338
372
  }],
339
373
  "standalone_kpis": [...],
@@ -349,12 +383,59 @@ Proposal JSON currently supports at most one item in each collection: `projects`
349
383
  }],
350
384
  "signals": [
351
385
  { "type": "kpi_off_pace", "severity": "warning", "message": "..." }
352
- ]
386
+ ],
387
+ "recommended_action": {
388
+ "id": "create_work:...",
389
+ "action_type": "create_work",
390
+ "title": "Create Content pipeline work for paying_customers",
391
+ "target_type": "initiative",
392
+ "target_id": "...",
393
+ "goal_id": "...",
394
+ "kpi_id": "...",
395
+ "initiative_id": "...",
396
+ "source_signal_ids": ["kpi_off_pace:..."],
397
+ "why_now": "paying_customers is off pace, and Content pipeline has no active linked issue.",
398
+ "expected_impact": "Create the missing execution path for the initiative expected to move paying_customers: +30 signups/mo.",
399
+ "evidence": ["KPI \"paying_customers\" is off pace..."],
400
+ "first_step": "Open Content pipeline and define the smallest task that can move paying_customers.",
401
+ "success_criteria": ["Create or update concrete follow-up actions tied to paying_customers."],
402
+ "suggested_write": {
403
+ "operation": "issue.create",
404
+ "title": "Create Content pipeline work for paying_customers",
405
+ "body": "<h2>Why now</h2>...",
406
+ "status": "todo",
407
+ "priority": 1,
408
+ "project_id": "...",
409
+ "initiative_id": "...",
410
+ "kpi_id": "...",
411
+ "initiative_target_id": "..."
412
+ },
413
+ "confidence": "high",
414
+ "caveats": [],
415
+ "quality_checks": [{ "id": "kpi_link", "status": "pass", "message": "Recommendation includes a KPI link." }],
416
+ "usage_guidance": {
417
+ "instructions": [
418
+ "Prefer suggested_write.operation when it matches the current board state and the recommendation is still current.",
419
+ "Preserve goal, KPI, initiative, initiative target, why-now, expected impact, first step, suggested_write, and success criteria evidence in any issue, status update, KPI refresh, or comment you create.",
420
+ "Do not copy deferred busywork, unrelated tasks, or caveat text into write payloads unless it is directly needed for the recommended action."
421
+ ],
422
+ "preserve_fields": ["goal_id", "kpi_id", "initiative_id", "initiative_target_id", "why_now", "expected_impact", "first_step", "success_criteria", "suggested_write"],
423
+ "avoid_payload_sources": ["deferred_busywork", "unrelated_assigned_issues", "stale_recommendations_after_board_change"]
424
+ }
425
+ }
353
426
  }
354
427
  ```
355
428
 
356
429
  Heartbeat is org-scoped, but project-bound goals, KPIs, initiatives, issue health, milestone signals, assigned work, and `project_context` are filtered by the caller's project access. Non-guest members can also see unprojected org-level strategy. Shared initiatives can appear with counts and signals based only on accessible work.
357
430
 
431
+ Heartbeat also includes `attention_items` for direct current-member notifications such as mentions, assignments, assignee comments, and creator-visible status changes. Each attention item includes `id`, `source`, `event_type`, `severity`, `action_kind`, resource fields, `target_path`, `created_at`, and `ack_endpoint`; after handling the referenced item, call `ack_endpoint` so the notification is acknowledged and removed from later heartbeat attention results. `attention_summary` includes counts such as `mentions`, `assignments`, `blockers`, and `total_unread`.
432
+
433
+ Current-member notifications can use `event_type` values such as `mention.created`, `issue.assigned`, `comment.added`, and `issue.status_changed`. Notification preferences use `event_type` (currently `mention.created`), `channel` (currently `in_app`), and `enabled` for current-member mention opt-out. Setting `enabled: false` for in-app `mention.created` also attempts to acknowledge that member's currently unread mention notifications; when cleanup succeeds, they no longer appear in notification lists or heartbeat `attention_items`.
434
+
435
+ Agents should 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 in any write, and avoid copying deferred busywork or unrelated assigned tasks into issue or comment payloads. When `start_work` uses `suggested_write.operation: "issue.update"` with a body, apply the status update and preserve that body as an issue comment; `PATCH /issues/{issueId}` accepts `comment_body` for this same-request progress note.
436
+
437
+ `recommended_action` is a deterministic strategy-backed next action built from heartbeat context. MVP action types are `create_work`, `start_work`, `escalate_blocker`, and `refresh_metric`; suggested writes may prefill issue creation, issue status updates, blocker comments, or KPI refresh requests. Issue-create bodies are HTML for Atoll's rich-text issue description; blocker/comment and metric-refresh bodies are plain text.
438
+
358
439
  ## Strategy Audit Response
359
440
 
360
441
  `GET /api/orgs/{id}/strategy/audit` returns findings (sorted critical → warning → info), each with a concrete `suggested_fix`, plus summary counts.
@@ -376,11 +457,11 @@ Heartbeat is org-scoped, but project-bound goals, KPIs, initiatives, issue healt
376
457
  }
377
458
  ```
378
459
 
379
- Each finding carries whichever entity ids apply: `goal_id`, `kpi_id`, `initiative_id`, `issue_id`, `milestone_id`, `project_id`. Finding `type` values:
460
+ Each finding carries whichever entity ids apply: `goal_id`, `kpi_id`, `initiative_id`, `initiative_target_id`, `issue_id`, `milestone_id`, `project_id`. Finding `type` values:
380
461
 
381
462
  - Structural: `initiative_orphaned`, `kpi_orphaned`, `goal_missing_kpi`, `goal_missing_initiative`, `dangling_initiative_project`, `dangling_initiative_issue`, `dangling_initiative_milestone`
382
463
  - KPI health: `kpi_unrecorded`, `kpi_missing_target`, `kpi_stale`, `kpi_off_pace`
383
- - Initiative health: `initiative_missing_impact`, `initiative_missing_execution`, `initiative_stalled`
464
+ - Initiative health: `initiative_missing_impact`, `initiative_missing_execution`, `initiative_stalled`, `initiative_target_missing_execution`, `initiative_target_overdue`, `initiative_target_blocked`
384
465
  - Execution: `issue_blocked`, `issue_overdue`, `milestone_overdue`
385
466
 
386
467
  ## Analytics Response
@@ -403,6 +484,7 @@ Each finding carries whichever entity ids apply: `goal_id`, `kpi_id`, `initiativ
403
484
  | Task | `status` | `backlog`, `todo`, `in_progress`, `done`, `cancelled` (custom per project via board-columns) |
404
485
  | Board column | `description` | Optional stage criteria or agent guidance |
405
486
  | Task | `priority` | `0` (urgent), `1` (high), `2` (medium), `3` (low) |
487
+ | Task update request | `comment_body` | Optional Markdown/plain text or rich-text HTML comment body created with the issue update; stored and returned as sanitized HTML |
406
488
  | Task | `recurrenceType` | `daily`, `weekly`, `monthly`, `yearly` |
407
489
  | Goal | `status` | `active`, `achieved`, `missed`, `paused`, `cancelled` |
408
490
  | KPI | `unit` | `count`, `percentage`, `currency`, `duration`, `ratio`, `custom` |
@@ -417,7 +499,7 @@ Each finding carries whichever entity ids apply: `goal_id`, `kpi_id`, `initiativ
417
499
  | Member | `role` | `owner`, `admin`, `member`, `guest` |
418
500
  | Project member | `accessLevel` | `view`, `edit`, `admin` |
419
501
  | Automation | `trigger_event` | `issue.created`, `issue.status_changed`, `issue.assigned`, `issue.priority_changed` |
420
- | Heartbeat signal | `type` | `kpi_off_pace`, `kpi_stale`, `issue_stale`, `issue_blocked`, `milestone_overdue`, `initiative_stalled`, `webhook_failing` |
502
+ | Heartbeat signal | `type` | `kpi_off_pace`, `kpi_stale`, `issue_stale`, `issue_blocked`, `milestone_overdue`, `initiative_stalled`, `initiative_target_due_soon`, `initiative_target_overdue`, `initiative_target_blocked`, `webhook_failing` |
421
503
  | Heartbeat signal | `severity` | `info`, `warning`, `critical` |
422
504
  | Custom view | `display_mode` | `board`, `list` |
423
505
 
@@ -430,7 +512,7 @@ REST list responses use resource-specific keys by default. Main list endpoints s
430
512
  ## Notes
431
513
 
432
514
  - All timestamps are ISO 8601 in UTC
433
- - Description and comment fields support Markdown
515
+ - Descriptions support Markdown; comment bodies accept Markdown/plain text or rich-text HTML and are stored as sanitized HTML
434
516
  - Board columns (statuses) are customizable per project -- query `/board-columns` for available statuses and optional descriptions
435
517
  - Default statuses for new projects: `backlog`, `todo`, `in_progress`, `done`
436
518
  - `cancelled` is always valid but not shown on the board