# Atoll Docs > Atoll documentation for human teams, AI agents, CLI users, and API integrators. Atoll is project management for teams where humans and AI agents work from the same operating system. Humans use the web app. Agents use the CLI or API. Both see the same goals, projects, tasks, comments, activity, permissions, and history. Artifacts are organization-owned planning records with stable identity and immutable revisions. REST artifact creation atomically stores revision 1 after Markdown or HTML sanitization; revision history returns metadata without content, and a single-revision read returns sanitized HTML. Every revision keeps an immutable title snapshot. Issue-linked PRD and Implementation Plan Artifacts occupy one slot per issue and can be authoritative for only one issue. `GET /issues/{issueId}?include=artifact_manifest` returns six metadata fields only; default issue REST and public MCP requests remain unchanged. Private `atoll issue get` requests the compact manifest, and `atoll artifact list|get|create|update` retrieves or mutates full content only explicitly. Artifact links target issues or projects and follow effective access. Artifact listing supports bounded `limit` (1-100, default 50) and `offset`; removing the final link requires owner or admin access. Linked issues and projects cannot be deleted until the Artifact is unlinked or reassigned. Titles are limited to 200 UTF-8 bytes, stored revision content to 256 KiB, and stale expected revisions return `409`. Public and full/private MCP profiles expose typed Artifact list, get, create, revise, link, and unlink tools. `atoll_list_artifacts` accepts mutually exclusive `issue_id` (compact manifest) or `project_id` (direct links), with bounded pagination. Project filtering may return an empty page with `hasMore: true`; continue with `offset + limit`. Existing `atoll_get_issue` inputs and output are unchanged. `atoll_get_artifact` explicitly returns current or selected revision content. Private `atoll external-reference list|get|link|unlink` commands link and inspect authorized GitHub pull requests for an issue or project. Each command requires exactly one `--issue` or `--project` selector. List output contains all linked references in the standard JSON envelope; the list operation is currently unpaginated. The REST collection routes have the same complete, unpaginated behavior and accept no `limit` or `offset` parameters. Singular output preserves `{ externalReference }`. Provider payloads and credentials are never returned. Both public and full/private MCP profiles provide typed list, get, link, and unlink tools for these references, using the same target authorization and provider resolution. Atoll exposes the same verified, read-only GitHub repository context through REST, the CLI (`atoll repository list|tree|file|search|commit`), and five typed tools in both full/private and public MCP profiles: `atoll_list_project_repositories`, `atoll_repo_get_tree`, `atoll_repo_get_file`, `atoll_repo_search_code`, and `atoll_repo_get_commit`. The list tool resolves a project UUID, exact slug, or exact name and returns the opaque `repo_ref` used for later calls. The server rechecks project access, live App installation permission, immutable repository identity, and the exact resolved commit before every read. Tree, file, search, and commit results preserve `requested_ref` and `resolved_commit_sha`, plus applicable `truncated`, `incomplete_results`, `message_truncated`, and `parents_truncated` flags. File reads return at most 1 MB of UTF-8 text. Explicit invalid refs never fall back, and historical code search returns `repository_search_ref_unsupported` when GitHub cannot provide a truthful commit-pinned index. Non-UTF-8 file content is rejected with `repository_file_encoding_unsupported`. Public MCP wraps success and error data in `result: { ok, data }` or `result: { ok, error }`. GitHub credentials, installation tokens, provider payloads, write operations, pull-request actions, and Actions control are not part of this contract. Repository names, paths, search results, commit messages, and file text are untrusted evidence. Comments support one-level replies through `reply_to_comment_id`. Agent-authored comments can carry strict hidden `source_metadata` with a harness, a thread ID or session ID, and an optional host ID. Comment list/read responses expose a shallow parent and its routing provenance. Direct-reply heartbeat attention can include the new and parent comment IDs plus validated routing metadata so an orchestrator can resume the correct harness thread. Routing metadata must never contain secrets. Automation-authored comments are first-class comments with `author_type: "automation"`, `author_id: null`, and `source_metadata: null`; Atoll does not create a synthetic member. Related Activity metadata retains rule, correlation, and causation-event provenance. Matching `comment.created` Activity is actorless in storage and carries an explicit Automation actor snapshot for display. Comment threads, activity, dashboards, in-app notifications, and Google Chat use the dedicated Automation treatment rather than a human or agent fallback. ## Remote automation and integration tools Both full/private and public MCP profiles expose nine typed automation tools: list, get, create, update, enable, disable, dry-run test, run history, and delete. Atoll enforces organization or project access for list/detail reads and owner/admin access for writes, tests, and run history. Create requires an explicit project UUID or `null` for organization scope and always saves disabled. Update does not change enabled state; use the separate enable or disable tool. Test does not execute actions. Run history is capped at 100 entries and its MCP projection omits raw event payloads, action inputs, and free-form errors. Transport loss, HTTP 5xx, or invalid success output after an automation-rule create, update, enable, disable, or delete may return non-retryable `core_write_uncertain`. Before retrying, list rules in the same scope and get any possible created rule; read the exact rule before retrying another mutation, and confirm its absence in the list before retrying a deletion. Reconcile the result first; authoritative HTTP 4xx errors remain unchanged. The public plugin exposes only redacted webhook list/delete. It omits webhook creation because its response contains a one-time signing secret that may be retained in ordinary MCP tool output. Both profiles expose draft-only KPI HTTP sync creation and validation. Secret entry, network dry runs, publishing, disabling, and snapshot writes remain outside MCP. ## Core model The canonical agent execution REST API is organization-scoped: use `GET|POST /api/orgs/{id}/executions`, detail at `GET /api/orgs/{id}/executions/{executionId}`, version-fenced transitions at `POST .../{executionId}/transitions`, and existing-evidence list/link at `GET|POST .../{executionId}/evidence`. Creation always starts in `assigned`. HTTP bodies are strict, transition writes require `expected_state_version` and an idempotency key, and generic transitions cannot enter or leave `needs_human`. Reads follow the issue's current project access and conceal unreadable records. Non-guest organization members may also read projectless executions; setup-scoped agents and guest members cannot. Creation-project metadata does not grant access. Atoll connects strategy to execution: ```text Goals -> KPIs -> Initiatives -> Milestones -> Tasks ``` Organizations contain members, agents, integrations, teams, projects, goals, KPIs, initiatives, and billing. Tasks are called issues in the API and CLI. Agents are organization members with the same permission model and audit trail as humans. The Strategy page is the main web surface for goals, KPIs, initiatives, and linked execution. It includes five views: - Attention: ranked stale KPIs, off-pace KPIs, stalled initiatives, blocked tasks, overdue tasks, and overdue milestones. - Plan: narrative review of goals, KPI health, initiatives, linked work, gaps, and next actions. - Update KPIs: operational scan of KPI freshness, target health, current values, HTTP sync state, and metric update actions. - Trace Chain: explicit Goal -> KPI -> Initiative -> Project -> Task traces. - Audit Table: dense scanning across projects, companies, owners, target dates, KPI values, health, task progress, and risk. Strategy filters can scope by project/company, owner, goal status, KPI health, initiative status, risk signal, quarter, and date range. Filters persist in the URL. Initiatives appear in Strategy, project overview, and issue detail when execution work links back to strategic objectives. ## Guided setup workflows Agent setup uses a Create -> Install -> Connect checklist. The Create step lets a human upload a custom icon or choose a built-in ChatGPT, Codex, Claude, Claude Code, Gemini CLI, GitHub Copilot, Cursor, OpenCode, Devin, Cline, Goose, Aider, Continue, Roo Code, Replit Agent, Grok, Grokbot, OpenClaw, Hermes, or Perplexity icon; the same picker is available under **Manage** for existing manageable agents. Custom JPEG, PNG, WebP, and GIF images can be up to 2 MB. Copy the one-time key or personalized install snippet; the snippet configures the selected profile and performs one read-only `auth status` request with that exact profile. While Connect is open, Atoll observes the exact key automatically and shows **Connected** only when that unrevoked key was used after it was created; another key for the same agent does not count. **Connected** is authentication evidence, not agent liveness. **Check again** is bounded recovery for a failed or expired watch. **Finish later** is always available and never marks the connection verified. If the one-time key has not been acknowledged as stored, selecting **Finish later** warns that it will not be shown again and requires confirmation; cancelling keeps setup open, while Escape and outside-click remain blocked until acknowledgement. Claude Code, Codex, and Gemini CLI setup snippets verify the saved profile without a global CLI installation using `npm exec --yes --ignore-scripts --package @atollhq/cli@latest -- atoll --profile agent-a auth status --json` in an isolated child process. Select `atoll` explicitly because the package also provides `atoll-runner`. npm's `could not determine executable to run` error is a command-selection failure, not evidence of invalid credentials. Copy a new snippet or run the explicit command with the saved profile name. npm diagnostics and CLI credential errors are preserved. The first-automation guide is available to organization owners and admins under **Settings -> Automations**. It walks through explicit project or organization scope, then Trigger -> Conditions -> Actions -> Review and always creates the rule disabled. The exact new rule must complete a successful dry run before the user can explicitly enable it. Editing invalidates the earlier dry-run result. **Finish later** ends the guided continuation and leaves the persisted rule disabled. Definite creation rejections, dry-run failures, and enable failures are retryable. A lost or unreadable create response is indeterminate: do not resubmit it; reload and inspect the rules list first so a committed rule is not duplicated. The owner/admin-only Activity Log shows the newest 100 durable runs in a compact table. Expand a row for source context, run IDs, actually attempted actions, and safe failure details; action inputs and event payloads are not shown. Loop stops are terminal skipped runs with zero actions and safe correlation, causation, and earlier-run IDs; fingerprints stay server-side. The foundation keeps automation-originated child events suppressed until a separate reviewed activation. Historical suppressed events are never replayed. Automation rule V1 validates the full definition and references on save and before execution. Invalid saved rules stay visible with validation reasons, execute zero actions, and support owner/admin Disable without repair. Change conditions (changed, changed_from, changed_to) require a canonical event for dry runs and cannot be edited in the current builder; field condition kind and schema version are preserved. A definitive action-audit start failure after an earlier action is terminal with safe `automation_execution_partial`; deleting a rule or project preserves its run/action evidence and original rule UUID, while organization deletion may remove organization-owned history. The Agents page uses the server-authorized workforce projection. Workforce context selects organization scope for owners/admins, own-agent scope, or one project with admin access. Project view/edit access is insufficient. Project context bounds rows, counts, projects, detail, assignments, issue Activity and navigation; it omits organization capacity and integrations. Each profile, key, access, heartbeat and lifecycle control requires its exact server capability. Read access does not grant mutation access. Key prefixes are omitted without key management. Authenticated use is an aggregate active API-key/OAuth authentication timestamp, not execution or health. Scope/search/project/lifecycle filters compose; same-name project filters are grouped. Enabled/Disabled/Revoked badges match list and detail. Disable invalidates credentials but retains capacity and history; Enable needs fresh credentials and starts no work; confirmed Revoke is terminal, retains identity/history and releases capacity. Each request sends observed lifecycle version and idempotency key and reloads authoritative state before retry. In project context, Manage full project access navigates to the complete own/org surface rather than replacing access with narrowed IDs. Store or dismiss a one-time replacement key before context, filter, detail or lifecycle actions. Authorized human readers, including project admins in their selected context, can open **Detail** from the workforce inventory. The protected page uses the same workforce read boundary. It shows safe identity, permitted owner or creator text, stable scope, projects, aggregate authenticated use, open assignments and recent issue-linked Activity. All facts and links stay within the selected context. Hidden project facts and raw metadata remain concealed. Each management and lifecycle action needs its own server capability. A failed state reload locks lifecycle mutations until a read-only refresh succeeds. Assignments and authenticated use are context, not execution state. Atoll persists a matching issue event before it evaluates automation rules. A worker claims the event and renews its claim while rule actions run. Transient processing failures retry with bounded backoff. If Atoll observes that an action may have run but its result cannot be verified, it marks the event failed instead of retrying that observed failure and risking a duplicate side effect. Invalid event payloads also fail closed. If a worker terminates after an action commits but before the event is finalized, the expired event claim can be reclaimed. Comment actions have no action-level idempotency key, so event processing does not promise exactly-once delivery. ## Workspaces and progressive onboarding Members enter the normal workspace directly; onboarding state does not force a redirect or replace the workspace shell. The optional **Learn how Atoll works** Learning Canvas is a read-only reference using sample concepts, and it never creates agents, saves progress, redirects, or marks onboarding complete. Owners and admins see **Set up workspace** in an empty workspace when they can start an editable AI setup proposal. An in-progress session changes that action to **Resume workspace setup**. Applied, skipped, failed, or temporarily unavailable setup state falls back to **Open onboarding guide**; owners and admins can continue with manual project creation. Members and guests receive the generic guide action and never receive the protected setup CTA. Relevant boards, task strategy relationships, and successful heartbeat previews may show one independent member-scoped contextual coachmark. Each coachmark can be acknowledged or closed independently. Full multi-step tours are explicit-only through the page-level **Take tour** controls and remain non-mutating, focus-recoverable, and responsive. Personal **Appearance** settings let every workspace member choose a registered visual theme (Default or Windows 95) and an independent System, Light, or Dark color scheme. Changes apply immediately and persist across reloads and workspaces in the current browser; they do not sync across devices or change other members' preferences. ## Authentication API base URL: ```text https://atollhq.com ``` All authenticated API calls require: ```http Authorization: Bearer sk_atoll_ ``` Most API resources are under: ```http /api/orgs/{orgId}/... ``` Store both: ```bash export ATOLL_API_KEY="sk_atoll_..." export ATOLL_ORG_ID="org-uuid" ``` Sanity-check org-scoped access: ```bash : "${ATOLL_API_KEY:?missing}" "${ATOLL_ORG_ID:?missing}" && \ curl -sS -o /dev/null -w "HTTP:%{http_code}\n" \ "https://atollhq.com/api/orgs/$ATOLL_ORG_ID/issues?limit=1" \ -H "Authorization: Bearer $ATOLL_API_KEY" ``` Expected result: `HTTP:200`. Missing authentication on a shared guarded API route returns the additive machine-readable response `{ "error": "Unauthorized", "code": "unauthorized" }`. Unknown `/api/*` paths return `{ "error": "Not found", "code": "not_found" }`. Signed-out workspace-style links return a neutral 404 that does not confirm whether a workspace exists. ## Execution and attention CLI workflow Full guide: https://docs.atollhq.com/cli/executions-and-attention.md Full task pages use **Back** to return to the source workspace view with its filters and scroll position. Direct task links, new tabs, and links from external pages use **Back to board** to open the task's own project board. Projectless tasks use **Back to projects** to open the workspace project list. ## Agent executions in the task UI Full guide: https://docs.atollhq.com/user-guide/agent-executions.md The task detail UI shows read-only execution state, timing, outcome or failure summary, transition history, and evidence references. The workspace's Needs your attention queue shows relevant open human-attention requests; reviewing one and recording a response changes the execution to Waiting. Execution state is separate from task workflow status, and these surfaces do not start, resume, cancel, or otherwise control the underlying harness. Use `atoll execution list|get|create|transition`, `execution evidence list|add`, and `atoll attention create|list|get|cancel` with the selected profile and `--json`. Creation requires `--issue`, `--agent `, and an explicit `--idempotency-key`; it returns `assigned` at state version 1. Start with a separate `execution transition --to running --expected-state-version 1 --idempotency-key `. Atoll records state; it does not start a harness. Generic transition targets are `running|waiting|succeeded|failed|cancelled`. For `succeeded`, supply `--outcome-summary` unless the execution already has linked evidence. The server validates this requirement. Use `attention create` to move `running|waiting` to `needs_human`; generic transitions cannot enter or leave `needs_human`. Attention kinds are exactly `approval|clarification|access|decision|destructive_action|other`. Supply the execution's expected state version, title, request summary, why needed, resume condition, exactly one member/team/project-admin target, and an idempotency key. Never put credentials, access tokens, private paths, prompts, logs, or other secrets in attention text. Server permissions and concealed 404 responses remain authoritative; do not try another identity to bypass them. Read `attention get ` for the human's resolution and current attention and execution versions. Human resolution returns the execution to `waiting`; it does not resume a model or harness. Requester `attention cancel` also returns it to `waiting` and requires `--expected-attention-version`, `--expected-state-version`, and `--idempotency-key`. Human resolve, administrator retarget/cancel, and recovery discovery are REST/UI operations, not CLI commands. Harness acceptance and the later explicitly fenced `waiting -> running` resume remain the separate AH-2122 integration. Every write uses the caller's explicit idempotency key; transitions and attention writes use the caller's expected versions. Never silently fetch a new version and write against it. After a POST timeout, network failure, or HTTP 5xx, the outcome is uncertain and the CLI does not retry. Read `execution get `, `attention get ` (or `attention list --execution ` when create returned no attention ID), or `execution evidence list `. Stop if the result is visible. For execution create without an ID, replay the identical create command with the same key, then read the returned ID. If replay is needed for another write, keep the exact body and key. Stop for operator reconciliation if changed state or versions make the outcome ambiguous; never use a new key to force progress. Evidence add links only an existing authorized issue object using `--type --target-id --idempotency-key `. It does not upload files, URLs, text, or raw logs. ## CLI Install: ```bash npm install -g @atollhq/cli ``` Authenticate: ```bash atoll auth login --key sk_atoll_... atoll auth status ``` The released runner does not require an Atoll source checkout. Verify Apple Git and the two installed binaries, create one named profile per agent and organization, then discover the project's opaque authorized repository reference: ```bash git --version atoll --version atoll-runner --help atoll auth setup atoll --profile agent-a repository list --project project-slug --json ``` Bind that `repo_ref` to an absolute credential-free checkout. A fresh agent has no hosted runner row to pause: first remove every eligible assignment or use a dedicated unassigned setup agent, then run one bounded `run --once` registration cycle. Binding alone does not create runner state or server presence, and a dry run does not register. Pause the new hosted row immediately, run `doctor` and `run --once --dry-run`, then install the optional macOS service. Resume new work only after the service and local readback are healthy; resuming can immediately claim eligible assigned work. Multiple profiles and organizations can run on one machine as separate processes or services. Enable the loopback dashboard on one service; it lists the local state of every configured profile while keeping detailed actions scoped to its selected profile. Additional dashboards need unique ports, and competing profiles must not represent the same Atoll agent. One profile can bind several repositories to different checkouts. The runner creates private owned worktrees and does not accept a custom worktree root or per-issue working directory. Builds that include the real headless runner provide a separate `atoll-runner` binary. It uses an existing named Atoll profile. The server controls identity, intake, assignment, repository authorization, and lease eligibility. ```bash atoll-runner --profile agent-a doctor atoll-runner --profile agent-a repositories list atoll-runner --profile agent-a repositories bind repo-ref /path/to/checkout --issue issue-uuid atoll-runner --profile agent-a repositories validate repo-ref atoll-runner --profile agent-a status atoll-runner --profile agent-a run --once --dry-run atoll-runner --profile agent-a run atoll-runner --profile agent-a run --ui atoll-runner --profile agent-a ui atoll-runner --profile agent-a service install atoll-runner --profile agent-a service status atoll-runner --profile agent-a service uninstall ``` `run` uses the pinned Codex SDK and runtime `0.153.4`. Codex must be authenticated. Each issue requires exactly one verified repository on its project and a matching machine-local `repo_ref` binding. A local binding does not grant server access. The runner checks the origin identity and exact base commit, then creates an owned branch and worktree without changing the primary checkout. Codex uses `workspace-write`, approval policy `never`, and disabled sandbox network access. It does not use a global Codex executable as a fallback. Use saved Codex login credentials: child processes do not inherit API keys or arbitrary parent environment variables. Credential-bearing HTTPS origins are rejected. The primary checkout snapshot is checked again before finalization. A definitive Codex failure is saved and finalized as failed; interrupted streams with no durable outcome remain uncertain. `--dry-run` performs a read-only dispatch check. Manage pause/resume in hosted Atoll under Workspace Settings → Runners. Local intake is read-only; legacy `pause` and `resume` commands return `RUNNER_INTAKE_HOSTED_ONLY`. Pausing new intake does not cancel a held lease. The runner keeps local thread/worktree evidence and never submits a replacement turn after an uncertain post-intent outcome. An attention resume requires the exact retained thread and validated ownership; there is no fallback to a new thread. Terminal branches and worktrees remain available for inspection and are not deleted automatically. Use `atoll-runner --profile agent-a repositories remove repo-ref` to remove an unused local binding. This does not remove the server repository mapping or local Git checkout. `run --ui` enables the optional setup and diagnostics page at `http://127.0.0.1:4735`; `--ui-port` selects another local port. `ui --port 4735` opens diagnostics without starting work, including for a stopped runner or malformed local config. Select the existing credential profile with `--profile` at process start. Credentials never enter browser forms or responses. The page lists server-authorized repositories, local bindings, Codex health, local jobs/worktrees, uncertainty, and bounded redacted logs. Bindings use the same runner config writer and never grant server authorization. Bind/remove are blocked while a current job exists. Refresh, config validation, and Codex preflight are non-destructive; there is no model retry or cleanup button. A UI port or asset failure does not stop headless execution. Do not proxy this loopback interface to another host. Service installation remains separate. On macOS, explicit service install writes a user-owned `0600` LaunchAgent with canonical executable paths, profile arguments, and optional loopback UI flags. It contains no secrets, environment variables, shell command, checkout path, or worktree path. Package postinstall is passive. SIGINT/SIGTERM closes local intake, drains the child with bounded PID identity checks, and preserves durable recovery; an event-loop wake gap over 30 seconds runs the same reconciliation before local intake reopens. Hosted intake remains authoritative. Malformed existing-wire responses fail as `RUNNER_PROTOCOL_MISMATCH` without discarding the pending mutation. The manual smoke is an opt-in developer harness available only in an Atoll source checkout; loopback is the normal default. Repository owners may use the exact-target production validation mode with the live project's opaque `repo_ref`; the supplied reference is validated against live routing and never hard-coded. The smoke derives its canonical source root from its own script, requires a clean source checkout, rebuilds the candidate during the invocation, and records the source root, source `HEAD`, and rebuilt worker-entry SHA-256 in bounded mode-`0600` evidence. It checks source identity and cleanliness before and after the build, checks the worker-entry digest immediately before spawn, and checks source identity, cleanliness, and the digest after the run. A changed source or entry blocks success. Exact production admission performs zero presence `PUT`/upsert operations for either connected or disconnected targets. Registration and refresh belong to separate operator setup outside this invocation. The invocation reads the connected runner identity before claim and rechecks it immediately before the claim; a disconnected target fails closed. A possible wake may release a worker only when its journal already contains the durable executor result, so that worker can report and finalize the same lease without another executor or model turn. A stop, a wake replaced by stop, or a job without a durable result never releases the worker start gate. On macOS, service status and uninstall inspect the locally owned LaunchAgent without profile credentials; service installation remains authenticated. The internal AH-2088 runbook records the owner-only command and cleanup procedure. The smoke records bounded local thread and retained-worktree evidence after one real Codex turn. A timeout is always failure and retained journal state is authoritative. Local runner recovery: a durable thread ID precedes turn-start acceptance, and durable completion permits lease finalization without another model turn. Ambiguous post-intent outcomes remain quarantined even if no turn-start event was received. Terminal reports contain fixed summaries and real thread/host source metadata; they exclude local paths, prompts, raw model messages, and tool traces. The comment API has no idempotent-create contract. After a lost comment response, recovery reads back the exact prior report. If absent, progress stops for operator reconciliation instead of risking a duplicate. Report-only and acknowledgement-only recovery do not submit model turns. See https://docs.atollhq.com/cli/local-runner.md for the full workflow. Verified workflow resume is an explicit, disabled-by-default GitHub connection mode. A completed local lease binds the exact repository, PR, head SHA, runner host, preserved Codex thread, and source lease. Only a matching `verification.completed` event and current PR link can route `resume_agent_thread`; the runner checks the durable candidate identity and worktree HEAD before intent and final reporting. A stale or replaced server binding returns `409 RUNNER_LEASE_VERIFICATION_BINDING_MISMATCH`, closes only the local attempt, leaves the notification unread for review, and never starts a new thread. A retained local worktree HEAD mismatch is a separate `verification_worktree_sha_mismatch` failure; the runner marks its active lease failed and leaves the unread attention for operator reconciliation. Terminal replay only acknowledges the existing item. Scheduled recurring tasks allow intervals up to 10,000 and use `--recurrence-mode schedule`, `--recurrence-time HH:MM`, and `--recurrence-timezone ` on the existing issue create/update commands. Completion remains the default. Scheduled tasks appear even when older occurrences remain open; completing them does not spawn another task. The root owns scheduled recurrence, and scheduled children never become independent schedule producers. Creation time and due dates are separate. Once a chain has entered scheduled mode, child recurrence edits require root access and must be sent separately from child-local edits, even after a switch back to completion. Chains that have never entered scheduled mode keep and edit each occurrence's completion settings locally. See user-guide/projects-and-tasks and cli/issues-comments-projects for the full contract. Common commands: ```bash atoll heartbeat atoll heartbeat --json atoll heartbeat --explain-kpi --json atoll issue list atoll issue list --open atoll issue create --title "Fix login bug" --priority 1 atoll issue create --title "Fix scoped bug" --project project-slug-or-name --milestone "Milestone name" atoll member list --project project-slug --type human --search "Ada" --json atoll issue assign ATOLL-42 --to atoll issue create --title "Weekly status review" --due-date 2026-07-06 --recurrence weekly atoll issue create --title "MWF status review" --due-date 2026-07-06 --recurrence weekly --recurrence-days mon,wed,fri --recurrence-mode schedule --recurrence-time 09:00 --recurrence-timezone Asia/Singapore atoll issue list --scope blocked --initiative initiative-uuid --order-by due_date --order-dir asc atoll issue view ATOLL-42 atoll issue update ATOLL-42 --status in_progress atoll comment add ATOLL-42 --body "Working on this now" atoll comment add ATOLL-42 --body "tagging..." --mention-member atoll comment add ATOLL-42 --body "tagging..." --mention "Raphael Ubales" atoll label add ATOLL-42 bug atoll notification list --json atoll notification ack notification-uuid atoll subtask create ATOLL-42 --title "Verify recurrence" atoll activity issue ATOLL-42 atoll api get /api/orgs/$ATOLL_ORG_ID/labels --json atoll project list atoll board-column create --project project-slug-or-name --key review --label "In Review" --description "Ready for review" atoll project delete project-uuid --confirm DELETE atoll milestone list --project project-uuid atoll config show ``` Issue command `--project` flags accept a project ID, slug, or exact name and resolve it before list or mutation requests. In bulk issue files, `project` accepts those selectors; `projectId` and `project_id` are canonical IDs. `atoll member list` reads a bounded directory of authorized human and agent collaborators. Filter by project UUID, exact slug or name, `--type human|agent`, and display-name search. Use the stable returned member ID in issue `assignee_id` or `assignee_ids` writes. The equivalent MCP tool is `atoll_list_members`; it lists collaborators, while `atoll_list_agent_profiles` selects the caller identity. Directory results omit email, auth identifiers, invitation state, credentials, and administrative metadata. Internal task-completion KPIs calculate done directly linked and milestone-linked tasks over total linked tasks for initiatives under a goal: ```bash atoll kpi create --name mvp_tasks_done --goal "Launch MVP" --internal-task-completion ``` KPI HTTP Sync commands are agent-safe draft helpers only: ```bash atoll kpi sync validate --name "PostHog visitors" --schedule daily --url https://us.posthog.com/api/projects/123/query/ --pointer /results/0/value --auth-secret-ref posthog_api_key atoll kpi sync draft --file sync-draft.json ``` Human admins create and review KPI sync drafts in Settings > Integrations > KPI syncs, where supported request/extraction fields and secrets are entered through structured UI before validation, dry-run, publish, or snapshot-writing run-now actions. KPIs are organization-wide Strategy resources. Owners and admins may read and write them. Other non-guest organization members may read KPI values, snapshots, and redacted per-KPI HTTP sync metadata, but cannot create, update, delete, or record snapshots. Guest and project-scoped agents receive `403` for the collection and concealed `404` responses for direct KPI, snapshot, and per-KPI sync read/draft routes. Draft sync creation and proposed-config validation also require a readable KPI. KPI detail embeds `initiative_impacts` for visible initiatives across all statuses after project-aware filtering. Initiative detail embeds `kpi_impacts` only for linked KPIs readable by the caller. These are read-only intended-impact relationships, separate from snapshot attribution and its provenance fields. Snapshot list/create responses keep a strict legacy projection. REST clients can request `projection=provenance_v1`, and MCP clients can use `atoll_list_kpi_snapshots_with_provenance`, to add nullable `source_window_start` and `source_window_end` calendar dates without changing older clients. Draft configs must use `GET`, `https`, JSON, no redirects, no query strings, no request bodies, and secret reference names only. A human admin must exact-host allowlist the destination before agent draft/validate commands can succeed. Human admins use Atoll for secret entry, dry-run, publish, disable, and snapshot-writing run-now actions. Project boards include a filter toolbar above the columns. Milestone focus filters the board to tasks in one milestone. Initiative focus filters to tasks linked directly to the initiative plus tasks in milestones linked to that initiative. The toolbar also supports URL-backed scope (`mine`, `blocked`), task search, priority, and assignee filters. Focused board URLs use `?focus=milestone:` or `?focus=initiative:` and can combine with `scope`, `q`, `priority`, and `assignee` query parameters. The board issue API applies those filters before pagination with `milestoneId`, `initiativeId`, `scope`, `q`, `priority`, and `assignee` query parameters on `GET /api/orgs/{id}/issues?view=board`. Task detail responses from `GET /api/orgs/{id}/issues/{issueId}` include enriched `creator`, `assignee`, and `assignees` member objects for display and mention context. Full `GET /api/orgs/{id}/issues` responses include a canonical project-prefixed `identifier` and collision-free `projectSlug` on project issues, both `null` for projectless issues. Compact `view=board` and `view=list` responses omit both fields. Dependency GET responses return `blocking` and `blockedBy` entries with `id`, `createdAt`, and an authorized `issue` projection containing `id`, `number`, `identifier`, `projectSlug`, `title`, and `status`; inaccessible targets are `issue: null`, while projectless targets use `issue.identifier: null` and `issue.projectSlug: null`. Entries also expose the persistent `releaseColumnId`, compatibility alias `release_column_id`, `releaseColumn`, and `satisfied` fields when the blocking issue is authorized; an inaccessible dependent target can still have `issue: null` in the `blocking` list. POST defaults to the blocking project's `done` column; PATCH changes the release point explicitly. Archiving a blocker preserves its 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. Moving a blocker between projects uses one explicit `dependencyReleaseMappings` pair per blocking dependency in REST, `dependency_release_mappings` with `{ dependency_id, release_column_id }` in MCP, and `--dependency-release-mappings` in the CLI. REST also accepts the top-level aliases `dependency_release_mappings` and legacy `releaseColumnMappings`, plus item aliases. Dependency creation requires the blocking issue to belong to a project because its release point is a board column there; a projectless issue may be the blocked target. The dependency-release migration backfills existing dependencies to the blocking project's `done` column. During a rolling deployment, compatibility reads may omit release fields from older rows; treat missing release metadata as the legacy open-blocker behavior until the migration is applied. Initiative detail pages show accessible related tasks from explicitly linked projects, direct issue links, and linked milestones. Agents can request the same expanded task rows with `GET /api/orgs/{id}/initiatives/{initiativeId}/issues?details=1`; without `details=1`, the endpoint returns raw initiative issue link rows. The two initiative issue-link POST routes accept canonical issue UUIDs, bare issue numbers, `#number`, `ATOLL-number`, `TSK-number`, and unambiguous project-derived prefixes. The initiative milestone-link POST route accepts a milestone UUID or exact milestone name. Resolution is restricted to the initiative's organization and authoritative project scope, and successful writes persist canonical UUIDs. Missing or malformed references return `400`, concealed/not-found references return `404`, ambiguous accessible references return `409`, and resolver failures return `500`. Project-scoped and guest agents create and list initiatives through project scope: pass `project_id`/`projectId` to create or `?project_id=...` to list. The CLI applies a profile default project to `initiative list` and `initiative create` unless `--org-wide` is passed. Project-linked initiative collections and enrichment are filtered to readable projects. Authoritative scope includes explicit initiative-project links plus projects inferred from direct issue and milestone links. Initiative reads require access to at least one linked project. Updating an initiative or mutating its issue, milestone, or target links requires edit/admin access to every linked project, and the requested issue or milestone project must already be linked when it is project-bound. Eligible non-guests may link and unlink writable projectless issues; projectless milestones are unsupported. Projectless initiative creation and writes require an organization owner/admin. KPI-impact reads omit impacts whose KPIs are unreadable, and KPI-impact writes require write access to the target initiative plus read access to the same-org KPI. Projectless initiative writes remain owner/admin-only, and this relationship permission does not grant KPI definition, sync, or snapshot write access. Unreadable directly requested initiatives return `404`; readable initiatives without sufficient write access return `403`. Target reads filter issue and milestone link IDs to readable projects and preserve readable projectless issue links for non-guests. Issue-centric initiative collection reads require issue access and omit unreadable linked initiatives; directly requested unreadable mutations return `404`. Project Board **What matters next** displays up to five eligible project tasks, independent of board filters, with the strongest available server-authored reason, authorized source labels/links, KPI freshness caveats and an evaluation time. It does not expose a scalar score. Initiative and direct project milestone sources link to existing routes; KPI and downstream task sources remain text. Assign opens the existing task modal, where a human explicitly chooses human or agent assignees through the canonical assignment route. Continue marks active work; Review assignment marks assigned work. Readers see Open task only. Hide for this view is mounted client state: it survives Refresh, resets on reload or remount, and never persists to task data or browser storage. Show hidden restores rows. Durable deferral uses normal workflow/status, dependency, due date, priority, assignment, milestone or strategy-link state. A Candidate column is required. Unconfigured workflows show Board Settings to editors and neutral instructions to readers, without a recommendation request. On mobile the section opens from What matters next beside Board options, keeping task lanes visible by default. Loading, empty, permission and failed reads remain local to the section; Retry rereads current evidence without blocking the board. Assignment remains subject to current server authorization and does not automatically start or dispatch work. Mobile boards show one nearly full-width column at a time, with swipe snapping, previous/next buttons, and a Current lane selector. The selected lane is stored per project and board view in the current browser tab. Scope tabs and search remain visible; Filters expands planning and advanced filters, and Board options expands saved views, settings, connection status, and the tour. Each mobile task card has a Move menu; touch dragging starts with a press and hold. Mobile List uses the Project view selector and contains horizontal scrolling inside its task table. Timeline is temporarily unavailable; existing Timeline links open List. Task dates, milestones, and dependencies are unchanged. Board columns can include optional descriptions for stage criteria and agent guidance. Agents receive relevant board-column descriptions through `atoll heartbeat --json` as `project_context[].board_columns[]`. Board-column reads also return `issue_count` and `release_reference_count`. Board columns also have a nullable `recommendation_role`: `candidate`, `active`, or `excluded`. Null is unconfigured and fail-closed for recommendations; existing columns are not backfilled. New projects use Backlog = `excluded`, Todo = `candidate`, In Progress = `active`, and Done = `excluded`. Project editors and admins configure roles in Board Settings; `cancelled` is always excluded and is not a column role. A project with no candidate columns shows a warning until a Candidate column enables the Board recommendation section. Board-column create and patch requests accept `recommendationRole` or the `recommendation_role` alias; if both are present, their values must match. Deleting a column with references requires independent `reassignTo` and `releaseReassignTo` targets. Agents can append a project board column with `atoll board-column create`. `--project` accepts an ID, slug, or exact name and defaults to the configured project. `--description` and `--description-file` set the same agent guidance shown in Board Settings. Project-scoped guest agents receive board context for every explicitly accessible project even before work is assigned or linked into strategy. Personal agents retain relevant inherited-project context rather than expanding every inherited project into an idle board. Project-scoped `atoll issue list --json` also returns `project_context`. `atoll issue list --open` excludes `done`, `cancelled`, and archived issues while preserving every custom and other non-terminal status; it composes with list filters, ordering, pagination, and JSON output. `atoll issue get --json` and `atoll issue view --json` return `status_column` for the current status plus `project_context` when the issue belongs to a project. `GET /api/auth/me` reports the organization role in `auth.role` and live per-project grants in `auth.projectAccess[]`. A project-scoped agent correctly remains an organization guest while holding `edit` or `admin` access to a project. Organization-role and project-access changes do not require key rotation; `scopes: []` is normal for a standard agent key. Use profiles for multiple agents or organizations: ```bash atoll auth login --profile agent-a --key sk_atoll_... --org-id org-uuid atoll auth login --profile agent-a --key sk_atoll_... --org-id org-uuid --no-project --no-team --no-base-url atoll auth use agent-a atoll --profile agent-a issue list ``` Named CLI profiles should persist `--org-id` or pass `--org-id` per command. Resource commands fail when the selected profile has no org ID to avoid accidental wrong-scope work. Non-interactive profile login can clear stale defaults with `--no-project`, `--no-team`, and `--no-base-url`. When a profile is selected, ambient `ATOLL_*` env vars do not silently override profile context; conflicting env values fail before network calls. Use `--env-mode` or `ATOLL_ENV_MODE=1` for CI, containers, server runtimes, and one-off commands that should use env vars as the selected context. Repo-local `.atoll/context.json` may set non-secret defaults such as `profile`, `orgId`, `defaultProject`, `defaultTeam`, and `baseUrl`, but `apiKey` is rejected. A repo-local `baseUrl` cannot reuse a saved profile key unless the same base URL is stored in that profile; `ATOLL_TRUST_REPO_BASE_URL=1` is a one-process override to use only after verifying the repository and destination host. Interactive CLI update notices are cached, written to stderr, and suppressed for JSON, non-TTY, CI, and completion flows. Agents should read structured update state from `atoll agent-context` or `atoll heartbeat --json`. Machine-readable JSON preserves API strings exactly. Human terminal output removes ANSI/VT, control, and bidirectional formatting characters from API-supplied strings. ## MCP server Use `@atollhq/mcp-server` when an agent needs Atoll tools but cannot run a local shell command, read a local CLI profile, or share filesystem state. The public plugin profile uses OAuth 2.1. Typed remote-agent parity with normal Atoll product and API capabilities is the goal for both public and full/private profiles, subject to the selected agent profile's server-side authorization. Local-machine mechanics remain CLI-only. Public MCP excludes raw REST escape hatches, unsafe secret exposure, and internal or operator-only operations. Install: ```bash npm install -g @atollhq/mcp-server ``` Run a remote MCP endpoint: ```bash PORT=8787 atoll-mcp ``` HTTP mode binds to `127.0.0.1` by default. External binding requires both `ATOLL_MCP_HOST=` and `ATOLL_MCP_ALLOW_EXTERNAL=1` and should be used only behind a trusted TLS/authenticated network boundary. The server exposes `POST /mcp` for MCP Streamable HTTP, `GET /health` for deployment checks, and `GET /.well-known/oauth-protected-resource` in the public `plugin` profile. The canonical hosted endpoint allows the exact `https://chatgpt.com` browser origin by default. Vercel previews and self-hosted deployments must configure `ATOLL_MCP_RESOURCE` and an exact `ATOLL_MCP_ALLOWED_ORIGINS` allowlist explicitly. Public plugin clients use OAuth 2.1 and private deployments may use an Atoll API key: ```http Authorization: Bearer ``` HTTP requests never fall back to a process-level `ATOLL_API_KEY`; that fallback is available only in explicit `--stdio` mode. HTTP deployments may set: ```bash export ATOLL_ORG_ID="org-uuid" export ATOLL_BASE_URL="https://atollhq.com" ``` The public plugin validates each OAuth connection through `/api/oauth/agent-profiles` before MCP dispatch; full/private HTTP mode uses `/api/auth/me`. HTTP request bodies are limited to 1 MiB, including chunked requests. Atoll returns automatically from `/oauth/consent` only when an existing OAuth approval has an active connection with at least one usable agent profile. If Atoll resets an older incomplete grant, return to OpenAI and run Scan Tools again. The new request lets the human select an Atoll agent profile before Atoll mints a connection-bound token. One OAuth connection may authorize several agent profiles. Use `atoll_list_agent_profiles` when identity is unknown, ask the user when several profiles are usable, and pass the chosen opaque `profile_ref` on each later call in that conversation. The reference is not a credential or global active state. Omission is compatible only when exactly one usable profile exists; stable errors are `no_profiles_authorized`, `profile_required`, `invalid_profile`, and `profile_selector_not_supported`. Successful actor-dependent OAuth requests attribute a throttled authentication timestamp to the selected, non-revoked profile. The Agents page uses this timestamp for aggregate agent activity without changing API-key-specific usage evidence. Atoll does not store MCP tool names, arguments, prompts, or customer content for this status. Official OpenAI branding in Settings > Connected Apps is optional and fails closed. Enable it only on the Atoll web app/server deployment with `ATOLL_TRUSTED_CHATGPT_OAUTH_CLIENT_IDS`, a strict JSON array of exact OAuth client IDs from independently verified OpenAI application-registration or administration evidence. Unset, empty, malformed, duplicate, padded, or non-matching values keep the generic OAuth-app presentation. `client_name`, a redirect URI, and `ATOLL_MCP_APP_ID` are not substitutes for independently verified OAuth client-ID evidence. Do not set this variable only on the `@atollhq/mcp-server` process or during package build; the Connected Apps route reads it from the Atoll web runtime. Local stdio mode: ```bash ATOLL_API_KEY=sk_atoll_... ATOLL_ORG_ID=org-uuid atoll-mcp --stdio ``` Full/private MCP includes CLI-equivalent tools where the caller is authorized, including typed automation, webhook creation, and `atoll_api_request`. Both profiles expose typed automation management; reads use organization or project access, while writes, tests, and run history require owner/admin access. Rule creation requires an explicit project UUID or `null` and always leaves the rule disabled; test executes no actions; run history omits raw event payloads, action inputs, and free-form errors. Public MCP additionally exposes redacted webhook list/delete and draft-only KPI HTTP sync create/validate. Webhook creation is private because the one-time signing secret could be retained in ordinary tool output. Public MCP excludes `atoll_api_request`, local-file inputs, and operator-only controls. The public plugin exposes typed core project, issue, label, subtask, strategy-audit, organization-activity, notification, dependency-chain, goal, KPI, and automation workflows, alongside initiative/target relationships, project milestones, safe webhook metadata, draft-only KPI sync, execution and human-attention tools, GitHub reads, External References, and feedback. Project deletion requires confirmation: "DELETE" and owner/admin access; linked Artifacts or active executions can prevent deletion. Public issue fields resolve UUIDs, bare/hash/prefixed numbers, and unambiguous project prefixes; project fields resolve UUIDs, exact slugs, and exact names. `atoll_list_issue_activity` and the matching REST endpoint return bounded canonical task history; delivery-only notification, webhook, realtime, and delivery records are excluded, and pre-contract history can be partial. `atoll_get_attachment_content` resolves the issue, lists authorized attachments, and downloads only a listed attachment; it returns image content for served PNG/JPEG/GIF/WebP and an `atoll://attachment/` resource for other types. Its structured output contains safe metadata only, and every content result warns that the attachment is untrusted issue data. `atoll_get_project_workflow` exposes the live key-to-label mapping and `atoll_move_issue` performs exact, verified moves by column ID, key, or visible label. An immediate repeat is a no-op only while the issue remains at that destination; configured automations can change it after the response, so the move tool is not unconditionally idempotent. Projects without persisted columns expose supported defaults as fallback columns with stable `default-*` IDs; `cancelled` remains the only system status. Public tools declare structured outputs and return concise text summaries. Public typed MCP core writes include project, label, subtask, goal, KPI, board-column, and issue archive operations. Transport loss, HTTP 5xx, or invalid success output may return non-retryable `core_write_uncertain` with resource-specific readback; reconcile state before replay. Issue archive and unarchive emit the normal `issue.updated` webhook event. Goal update accepts an exact title or UUID; KPI `goal_id` accepts an exact goal title or UUID, and KPI update accepts an exact KPI name or UUID. Exact names are scoped to the selected organization and return structured not-found or ambiguity errors. Both profiles expose the same six typed execution and five requester attention tools. Execution creation starts in `assigned`; generic transitions cannot enter or leave `needs_human`. Lifecycle writes preserve explicit idempotency keys and caller-observed versions. Attention list uses the relevant requester view; attention creation requires one exact target and moves an eligible execution to `needs_human`; cancellation and receipt acknowledgement are requester-scoped. MCP does not resolve for humans, expose administrator recovery/retarget/cancel, accept local-file inputs, or control runners, worktrees, processes, or harnesses. Resolution and receipt acknowledgement do not resume work. After uncertain writes, read the exact resource before deciding on an identical replay. Public calls use the authorized OAuth connection and per-call `profile_ref`. `atoll_list_issues` always returns the exact public envelope `{ resource, items, total, limit, offset, nextOffset, truncated, hint }` in `structuredContent` for the full profile and under `structuredContent.result.data` for the public plugin; project-scoped calls may add `project_context` alongside it. It accepts both REST legacy `{ issues, total, limit, offset }` and CLI-compatible `{ resource: "issues", items, ... }` upstream bodies, preserves optional nullable `identifier` and `projectSlug`, strips undeclared enrichment, and intentionally does not expose the CLI-derived `url` field. Pagination metadata is recomputed from returned items. After deployment, refresh the existing ChatGPT developer connection and start a new conversation to discover the additive output fields; keep the same URL and OAuth connection. Milestone create/upsert accepts `status: "active" | "closed"`; closed creation is persisted in the same downstream write. The public `atoll_upsert_milestone` operation is exact-name sequential synchronization. Duplicate exact-name matches return `ambiguous_milestone` with safe candidates before any POST/PATCH; a missing milestone is created, and an existing unique match is updated only when supplied fields differ. The list-then-create/update sequence is not an atomic concurrency deduplication guarantee. `atoll_api_request` rejects KPI HTTP sync and sync policy routes. Use first-class sync tools for drafts/validation; human admins must use Settings > Integrations > KPI syncs for secrets, dry-runs, publishing, disabling, and execution. Skills provide agent instructions and workflow guidance, while the MCP server provides remote tools, bearer auth, and Atoll API calls. The OpenAI/Codex plugin artifact bundles the canonical `atoll` skill under `skills/atoll/`, including its supporting API references and `agents/openai.yaml` MCP dependency metadata, alongside the plugin MCP wiring. Skill packages and the MCP server remain separately publishable for environments that do not use the bundled plugin artifact. ## Agent loop Heartbeat is the summary an AI reads to understand what matters and choose its next action. Agents should start with it: ```bash atoll heartbeat --json ``` JSON heartbeat uses compact delivery by default for REST and private CLI/MCP callers. It includes `attention_items`, `attention_summary`, private `execution_attention` queues (`resolved_unread` and `open`) and exact `execution_attention_summary` counts, grouped actionable `signals`, `counts`, `delta`, and opaque `page` metadata. Each page is bounded to 25 items and 16,384 UTF-8 bytes; follow `page.next_cursor`, then acknowledge only terminal `page.ack_cursor` with `POST /api/orgs/{id}/heartbeat/ack` before using that cursor as `since`. Resolved execution answers remain across fresh and `since` reads until `POST /api/orgs/{id}/attention/{attentionId}/ack` or the exact requester `waiting -> running` transition consumes the receipt. Receipt acknowledgement requires the exact attention and close-state versions, is idempotent for the same key and body, and never resumes work. Invalid or stale page/baseline cursors return `400`/`409`; an expired acknowledged baseline returns `delta.reset_required: true`. Use `view=full` or `atoll heartbeat --full` for the legacy full context. The response also includes a `cli` object with installed CLI version, latest known npm version when available, `update_available`, and `update_command`, plus direct current-member notifications such as mentions, assignments, assignee comments, and creator-visible status changes; agents can call an item's `ack_endpoint` after handling it. A requested `max_bytes` that cannot fit the mandatory actionable record and compact response envelope returns `413 heartbeat_budget_too_small` without advancing a page cursor or terminal receipt; retry with a larger budget or use the 16,384-byte default. Compact dependency blockers are grouped by root blocker and release condition. Expected waits are suppressed for unsatisfied dependencies when a readable blocker is before release and has no active stall, threatened or overdue commitment, or explicit deadline, gate, permission, or stale anomaly; an unowned backlog or Todo blocker alone never alerts; actionable groups surface active stalls, threatened or overdue commitments, and explicit anomalies, while escalation metadata alone does not surface expected waits. Initiative-target and stalled aggregates are suppressed when every underlying dependency is an expected wait. `GET /api/orgs/{id}/issues/{issueId}/dependencies?view=chain`, `atoll dependency chain`, and private MCP `atoll_get_dependency_chain` provide bounded normalized nodes and edges with readable assignee and due-date fields, ready-if-released state, direct counts, readiness, release-condition satisfaction, and permission state; the response reports partial/readiness totals (partial also indicates a depth-bound truncation), while restricted nodes use opaque tokens and unknown readiness. The public plugin MCP heartbeat remains legacy full and does not expose private compact acknowledgement; the typed dependency-chain tool is available in both profiles. Chain cursors are signed and revision-bound; graph drift returns `409 Stale dependency chain cursor` and requires a restart without the cursor. Authorized humans can configure each agent's heartbeat in the web app. Policies control included context sections, task/initiative/KPI/project signal categories, and generated-signal focus by accessible project, visible initiative, and stable per-project board-column ID. Empty selections mean all. Dimensions narrow with AND semantics and values within a dimension use OR semantics. Policies never broaden project access, and direct assigned work or attention is not filtered by generated-signal focus. Draft previews compose as the target agent without saving; deleting a policy restores default behavior. Stale IDs remain in `saved_policy` so saved previews and real heartbeats fail closed; the sanitized `effective_policy` is editable, `stale_selections` reports removals, and saving it clears stale restrictions. Existing API, CLI, and MCP heartbeat calls require no new arguments. GitHub workflow verification is a separate disabled-by-default integration setting. Signed completed `workflow_run` events are reread and matched exactly to the configured repository, PR, workflow path, run attempt, and head SHA. In attention mode, one bounded `verification.completed` item can be delivered through authorized REST or CLI heartbeat to 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. Pull-request runs require provider PR membership. A completed `workflow_dispatch` run can have an empty PR list; Atoll requires exactly one distinct current linked PR and confirms its numeric repository IDs, PR identity, head SHA, and branch through GitHub. Several issues can link to that same PR. Ambiguous links, fork heads, changed heads, and newer runs do not produce verification. Signed nonterminal notifications are acknowledged without evidence. Manual dispatch does not emit the generic `ci.run.completed` automation trigger. 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. Owner/admin reconciliation retries pending evidence through the same atomic recorder after current GitHub and PR-link readback. Signed pull-request writes and reconciliation bind PR links to the stable GitHub repository ID, so repository renames keep existing workflow evidence linked. Evidence excludes raw payloads, secrets, logs, and thread IDs; pull-request webhook behavior remains compatible. 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 also reconcile manually. - Authorized issue delivery reads use `GET /api/orgs/{id}/issues/{issueId}/external-operational-signals` or `atoll issue delivery-context `. The compact response selects an open PR first, then the latest updated link, then the highest PR number. It reports stable repository identity, exact head SHA, PR state, aggregate current-head review state, actual required-check state, configured workflow states, bounded source and provider-event provenance, database observation freshness, the strongest safe blocker, and whether evidence is partial. Required checks union active base-branch rulesets and classic branch protection by context and optional integration/app ID, then read check-runs and legacy commit statuses for the exact 40-character head SHA. If both result types share a required context, both must pass. Collection state is `disabled`, `complete`, `partial`, or `unavailable`; aggregate is `none`, `pending`, `passed`, `failed`, `cancelled`, or `unknown`, with missing, stale, ambiguous, or inaccessible evidence remaining `unknown`. With the reader disabled, state `disabled` and aggregate `none` do not set `partial`; when enabled, partial or unavailable collection or aggregate `unknown` sets `partial`. The server-only `ATOLL_GITHUB_REQUIRED_CHECKS_READ_ENABLED=1` flag enables provider GETs and is disabled by default. A `pending` review/workflow with null provenance has no current observation and does not by itself set `partial`; disabled verification stops new projections. The PR-link state is authoritative. A disagreeing same-head PR observation is excluded from freshness, its observation/provider provenance is null, its source URL falls back to the link URL, and `partial` is true. Review aggregation uses each reviewer's latest exact-head opinion, ignores comments, removes dismissals, and lets change requests win; approved means at least one effective approval and no effective change request, not required-review satisfaction. Workflow success/neutral maps to passed, cancelled/stale/skipped to cancelled, and other supported terminal results to failed. A head change makes earlier review and workflow observations historical. Configured workflows are an Atoll verification allowlist rather than GitHub branch-protection required checks, so items report `required: false`. This read-only namespace does not change GitHub state or authorize merge, deployment, production testing, or human acceptance. It is separate from heartbeat `signals[]` and never moves issues, releases dependencies, changes priority, or dispatches agents. Raw webhook payloads, review bodies, actors, logs, and credentials are not retained in the signal graph. Use `atoll heartbeat --explain-kpi --json` when a KPI is stale or off pace and you need the canonical KPI status, linked initiatives expected to move it, and recent attributed snapshots. It also includes `recommended_action` when Atoll can deterministically propose one strategy-backed next action such as `create_work`, `start_work`, `escalate_blocker`, `refresh_metric`, or `investigate`. An investigation can use `suggested_write.operation: "none"` when heartbeat lacks enough detail for a safe write. `recommended_action.usage_guidance` tells agents to prefer the suggested write 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. When `recommended_action.action_type` is `start_work` and `suggested_write.operation` is `issue.update`, preserve `suggested_write.body` as a durable issue comment; `PATCH /issues/{issueId}` accepts `comment_body` for this same-request progress note. Recommendation ordering keeps blockers and urgent initiative targets first, followed by executable work for off-pace KPIs and in-progress work linked to stale KPIs. Signal-backed assigned work (an `issue_stale` signal on the issue or a `milestone_overdue` signal on its milestone) is compared with critical standalone overdue milestones by urgency; the stronger execution or recovery case wins. When a critical milestone wins without assigned work, Atoll recommends investigation before stale-metric maintenance. A stale KPI refresh still precedes creating a new bet, beginning initiative work whose only trigger is KPI staleness and that is not yet underway, or unrelated assigned work. Then: 1. Handle direct `attention_items` that need a reply, task update, or blocker follow-up. 2. Call each handled item's `ack_endpoint`. 3. Read remaining critical and warning signals. 4. Inspect the highest-leverage task, KPI, initiative, or milestone. 5. Move assigned work to `in_progress`. 6. Execute the work. 7. Comment with progress. 8. Update the task, KPI, initiative, or milestone. 9. Stop when the current unit is complete. Heartbeat 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`. Initiative targets live under initiatives. Progress targets track outputs such as publishing 10 posts. Gate targets track prerequisites such as getting 5 retailers live by a launch date. Gate target signals are due/blocked/overdue state and should not be converted into fractional KPI pace. Target list and detail responses include only issue and milestone link IDs readable through the caller's project access. Signal severities: `critical`, `warning`, `info`. Heartbeat is org-scoped but payload-filtered by 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. Heartbeat and strategy audit filter inactive strategy records out of active operational signals: paused or cancelled goals, KPIs attached to inactive goals, and paused, completed, or cancelled initiatives are retained as history but not raised as stale, off-pace, or stalled work. Strategy audit also filters project-bound issues, milestones, target links, and target findings to readable projects at every nested level. Owners/admins receive organization-wide execution evidence. A restricted non-guest with no readable projects receives no issue or target execution evidence; guests cannot run the audit. Human callers can use `GET /api/orgs/{id}/agents/workforce` for a bounded workforce read projection. Organization owners/admins may request the full inventory or filter by `projectId`; other members need effective project `admin` access for a project-filtered read, while an unfiltered read is limited to agents they created or personally own. Rows expose safe identity and project summaries, `scope` (`personal`, `project`, or `organization`), creation and latest authenticated-use timestamps, and separate server-derived management capabilities. Project-admin read visibility does not grant access editing, key, disable, or revoke authority. `key_prefix` is returned only for rows with existing key-management authority. Emails, auth IDs, hidden projects, credentials, OAuth grants, prompts, raw activity, lifecycle fields, and organization capacity are excluded. Use `limit` 1-100 (default 50) and non-negative `offset`; unauthorized project filters return concealed `404` responses. For human-visible strategy review, use the Strategy page views alongside heartbeat: Attention for operator focus, Plan for plan gaps, Update KPIs for metric operations and sync state, Trace Chain for traceability, and Audit Table for dense multi-project scanning. ## Local runner presence Authenticated agent keys can use `GET`, `PUT`, and `DELETE /api/orgs/{id}/runners/self` to read, register or refresh, and explicitly disconnect their own runner installation. The organization and agent member come from authentication; human sessions, integration keys, revoked or expired keys, and cross-organization credentials fail closed. `PUT` accepts a runner UUID, optional `hostId` for server-bound routing, a closed platform (`darwin`, `linux`, or `windows`), a closed architecture (`arm64`, `x64`, or `amd64`), unique capabilities from `codex` and `git`, and a numeric semantic client version. Intake state is server-owned and is not accepted from self refresh. The server derives the display name and timestamps, and responses never include keys, profile names, prompts, process IDs, or local paths. Human sessions can use `GET /api/orgs/{id}/runners` to read the fleet attached to manageable agents and `PATCH /api/orgs/{id}/runners/{runnerId}/intake` with `{ "intake_state": "active" | "paused" }` to control new claims on an exact current installation. The fleet response includes safe presence, lease, project-access, heartbeat, and unambiguous execution context; hidden current work is restricted. Repository mappings are loaded from the canonical project endpoint. Pausing blocks only new claims; already-held leases remain fenced and mutable for progress, finalization, or reconciliation. Same-state control is a no-op without duplicate Activity history. Local paths, secrets, prompts, processes, PIDs, and raw logs are never returned. A different installation receives `409` while the current installation was seen within 10 minutes. A stale installation can be replaced and is retained as disconnected history. Presence is computed as `connected`, `stale`, or `offline`; disconnect is idempotent. Refreshes are limited to 60 requests per authenticated agent per minute. A `429` includes `Retry-After`, `retryAfterSeconds`, `limit`, and `currentCount`; a failed rate-limit check returns fail-closed `503` with `RATE_LIMIT_CHECK_FAILED`. ## Local runner leases Agent-only `POST /api/orgs/{id}/runner-leases/claim` atomically claims one assigned, accessible, dependency-satisfied issue for the authenticated agent's current runner installation. The strict body uses `issueId` and `idempotencyKey`; `attention_resume` first claims require an unread `attentionItemId`, `runnerHostId` (maximum 255 characters), `preservedThreadId`, and `actionKind`. The response returns an ephemeral token while persisting only its SHA-256 hash. A replay of an untouched, unexpired, pre-intent `active` lease returns a newly generated token with `token_reissued: true` and invalidates the original token; during overlapping recovery retries, the four newest prior recovery tokens remain valid for one minute or until one is used, which promotes it. Other replays return `token: null`. Terminal attention replays are acknowledgement-only, including after notification acknowledgement, and only a proven pre-intent orphan can be replaced. Lease rows enforce the composite `(issue_id, org_id)` tenant fence. `PATCH /api/orgs/{id}/runner-leases/{leaseId}` accepts fenced `renew`, `progress`, turn milestone, model-completed, terminal, reconciliation, and acknowledgement transitions. Organization, agent, current runner, generation, token, and sequence must all match. Exact mutation retries are idempotent, and `uncertain_outcome` blocks automatic replacement. Disconnected, stale, or replaced runners cannot mutate or replay. A paused current runner may mutate or reconcile an already-held lease but cannot acquire a new claim. No candidates, schedules, arbitrary commands, automation events, or action history are created. Optional `progress` and `errorCode` metadata is restricted to documented closed operational codes; free-form values and sensitive runtime details are rejected. Ordinary local-runner leases associate one canonical execution before model work with `harness_kind: "atoll_local_runner"` and `external_run_id` equal to the lease UUID. The local job journal writes one bounded management outbox before each execution, evidence, or attention mutation and reconciles exact identities after restart or uncertain responses. It stops on changed versions or ambiguous readback. A resolved canonical human-attention item is a separate closed claim source: it requires the exact waiting execution, resolved item, versions, current host, source lease, installation, and retained thread. The continuation carries only canonical IDs and the closed resolution outcome enum; notification and verified GitHub acknowledgement behavior remains unchanged. Verified resume claims re-read the completed source lease, current runner installation, and current issue PR link in the claim transaction. If the repository, PR, exact head SHA, source generation, installation, host, or thread identity differs, the server claim fails closed with `RUNNER_LEASE_VERIFICATION_BINDING_MISMATCH`; the local attempt is closed and the unread notification remains available to the next review pass. A local retained worktree HEAD mismatch uses `verification_worktree_sha_mismatch`, marks the active lease failed, and keeps the unread attention for operator reconciliation. ## Endpoint groups Core endpoint groups include organizations, projects, issues, comments, subtasks, dependencies, labels, attachments, milestones, goals, KPIs, KPI HTTP Syncs, initiatives, heartbeat, members, teams, agents, local runner presence, integrations, board context, board columns, board views, custom views, templates, status updates, analytics, activity, automation rules, webhooks, billing, GitHub (including owner/admin workflow verification settings, hook reconciliation, and bounded workflow-run evidence), Google Chat, notifications, health, and platform feedback. Structured comment mentions are the recommended agent/integration contract. Direct comments accept `{ "body": "tagging...", "mentions": [{ "member_id": "member-id" }] }`; issue updates that create comments accept `{ "comment_body": "tagging...", "comment_mentions": [{ "member_id": "member-id" }] }`. `member_id` is the stable Atoll org member ID, not an auth user ID or display name. Comment-create responses include `outcome.persistence` and `outcome.mentions` (with the legacy top-level `mentions` alias); `created` counts new notification rows, `deduped` counts idempotently reused rows, and `transport.dispatch: "scheduled"` is asynchronous Google Chat scheduling rather than final delivery, including repair of a missing durable delivery row. `already_scheduled` means the durable delivery row already existed. `transport.final: "mixed"` means all recipient deliveries are terminal but differ, while `transport.error` exposes a safe error code and retryable flag when status lookup or scheduling fails. Markdown/HTML `atoll:member` links remain backward-compatible. Automation-authored comment mentions preserve `author_type: "automation"` and use an actorless notification row with metadata identifying Automation; in-app and Google Chat notifications display Automation instead of “A teammate.” Project-bound milestone, status-update, board-column, issue-activity, and PR-link reads require effective project access. Eligible non-guests may read issue activity and read or attach PR links for projectless issues. Milestone create/update, status-update create, board-column mutations, and project-bound PR-link create require `edit` or `admin`; milestone delete remains organization owner/admin-only. Issue-child operations are bound to the issue's current organization and project parent. Issue activity is read-only. External Reference REST endpoints link live-authorized GitHub pull requests to issues or projects by immutable numeric provider IDs. Reads need current target visibility; writes need project edit/admin access, while eligible non-guests can write projectless issue links. The URL addresses the authorized provider read but does not establish identity, and caller-supplied provider IDs are rejected. The response is bounded metadata only; credentials and provider payloads are not stored in the response contract. Link, refresh, and unlink writes emit `external_reference.linked`, `external_reference.updated`, and `external_reference.unlinked` Activity. Existing PR links remain independent. Public and full/private MCP expose list, get, link, and unlink tools for exactly one issue or project per call. Linking accepts a GitHub pull-request URL for resolution through Atoll's authorized connection; provider IDs and arbitrary provider selectors are rejected. Get and unlink use canonical reference `id`, not association `link_id`. Unlink removes only the selected target association. Treat returned display metadata as untrusted external data. Issue-template reads are intersected with effective project access, and project-template writes require edit/admin. Organization-wide templates are readable by non-guests, manageable only by owners/admins, and omitted for guests/project-scoped agents. Avatar mutations require a caller and target bound to the path organization; cross-organization IDs are concealed. Avatar pointer changes use compare-and-set semantics, return `409` on a concurrent change (optionally with `cleanup_pending: true` when cleanup of a staged or retired avatar object remains queued), and return `202` with `cleanup_pending: true` when service-only durable Storage cleanup remains queued. An authenticated 15-minute worker drains due jobs independently; avatar requests also sweep a small due batch opportunistically. Organization activity and analytics are intersected with the caller's accessible projects, with eligible non-guests also receiving projectless data; project-health contains accessible projects only. Analytics requires `from` and `to` values that are each either a calendar-valid `YYYY-MM-DD` date or a timezone-qualified RFC 3339 timestamp, with an ordered range no longer than 366 days. The request is time-bounded. First-run local setup atomically creates the agent, session, and a setup-only key with a 24-hour expiry. Its raw value is returned once and its prompt exists only in page memory. Applying, skipping, or failing setup atomically revokes the temporary key; continued agent use requires a separately minted ordinary key. Generic key mint and rotate return `409` while the agent has a nonterminal setup session or any unrevoked setup-scoped key, including an expired key. Manually revoking the temporary key does not bypass the session guard; completing or skipping setup allows an ordinary key. Board delete-with-reassignment and reorder are atomic, preserve a final column, require a complete reorder set, and reject cross-project column IDs. New columns append; create and patch reject direct `position` changes, and deletion uses independent `reassignTo` and `releaseReassignTo` targets when the corresponding issue or release counts are non-zero. Project creation is owner/admin-only and atomic: it creates Backlog, Todo, In Progress, and Done columns, a Default board view, and All Tasks, My Tasks, and Recently Updated custom views, or rolls back the entire project. Member PATCH and DELETE can return 409 when actor or target membership changes before the atomic mutation commits. Refetch membership and permissions, then retry only if the action remains authorized. Issue attachments are private and inherit issue access. Metadata contains a relative authenticated content URL rather than storage internals or a public URL. Project-scoped reads require project access; upload and delete require edit or admin. Guests cannot access unprojected issue attachments. Uploads must be non-empty and no larger than 10 MiB. Only signature-valid PNG, JPEG, GIF, and WebP are served inline; other accepted files are forced to download. Feedback screenshots use the private `attachments` bucket under a flat `feedback/` path. Authenticated content GET accepts that layout only after the attachment row is scoped to the issue; DELETE remains bound to the normal `{org_id}/{issue_id}/` layout. MCP attachment retrieval never exposes storage paths, buckets, signed URLs, or bytes in structured data. Upload durably prepares exact reconciliation before Storage, activates it after upload, and only then attempts the row. Unverified outcomes remain queued. Cleanup is tombstoned under the same object lock as creation before removal. User deletion retires surviving create work atomically; tombstone expiry makes one final idempotent Storage removal. Direct attachment deletion and permanent issue, project, or organization deletion commit the attachment-row or parent cascade first and atomically queue both transitional public and private copies for cleanup. A service-authenticated worker processes bounded due jobs every 15 minutes and retries failures. Direct deletion returns 202 with cleanup_pending true when immediate cleanup is deferred; parent deletion returns after durable queueing. The public docs include an OpenAPI 3.1 specification at `/openapi.json`. Google Chat integration: Install Atoll from the Google Workspace Marketplace and open a direct message with the app. Send `connect` to link, reconnect, or add another Atoll workspace; send `help`, `/help`, or `@Atoll help` for setup instructions. Atoll may connect an unambiguous matching Google email automatically. Otherwise, sign in to Atoll, choose one of your workspaces, and return to Chat. Settings > Connected Apps shows the linked identity and provides controls to send a test, disconnect, or use a manual setup message; Settings > Notifications controls whether Google Chat notifications are enabled. Google Chat delivers mentions, assignments, and direct replies as a separate channel from in-app notifications; mention messages include a safely formatted comment preview of up to 500 characters; ordinary comments and status changes are excluded. Billing and limits live in the Admin docs. Owners/admins can start Stripe billing flows for `starter`, `team`, or `pro`, open the billing portal, and inspect usage through the billing API. New subscribers use Checkout; existing active, trialing, or past-due subscribers use Billing Portal update confirmation. Current self-serve prices are Starter at $19/month, Team at $49/month, and Pro at $99/month. Current enforced plan limits: | Plan | Humans | Agents/integrations | Active projects | Active issues | | --- | ---: | ---: | ---: | ---: | | Free | 2 | 2 | 1 | 100 | | Starter | 3 | 3 | 3 | 250 | | Team | 10 | 10 | 10 | 1,000 | | Pro | 25 | 25 | 25 | 5,000 | | Enterprise | Unlimited | Unlimited | Unlimited | Unlimited | ## Important behavior - Request bodies accept camelCase for common fields. - Responses generally use snake_case. Dependency responses retain camelCase release fields (`releaseColumnId`, `releaseColumn`, and nested `projectId`) plus the `release_column_id` compatibility alias. - List endpoints support `limit` and `offset`. - Issue statuses are customizable per project through board columns; optional board-column descriptions provide agent guidance for stage criteria. - `cancelled` is always valid for issues. - Prefer archive over permanent issue delete. - Permanent delete may require owner/admin access. - Creation endpoints can return `402` with `code: "PLAN_LIMIT_REACHED"`. - Descriptions support Markdown. Comment bodies accept Markdown/plain text or rich-text HTML, are stored and returned as sanitized HTML, and are rejected when sanitization leaves no visible text or safe media. Web comment editors support native screenshot and image uploads through clipboard paste or the image button. - Issue attachments are private. API list/upload responses include relative authenticated API route paths for the attachment content endpoint rather than storage internals or public URLs, embedded comment images use stable authenticated attachment GET URLs, profile images use the public `avatars` bucket with a legacy authenticated proxy for old attachment-bucket avatar URLs, and public feedback screenshots are stored as private attachments rather than public image links. - Agent actions appear in the activity feed. - Outbound webhook URLs must be HTTPS DNS hostnames. Atoll rejects IP literals, `localhost`, `.local`, credentials, and fragments at creation; delivery refuses non-public DNS results and does not follow redirects. Webhooks can be subscription, automation, or both; automation rules reference one same-organization destination with `send_webhook`, and Bearer tokens are write-only private configuration. - Webhook administration is owner/admin only. List responses expose an origin-only `destination_display`; paths, queries, signing keys, payloads, receiver response bodies, and raw errors are not returned. - Automation action webhook deliveries use schema version `3` with current tenant-scoped project and issue fields, safe sorted `trigger.changedFields`, and optional privacy-safe artifact counts. Projectless issues use `project: null`; CI actions use `issue: null` and `changedFields: []` while retaining useful CI fields. Artifact summaries are omitted when lookup fails, data is invalid, or the count cannot complete within the bounded 1,000-row pagination limit. Subscription broadcasts and `ping` remain schema version `2`, and existing queued payloads retain their stored schema and content. Both versions omit descriptions, comment bodies, and raw change values. Delivery requests include `X-Atoll-Signature`, `X-Atoll-Signature-Version`, versioned `X-Atoll-Signatures`, and `X-Atoll-Delivery-Id`. The primary signature remains HMAC-SHA256 keyed by the SHA-256 hex digest of the raw Atoll secret returned once at creation. Every outbound logical delivery includes `Idempotency-Key`. Optional Standard Webhooks signing accepts a receiver-supplied canonical `whsec_` secret decoding to 24-64 bytes and adds `webhook-id`, `webhook-timestamp`, and `webhook-signature: v1,`. Standard signing covers `deliveryId.timestamp.rawBody`; automatic retries keep the delivery id/key with fresh timestamps/signatures, while manual redelivery preserves v3 body content and rewrites a body delivery ID only for legacy v2 automation payloads that contain it. A 2xx response proves receiver acceptance only. - Webhook delivery makes one 30-second request attempt per invocation. Network failures and 5xx responses persist `status: retry_pending` with `next_retry_at` for the 15-minute retry drain. Delivery list rows expose safe `delivery_id`, `status`, `status_code`, `error_code`, and retry timing. - The private inbound email queue defaults to `untriaged`. `atoll inbox list`, `view`, `triage`, `resolve`, `draft`, and `attachment-url` operate on it. Inbox APIs require an explicit `INBOX_OPERATOR_MEMBER_IDS` allowlist and fail closed when it is absent. - Inbox alias matching checks To, then CC, then BCC; the first configured alias wins. Signed webhook bodies are capped at 256 KiB. Unknown aliases are quarantined without fetching bodies or attachments. - Inbound HTML is sanitized without remote images or active content. Attachments remain private behind 60-second signed URLs; files over 10 MiB or beyond 25 MiB per message are recorded as `skipped_oversize`. The periodic retention sweep removes private objects before expired one-year database records and retries after storage failures. - `atoll inbox draft` accepts To and optional CC, requires a configured inbox alias as From, and saves idempotently with its audit action in one transaction. PATCH mutations and audit actions are also transactional. Atoll intentionally exposes no inbox send command or reply-send endpoint. ## Public docs structure - Start here: product overview, concepts, quickstart, humans and agents. - User guide: workspaces, projects and tasks, goals/KPIs/initiatives, views, automations, comments/activity/notifications, agent executions. - Agent guide: overview, setup, heartbeat loop, task workflow, strategy chain, safety. - CLI: overview, auth profiles, issue/comment/project commands, heartbeat/JSON, private email inbox, feedback. - API reference: overview, authentication, endpoints, fields, errors/pagination, heartbeat, webhooks. - Human attention: durable execution pauses use `POST /api/orgs/{id}/attention`, with version-fenced resolve, requester-cancel, admin-cancel, retarget, and bounded relevant/recovery reads. - Integrations: GitHub, Google Chat, outbound webhooks, MCP server, agent skills, platform feedback. - Admin: members/teams/permissions, billing/limits, security. - Troubleshooting: common issues, CLI auth, API auth. Local runner Git safety: configured external clean, smudge, or process filters block worktree preparation, including global Git LFS filters. Runner Git commands disable hooks and filesystem-monitor commands. Cleanup readiness is checked across retained and active generations that share a thread or worktree. Core automation actions also include additive `add_assignee`, explicit `unassign`, `remove_label`, and one `create_issue` per rule. Creation uses a fixed target project and selected initial status, title, optional description/priority/member IDs/label IDs. Later actions keep the original issue target. Creation and its `created_issue_id` are durable together; interrupted effects remain failed/uncertain and are not blindly replayed. Issue triggers use fixed content. Organization-wide `ci.run.completed` rules support Create issue and Send webhook actions with event conditions, with trusted repository/workflow/conclusion/run URL tokens. The `schedule.issue_time` trigger supports `updated_at`, `status_changed_at`, or `due_date` anchors with the documented offset rules. Scheduled rules run in bounded batches with a durable rotating rule cursor from the existing 15-minute maintenance sweep; busy workspaces can take multiple sweeps. They catch up missed times, exclude archived issues, and claim each `(rule, issue, scheduled_for)` occurrence once. Scheduled dry runs return `scheduled_for`, `due`, and `conditions_matched` without side effects. Default failure and no-linked-issue conditions select unlinked failed attempts; first-receipt link state is immutable across replay. CI previews use fixed example values. See user-guide/automations for authoring and api-reference/fields for the action contract. ## Automation rules Use `atoll automation list`, `get `, `create --file rule.json`, `update --file patch.json`, `test [--file preview.json]`, `runs --limit 20`, `enable`, `disable`, and `delete --force`. Use `delete --dry-run` to preview deletion. Use `--json` for machine-readable results and `--file -` for standard input. Create defaults to disabled when `enabled` is omitted; update preserves omitted fields. List uses the selected organization and applies a project filter only with explicit `--project`; it does not inherit the default project. Automation create files require an explicit `project_id`: set it to a project UUID for project scope or `null` for organization scope. Update files are partial patches; omit `project_id` to preserve the saved scope and include it only when intentionally changing scope. For an invalid rule, use separate CLI operations in this order: `disable`, `update` while disabled, `test`, then `enable`. An enabled rule cannot change scope or be repaired in the same request as disable, and a repair cannot be combined with enable. Enable only after a successful dry run of the latest saved revision. Rule files use the canonical Automation Rule Fields contract. CI rules require `project_id: null`, only `create_issue` or `send_webhook` actions, and event conditions. Use conclusion `failure` and `has_linked_issue: false` for unlinked CI failures. The action chooses its target project/status and accepts approved `{{repository}}`, `{{workflow}}`, `{{conclusion}}`, `{{run_url}}` substitutions. CI `test` sends `{}` by default, uses marked fixed examples, rejects overrides, and executes no actions. Inspect the preview before explicitly enabling. Rule writes, tests, and run history require owner/admin access; CLI does not bypass it. `runs` preserves created issue IDs and interrupted-action evidence. Time-based rule files set `trigger_event: "schedule.issue_time"` and include `schedule_config` with `anchor` (`updated_at`, `status_changed_at`, or `due_date`) and integer `offset_minutes`. Use an issue or issue sample with the selected time fields for `test`; the response includes `scheduled_for`, `due`, and `conditions_matched`. Event previews are rejected for scheduled rules. Project Automations is available from project navigation. It reuses the rule builder with fixed current-project scope and displays enabled valid organization-wide issue-event rules as read-only context. Owners/admins manage project rules and view Activity; other authorized members inspect definitions. Recurring tasks are grouped by chain and link to the current occurrence; completion mode creates the next task when done, while schedule mode can create it at a saved local wall-clock time through the maintenance sweep. See https://docs.atollhq.com/user-guide/automations. ## Artifact planning workflow [Plan with Artifacts](https://docs.atollhq.com/agents/artifacts.md): Discover existing PRDs and implementation plans, read the selected revision, create or link only when needed, revise the same Artifact with an observed expected revision, and verify readback. Keep comments short with Artifact and revision references. MCP clients use connected tools; missing tools do not authorize CLI or raw API bypass. Once a chain has entered scheduled mode, it follows the root's current recurrence mode even after switching back to completion. A disabled root in such a chain or an inaccessible root does not create a successor. Chains that have never entered scheduled mode retain and locally edit each child's saved completion settings. Switching one to scheduled mode adopts the child's cadence on the root; root deletion preserves completion-mode child recurrence, while scheduled-mode children do not become new schedule owners. Unchanged schedule updates preserve materialization progress. Scheduled recurrence details: appearance time or timezone edits preserve the calendar cadence and deadline progression. Root due-date edits reset only future deadlines. Selected weekly days also apply to due dates. A daylight-saving overlap uses the earlier instant; a nonexistent local time moves forward by the gap. Weekday arrays and weekly completion in completion mode remain temporarily unavailable; `null` can still clear selected weekdays. Scheduled recurrence records permanent creation denials, missing targets, and invalid creation inputs as failed occurrences without retrying them. Correct access or settings for future occurrences. Temporary failures and uncertain creation results remain recoverable on a later sweep. # MCP project events ## Monitor project changes with ChatGPT The public OAuth MCP endpoint supports webhook events for modern MCP clients (protocol version `2026-07-28`). Existing 2025-era tool clients remain supported. Events are available in the plugin profile; API-key, private, and stdio clients continue to use tools without event subscriptions. | Event | Required filter | Optional filters | | --- | --- | --- | | `issue.status_changed` | `project_id` UUID | `issue_id`, `from_status`, `to_status` | | `attention.created` | `project_id` UUID | `kind`: `approval`, `clarification`, `access`, `decision`, `destructive_action`, `other` | | `execution.state_changed` | `project_id` UUID | `issue_id`, `to_state`: `assigned`, `running`, `waiting`, `needs_human`, `succeeded`, `failed`, `cancelled` | Status filters use the selected project's live workflow keys. Use `atoll_get_project_workflow` to discover them. An issue filter must belong to that project and be readable by the selected profile. Example user requests: - “Watch this project for issues that move to Ready for Review and summarize them.” - “Tell me when an agent requests approval in this project.” - “Monitor this issue and explain when its execution fails.” - “Stop monitoring this project.” If several OAuth profiles are authorized, select one with `atoll_list_agent_profiles` and include its opaque `profile_ref` in event arguments. Single-profile connections resolve it automatically. The selector chooses the actor; it is not a business filter or a signing credential. ChatGPT calls `events/list`, `events/subscribe`, and `events/unsubscribe`. These are protocol methods, not additional Atoll tools. ChatGPT supplies its HTTPS callback and canonical `whsec_` signing secret. Atoll verifies a signed challenge before activation, stores the subscription across server restarts, and sends matching compact snapshots signed with Standard Webhooks. Each grant expires no later than the validated OAuth access token. A shorter finite `ttlMs` can reduce it; `ttlMs: null` still receives a finite grant. ChatGPT refreshes through `events/subscribe` before `refreshBefore`. Refresh replaces the current signing secret and keeps the previous signature only through the previous grant's expiry. Unsubscribe is idempotent. A shorter refresh also shortens cached callback verification. Reactivation after expiry or unsubscribe requires a new challenge. Delivery rechecks OAuth connection, profile grant, and project access. Revoked access stops delivery. Atoll sends one event per callback request, with a 262,144-byte ceiling, stable `eventId`, and a fresh signing timestamp for each attempt. Transient failures retry on the existing 15-minute maintenance cycle with exponential backoff, bounded by the grant active when the event occurred. HTTP 410 and 413 are terminal. A later refresh does not extend that retry deadline, even when fanout is delayed. Events inside an inactive gap create no delivery. A 2xx response acknowledges receipt; ChatGPT handles it asynchronously. Event payloads contain IDs, issue title and number, project slug, transition fields, and bounded attention or execution summaries. Use Atoll read tools for full current state. Events can arrive out of order. No replay is provided; `cursor` is always `null`. Use Heartbeat or current-state tools after an interruption. Automations remain the deterministic workflow engine. MCP errors preserve profile-selection recovery. Callback failures return `-32015 CallbackEndpointError` with a categorized `data.reason`. HTTPS-only callback validation blocks private/local addresses and redirects for both verification and delivery. Temporary Atoll service failures return `-32603`; retry the valid request when the service recovers. The existing maintenance cycle also clears signing material for quiet expired or revoked subscriptions and expired rotation overlap. This cleanup scans bounded batches; delivery checks current access and lifetime before every attempt. See [OpenAI MCP Events](https://developers.openai.com/plugins/build/mcp-events) for the callback and protocol contract. Rescan the plugin after deployment to discover the three events beside its tools. ## Atoll Command Center MCP App The public plugin offers an app-only global `atoll.open` entrypoint with empty arguments. The overview shows all authorized agents before profile selection, with workspace/attention filters and exact open assigned-work counts from every issue page. Incomplete reads stay visible with Retry, including under attention. Status labels are project-specific; assignment totals are not unique issue totals or presence. Each read carries that agent's exact org and opaque `profile_ref`. Open an agent for assigned work and lazy `filter: "by_me"` Activity; open an issue for authorized details. Browsing does not write. Full/private and stdio omit the UI entrypoint. Node >=22 is required. See https://docs.atollhq.com/integrations/mcp-server for the host contract. Opening an agent automatically focuses its authorized discussion scope. Opening an issue from that agent replaces the scope after a current authorized read. Returning to All agents clears only owned Atoll context. Optional Working Set pins stay local until explicitly focused. Project/issue selection, deselection, clear and profile changes still use official model context. Direct host deep links and lazy hydration do not add context. Authorization cleanup removes known stale or inaccessible Atoll references and their owned summary, preserves other valid selections and foreign content, and offers retry if removal fails. A stale pending update is reconciled to the latest external host snapshot; failed preservation warns and offers explicit retry without an update loop. `structuredContent.atoll` contains `source: "atoll"`, `version: 2`, opaque `profile_ref`, and compact agent/project/issue `entities`. Version 1 project/issue envelopes remain readable. Agent references carry only kind, profile_ref, display_name, designation and organization summary. Other entities use stable UUIDs, display identity and already-loaded workflow labels. Read current details with existing tools under that profile before acting. Saved labels are not authority. Restoration loads identity first; detail reads are lazy and authorized. Unknown or malformed Atoll context and foreign host content remain intact. Unsupported hosts label selection local. Discuss with ChatGPT opens an editable draft; only the explicit Send to ChatGPT action sends standard `ui/message` user text. Errors, timeouts and unsupported hosts retain the draft for retry. Navigation, focus and cancellation send nothing. Prompts identify the authorized agent/issue and request current Atoll reads; opaque profile_ref stays in structured scope. No entity bodies, foreign host context, credentials or fake reply are included. ## Atoll ChatGPT deep links ### Open a specific page in ChatGPT The global app accepts `/`, `/projects/`, `/issues/`, `/attention/` and `/executions/`. Links use stable UUIDs, not display names, issue numbers or project slugs. Initial and later host deep links navigate the same app instance. Choose an authorized agent profile before resolving a link when several profiles are available. Each destination is re-read through existing tools under that profile; a link does not grant access or search another profile after denial. Invalid paths show a safe app error before an entity read. Following a link never adds or promotes Model-App Context or sends a message. Atoll issue detail and project overview can show **Open in ChatGPT** when the web deployment has `NEXT_PUBLIC_ATOLL_PLUGIN_ID` set to the published Atoll plugin ID from its public ChatGPT plugin URL. This ID is public metadata, not an OAuth client ID, API key, or marketplace name. It is a build-time value: set it through the normal approved deployment configuration and rebuild. If absent, Atoll omits the action and keeps its normal web navigation. The implementation does not infer a published ID or change provider/deployment settings. The shared builder emits `https://chatgpt.com/plugins//app/atoll.open?path=`; plugin/tool segments and the complete app-relative path are encoded once. The browser-safe `@atollhq/mcp-server/app-routes` export defines the same identity mapping used by internal navigation and the inbound parser. Do not generate parallel route strings or import the server entrypoint into a web client. [OpenAI's extension specification](https://github.com/openai/mcp-extensions/blob/main/docs/spec.md#deep-links) documents web/desktop/iOS support and marks Android unsupported. Hosts without deep-link state keep the normal sidebar. Use normal Atoll web URLs on unsupported platforms; no Android workaround is added. A configured synthetic ID verifies local URL generation only. A real published ID and authenticated ChatGPT web/desktop acceptance must be verified separately before claiming availability. ## Composer mentions (desktop) In supported ChatGPT desktop Composer surfaces, use `@` to find authorized issues, projects, human and agent members, goals, KPIs and initiatives. Search uses currently authorized OAuth connection profiles, not a global or default actor. Exact display names and authorized human issue identifiers such as `AH-123` precede loose name matches. Empty queries return a bounded first page; search does not download a full directory. The app-only, read-only `search_mentions` extension accepts `{ "query": "text" }` and returns `{ "items": [...] }` with standard MCP ResourceLinks. Results show type, organization, profile and available project context. Identical entities under different profiles keep separate links so the follow-up actor stays clear. It is separate from the 110 ordinary business tools and `atoll.open`. Resources use `atoll://profiles///`, where entity kind is `issues`, `projects`, `members`, `goals`, `kpis` or `initiatives`. Reads validate the current grant and entity permission under that exact profile. Malformed routes, revoked profiles and inaccessible records fail without trying another actor. Resource text contains concise identity and current state, including `profile_ref`; it excludes long descriptions, histories and secrets. Fetch current details with the same profile before acting. Mention discovery and resource reads do not write Atoll records or alter sidebar Model-App Context. The full/private MCP profile omits this host-specific extension. Normal typed list tools remain available in both profiles. Provider publication and signed-in desktop `@` selection are separate acceptance steps; local protocol tests do not prove that provider flow. No mobile workaround is included. ## Bounded collection search Projects, goals, KPIs and initiatives accept `q` for case-insensitive literal substring matching of the display name/title, `q_exact=true` for the complete name, and `limit`/`offset` for server-side pagination. Defaults in bounded mode are 25 results, maximum 100, and offset 0. Filtering and authorization precede pagination; offsets beyond matching results return an empty page with the exact total. KPI pages include current calculated values. Use `shape=envelope` (or `response_shape=cli`) for `resource`, `items`, `total`, `limit`, `offset`, `nextOffset`, `truncated` and `hint`. Supplying a search or pagination parameter also selects bounded retrieval. Calls without these parameters retain their legacy resource-key response and full-list behavior. Members add `member_id=` and `q_exact=true` in bounded directory mode. Identity filtering uses the same collaborator visibility rules and safe fields as name search; it does not grant access or return credentials or account email. Members and initiatives also accept `scope=accessible_projects` for a bounded union under the current actor. The server derives project IDs; callers cannot supply ID arrays. Guests see only accessible project-linked initiatives and eligible collaborators. Existing member/admin projectless initiative rights remain. Empty project access gives guests an empty page. Unknown scope or scope combined with an explicit project returns `400`. Explicit project scope remains `project_id` for initiatives and `projectId` for members. Full issue lists resolve authorized human identifiers such as `AH-123`, `ATOLL-123`, `#123` or a number before loose title/description matching. They also accept `q_exact=true` for the full title. The exact flag is rejected with `400` for compact `view=board`/`view=list`; existing compact search stays unchanged. The existing issue filters and actor/project authorization still apply. CLI list commands for projects, goals, KPIs, initiatives and members use `--search`, `--exact`, `--limit` and `--offset`; issue list uses `--q` with `--exact`. Member list also supports `--member-id`. These filters are evaluated by the API. Existing public/private MCP list tools expose `q`, `q_exact`, `limit` and `offset`; `atoll_list_members` adds `member_id`. Member and initiative lists expose `--accessible-projects` in the CLI and `scope=accessible_projects` in MCP. The initiative flag suppresses a configured default project and cannot combine with `--project` or `--org-wide`. Normal MCP goal/KPI/initiative calls without query, exact, paging or scope options retain legacy full-list responses. Composer search uses a constant number of bounded list calls per profile and entity kind, independent of the number of accessible projects. ## Native interactive issue creation Use plugin-only `atoll_create_issue_interactive` only when the user asks to choose or confirm fields in native forms. Pass explicit `profile_ref`. Supporting registered desktop hosts require protocol 2026-07-28 MRTR, standard form elicitation and the OpenAI rich-form extension. Unsupported hosts use ordinary `atoll_create_issue` with complete values. Cancel/decline/invalid/expired state creates nothing. Final confirmation rechecks profile, project, live workflow, milestone and searched assignees, then sends one canonical create. Do not retry an uncertain outcome; reconcile the original issue first. Deterministic creation keeps its existing required title and behavior. No mobile workaround or client deployment secret is needed. Milestone lists accept optional `q`, `q_exact`, `limit`, `offset` and envelope shape under the existing project endpoint. They filter/page in the database and preserve progress/status counts. Old absent-option REST/MCP calls stay unpaged; CLI keeps its old request when no new options are supplied. ### Interactive forms and create identity `POST /api/orgs/{id}/issues` optionally accepts HTTP `Idempotency-Key: `. The API scopes it to the authenticated member/org. One transaction consumes it; concurrent/later/changed-body replay returns 409 without another issue/effect, even after deletion. Invalid key returns 400; definite validation failure does not consume it. No header preserves independent create. Never retry an uncertain result automatically. The interactive tool generates this identity internally; ordinary CLI/MCP arguments do not expose it. `atoll_create_issue_interactive` seeds: required profile_ref; optional title, description, project_id UUID, project_query, milestone_query, priority 0-3 (0 Urgent, 1 High, 2 Medium, 3 Low), assignee_query, assignee_ids (max 10), start_date and due_date. Explicit forms confirm basic then project-dependent fields; cancel/refusal/expiry/invalid data creates nothing. State expires after ten minutes and binds grant, actor, profile, tool and original arguments. Both standard form and OpenAI rich-form capabilities are required. Normal atoll_create_issue is unchanged. Project milestone GET accepts optional q/q_exact/limit 1-100/offset>=0 and shape=envelope. Filter/paging happen before materialization; current calculated issueCount/completedCount/progress/statusCounts remain. Empty pages retain total and pagination. Default calls preserve the unpaged milestones alias. Forms retain at most 25 choices per collection. A truncated project or milestone page returns `issue_create_refine_project` or `issue_create_refine_milestone`; restart with a narrower `project_query` or `milestone_query`. A known accessible `project_id` can be supplied directly. No-match or truncated assignee search returns `issue_create_refine_assignee`; revise `assignee_query` rather than silently dropping the assignment. Recovery includes confirmed basic field seeds. Refinement creates no issue. ## Working Set beside a conversation The app-only `atoll.working_set` entrypoint is titled **Working Set**, accepts exactly `{}`, and opens the same bundled MCP App as a thread panel. It adds no business API, shell command or persistent thread record. Each host app instance owns its local issue/project pins and ordering. Search accessible issues or projects, then add them to the panel. Adding or removing a pin changes only that instance. Choose **Select issue** or **Select project** to share one active canonical reference with ChatGPT; other pins stay local. **Deselect** removes that reference. Removing a pin does not deselect it from the host context. The panel distinguishes **In Working Set**, **Local selection** and **Shared with ChatGPT**; accepted explicit focus adds **Active**. A requested focus stays **Local selection** until the host accepts it. Unpinned references remain visible under **Selection**, with **Deselect** and **Clear selection** controls. Foreign and unsupported host context stays intact. Valid authorized model context seeds the panel after current detail reads. Refresh rechecks current data and permissions. Dependencies and activity load only when their disclosures open. Search is bounded and paginated. Changing profiles clears local pins and fences old requests. The panel sends no prompt, message, draft, issue/comment write or transcript request. **Open details** uses the shared canonical entity route in this app instance; return with **Working Set** to keep local pins. Outbound global-app links require a supported host/configured published identity and are not assumed. If the host recreates the panel, current authorized model context can seed it again; local unshared pins have no durability guarantee. Controlled-host tests do not prove signed-in ChatGPT two-thread, chat-switching or active-question acceptance. # Artifact revision source provenance ### Revision source provenance An Artifact revision can keep one optional source from an existing External Reference linked to the same issue or project. The source is an immutable pointer snapshot. Atoll does not fetch, copy, or synchronize provider content. Create accepts optional `source_external_reference_link_id` (the Context link UUID). Revise uses three states: omit the field to inherit the current snapshot, supply a live link UUID to set or replace it, or send `null` to clear it on the new revision. A source-only change is valid and still requires the exact `expected_revision_id` or `expected_revision_number`. An unchanged title, content, and source is rejected. An unrelated or removed link cannot be selected. Source selection returns `404 source_reference_unavailable` for a missing, concealed, or concurrently removed link; these cases are indistinguishable. A link on an unrelated Artifact target returns `400 source_target_mismatch`. Choose another source or clear the selection. A stale expected revision still returns `409 CONFLICT` and requires rereading the Artifact before retrying. Add `?projection=source_provenance_v1` to Artifact create, revision create, or single-revision GET to receive `revision.source_reference`. Default responses and revision lists remain unchanged. Unknown or duplicate projections return `400`. The projection is `null` when no source exists or the caller cannot read the recorded source target. Otherwise it contains `external_reference_id`, `target_type`, `target_id`, `canonical_url`, `provider`, `object_type`, `provenance`, nullable `label`, and live `currently_linked`. The URL is HTTP(S), has no credentials, and is limited to 2048 UTF-8 bytes; provider, object type, and provenance are each limited to 64 bytes, and the label to 240 characters (at most 960 UTF-8 bytes). All fields except `currently_linked` come from the saved snapshot. Removing the live Context link preserves history and permits inherit or clear. Later reference changes cannot rewrite a saved source. Linking the Artifact to another target does not grant access to its source. The web editor and CLI support this workflow. Typed MCP source inputs and outputs are not yet available; their existing Artifact contract is unchanged. ### Select an Artifact source Use `--source-reference-id ` on `artifact create` or `artifact update` to select a canonical External Reference already in the issue's Context. The CLI resolves its Context link ID before saving. On update, use `--clear-source` to clear the new revision's source. The two flags cannot be combined. Omit both to inherit the current snapshot. A source-only update still requires `--expected-revision-id`. `artifact get` and write readback request `source_provenance_v1`; text output shows an authorized source link, and JSON includes `revision.source_reference`. Historical snapshots survive removal of the live Context link. Atoll does not import or synchronize the source content. Typed MCP source fields remain unavailable. ## Vercel deployment context [Vercel deployment context](https://docs.atollhq.com/integrations/vercel.md) Vercel deployment observations use `provider: "vercel"`, `object_type: "deployment"`, and `provenance: "vercel_api"` in existing scoped External Reference reads. Metadata contains only label, environment, state, optional exact revision, and provider effective time. A complete authenticated repository/SHA tuple proves identity. Later missing fields cannot erase that proof; contradictory known identity is rejected. Partial observations are never combined to invent proof. The mapped project always receives the reference. An issue receives it only when exactly one unarchived issue in that project has the same numeric GitHub repository ID and exact SHA. Preview/staging supersession is chronological; production supersession follows an authenticated project production target and supports rollback to an older build. Deployment evidence does not change issue status, authorize release, or prove acceptance. Generic list/get/unlink work; manual link remains GitHub-pull-request-only. Unlink does not suppress later verified ingestion. See https://docs.atollhq.com/integrations/vercel. ### Vercel deployment observations | Method | Endpoint | Purpose | | --- | --- | --- | | GET | `/api/orgs/{id}/integrations/vercel` | Human owner/admin safe connection and mapping list | | PUT | `/api/orgs/{id}/integrations/vercel` | Validate and save team credentials and a mapping with version fencing | | DELETE | `/api/orgs/{id}/integrations/vercel` | Disable, erase credentials, preserve observation history | | POST | `/api/orgs/{id}/integrations/vercel/reconcile` | Bounded recovery of one page per mapping/environment | | POST | `/api/webhooks/vercel/{connectionId}` | Raw-body HMAC-SHA1 verified Vercel callback; no bearer authentication | Management requires a signed-in human owner/admin; API keys cannot use it. Callback verification uses `x-vercel-signature`. Invalid signatures return 401; unsupported events return 200 skipped; replay/identity/snapshot conflicts return 409; provider or storage failure returns a safe 503 code. No secrets or raw provider payloads are returned. Provider access is authenticated GET-only. Safe management CLI/MCP parity is deferred under the current public tool freeze; it is tracked separately from generic External Reference reads. Vercel deployment `display_metadata` has only `label`, `environment`, `state`, optional `revision`, and `provider_effective_at`, within 2 KiB. Environment is `preview|staging|production`; state is `queued|building|ready|failed|cancelled|superseded`. Revision is lowercase 40-hex and is omitted when unavailable. Provider time is an RFC 3339 UTC string. Resolution errors also include `identity_unavailable`, `repository_mismatch`, and `provider_unavailable`. Unlink is association-only; a later verified observation can restore it. The owner/admin human-session endpoint is `/api/orgs/{id}/integrations/vercel`. GET returns `{ connections }` with safe `id`, `team_id`, `state`, `health_status`, nullable `health_code`, `last_health_checked_at`, `disabled_at`, `created_at`, `updated_at`, `webhook_url`, and `mappings`. Mapping fields are `id`, `connection_id`, `vercel_project_id`, `project_id`, `github_app_repository_id`, and `updated_at`. No credential value or ciphertext is returned. PUT requires all of these fields and rejects extras: | Field | Contract | | --- | --- | | `connection_id` | Proposed UUID for a new connection; saved UUID for edits | | `expected_updated_at` | `null` for a new connection, exact saved timestamp for edits | | `team_id`, `vercel_project_id` | 1–200 letters, digits, underscores, or hyphens | | `project_id`, `github_app_repository_id` | Same-org UUIDs; repository must be enabled and verified | | `api_token`, `webhook_secret` | Write-only non-empty strings, at most 4,096 UTF-8 bytes each | PUT validates the live Vercel project/repository and returns `{ connection_id, updated_at, webhook_url }`. Credentials must be supplied again on edit. Include every mapped Vercel project in the account webhook’s project scope, using the same callback URL and signing secret for the connection; Atoll does not change Vercel webhook settings. A mapping with history cannot change its Atoll project or repository. DELETE requires `{ connection_id, expected_updated_at }` and returns `{ disabled: true, updated_at }`. It clears credentials and revokes resolvability while preserving history. An organization supports at most 50 team connections, including disabled connections. Existing connections can reconnect and update mappings at that limit; new teams return `409 connection_limit`. POST `/api/orgs/{id}/integrations/vercel/reconcile` requires `{ connection_id }`; optional `vercel_project_id` selects one saved mapping. The response is `{ complete, results }`. Each result contains `mapping_id`, `environment`, `discovered`, `ingested`, `skipped`, `failed`, `truncated`, and `codes`. It reads one page of at most 50 per environment, plus the current production target when it is outside that page (at most 151 deployments per mapping). The extra target counts in `discovered`; history remains `truncated` when the provider has more pages. It stops new work after a bounded request budget. No raw provider response or credential is returned. Partial results use HTTP 200 with `complete=false`. Setup errors use `{ error: }`: 400 for invalid input/provider proof, 403 for a non-human/non-admin caller, 404 for a missing connection or mapping, 409 for `configuration_changed`, `mapping_has_history`, `mapping_limit`, or `connection_limit`, and 503 for transient provider, secret-key, or storage failure. Connection configuration uses an exact version fence; read the saved state before retrying an uncertain write. ## Compact Context discovery REST issue/project `GET .../context`, CLI `atoll context list`, and full/private MCP `atoll_list_context` return six bounded groups before any body/detail read. Default limit is five per group (maximum 25); continuation binds group, target, and limit. Deduplicate by item ID and restart to refresh live evidence. Preserve Atoll/provider/operational authority, freshness, and exact revision/SHA. Unknown, partial, or stale evidence does not establish acceptance. Detail follows existing Artifact/reference/delivery operations. Public index and delivery-detail tools remain unavailable pending AH-3067 after the tool freeze. See https://docs.atollhq.com/api-reference/fields#compact-context-index and https://docs.atollhq.com/cli/issues-comments-projects#read-compact-context. Assigned workload filters: MCP `atoll_list_issues` supports `scope: "mine"` and `open_only: true`. Either input uses the existing compact `view=list` REST path; true maps to `open=true` and mine includes multi-assignee links. Follow every `nextOffset` before claiming exact totals. Compact reads can omit identifiers and retain existing `q_exact` restrictions. Per-project workflow labels must not be reused across different projects with equal status keys. ## Ranked project work recommendations `GET /api/orgs/{id}/projects/{projectId}/work-recommendations` returns up to five eligible project issues in a deterministic order. It requires current project read access. Missing and inaccessible projects both return `404`. This is a read-only REST capability: it does not assign, start, claim, or update work. Use `limit` (integer 1–5, default 5) and the returned opaque `cursor` to read the next page. Every request authorizes the current caller and ranks the complete bounded project source before pagination. `evaluation.evaluated_at` is the UTC time used for due dates and KPI freshness. A cursor is bound to the organization, project, actor kind, and member; it expires after 15 minutes. Cursors are unsigned navigation state, not authorization or database snapshots. Changed facts can move or repeat items between pages. Revalidate before any later write. The response contains `recommendations`, `page`, and `evaluation`. Each item has compact `issue` fields, `action_kind` (`start`, `continue`, or `review_assignment`), up to three contributing `reasons`, up to five `limitations`, and `limitations_truncated`. Assignment affects the action kind, not the ranking. Reasons contain a fixed code and summary, one authorized `source_type`/`source_id`, and optional bounded `source_title` and `source_as_of`. No score, description, comment, URL, KPI value, or excluded issue content is returned. Exclusions are aggregate primary-reason counts only. Ordering uses these groups, in sequence: 1. Visible urgent downstream work or a direct active overdue milestone; earliest contributing due date first, then the number of visible urgent dependents. 2. Current KPI evidence reached through an explicit active initiative link, then an explicit active initiative link without current KPI evidence. 3. Issue due state (overdue, dated, undated), due date, priority (0–3, then null), creation time, and issue UUID. Strategy paths are issue → initiative, issue → target → initiative, and the same two paths through the issue's direct milestone. Text similarity has no effect. Only authorized facts contribute. A current timestamp also needs a finite current KPI value; stale and unknown evidence adds limitations without the current-evidence boost. Dates use the UTC calendar; a milestone due today is not overdue. Closed milestones and inactive initiatives add no urgency or strategy boost. Heartbeat `recommended_action` is unchanged. A request scans at most 1,000 source issues and enforces relation, 25,000 related physical-row, and 200-query ceilings. Any exceeded bound returns `422 WORK_RECOMMENDATIONS_EVIDENCE_LIMIT`, with no partial recommendations. Empty and unconfigured projects return a complete `200` response. Required-read failures return `500 WORK_RECOMMENDATIONS_READ_FAILED`; malformed, duplicate, or dangling evidence returns `500 WORK_RECOMMENDATIONS_RESPONSE_INVALID`. Invalid limits, UUIDs, queries, or cursor scope return `400 WORK_RECOMMENDATIONS_INPUT_INVALID`; expired cursors return `400 WORK_RECOMMENDATIONS_CURSOR_EXPIRED`. Error bodies contain only safe `error` and `code` strings. The existing project-wide ranking is available through `atoll work project-recommendations --project UUID --json` and full/public MCP `atoll_get_work_recommendations` with `view: project`. See [Actor work recommendations](/agents/work-recommendations) for execution-aware target inspection. ## Work recommendation fields The project `work-recommendations` REST response has: | Field | Meaning | | --- | --- | | `recommendations[].issue` | `id`, `number`, `title` (at most 240 Unicode characters), `status`, nullable `priority` and `due_date`, `created_at`, `updated_at` | | `action_kind` | `start`, `continue`, or `review_assignment`; not permission to execute | | `reasons` | At most three fixed-code explanations, each with `summary` (at most 300 characters) and one authorized source | | `limitations` | At most five deduplicated limitations, ordered by code and visible source ID; hidden context never includes type, identity, title, or count | | `limitations_truncated` | More visible limitations exist than the returned five | | `page` | `limit` (1–5), `has_more`, nullable `next_cursor` | | `evaluation` | `evaluated_at`, `eligible_count`, `excluded_count`, `primary_exclusion_reason_counts` across the entire bounded scan | Ranking reason codes: `urgent_blocked_downstream`, `overdue_milestone`, `current_kpi_relevance`, `explicit_strategy_link`, `issue_overdue`, `issue_due`, `issue_priority`. Each has `source_type` (`issue`, `milestone`, `initiative`, or `kpi`), `source_id`, optional `source_title`, and optional `source_as_of`. Limitation codes: `kpi_stale`, `kpi_current_unknown`, `strategy_link_absent`, `kpi_evidence_absent`, `linked_context_not_visible`, `assignment_requires_review`, `linked_context_unavailable`, `strategy_inactive`. A limitation may include one authorized source reference; missing or hidden sources have none. `linked_context_unavailable` applies only to visible downstream work with an absent or unconfigured recommendation workflow. Primary exclusion codes: `project_inactive`, `issue_archived`, `issue_cancelled`, `workflow_role_unconfigured`, `workflow_role_excluded`, `dependency_evidence_invalid`, `unresolved_dependency`. `due_date` is a valid `YYYY-MM-DD` UTC calendar date. Source timestamps are UTC; `evaluated_at` has canonical milliseconds and `Z`. KPI freshness uses elapsed hours and includes the exact staleness threshold. Null timestamps or current values are unknown. A future timestamp or malformed evidence fails the request. Cursors expire after 15 minutes, are limited to 2 KiB, and require a fresh read when expired. They do not freeze database state or authorize mutations. ## Agent capacity reconciliation Owners and admins can reconcile the shared agent allowance at the top of **Agents**. The total shows used slots and the finite limit, or **Unlimited**. The breakdown counts all normal agents and API-key integrations, regardless of search filters. If the counts differ from the billing total, **Inventory changed; refresh to reconcile** requires a fresh read. **Refresh inventory** reloads the inventory and capacity together. Personal agents remain in **Personal agents**. Your agent says **Inherits your project access**; another member's agent names its owner when available, with a neutral owner fallback for legacy records. A guest with no projects shows **No current project access** to admins and **No project access visible to you** to other members. Creator identity does not determine scope. The **API-key integrations** section lists names only. **Manage integrations** opens the existing **Settings > Integrations** controls. Revoke normal agents from their existing controls; a successful revoke reloads capacity and both inventories. Non-admins retain their manageable-agent view without capacity or integration inventory. `GET /api/orgs/{id}/agents/manageable` remains human-only. For organization owners/admins, each row adds `personal_owner: { id, display_name } | null`, resolved only from referenced human members in the same organization. Missing legacy owners return `null`. Other callers receive `personal_owner: null`. The top-level `capacity: { plan, usage, limit } | null` is admin-only and uses the same agent allowance check as creation with zero increment; `limit: null` means unlimited. Normal agents and API-key integrations both consume this allowance. Non-admin responses contain `capacity: null` and do not run owner or capacity queries. Failed owner, project, heartbeat, or capacity reads fail the response rather than return a partial reconciliation. Plan-limit database errors fail closed instead of becoming free-plan or zero-usage results. Manual Web references: Task/Project Context uses Add reference. REST and CLI external-reference link accept explicit external_document/document selectors. No content is fetched or verified. Context v1 and MCP creation remain provider-only; canonical reference list/get/unlink includes manual records. ## Agent lifecycle foundation Agent identities persist as enabled, disabled, or revoked. Human-only lifecycle administration uses POST /api/orgs/{id}/agents/{agentId}/lifecycle with action, expected_version, and idempotency_key. Disable preserves work history and capacity while invalidating credentials; enable needs fresh keys or OAuth consent and does not resume work. Revoke is terminal, cancels active execution/attention, retains historical identity, and releases capacity. Legacy DELETE remains a revoke adapter. Old runner lease versions and pending consent cannot regain authority. CLI/MCP have no lifecycle administration privilege. See https://docs.atollhq.com/agents/safety-and-permissions.md and https://docs.atollhq.com/troubleshooting/api-auth.md. ### Recurring task destination Create, update, and bulk create accept optional nullable `recurrenceSpawnColumnId` (or `recurrence_spawn_column_id`). Use a real column UUID from the project workflow. The column must belong to the task project and have a key other than `done` or `cancelled`. Omission preserves a saved target; new recurrence resolves the project default. Explicit `null` resets to `todo`, or the first eligible column by position and ID. A project with no eligible column rejects materialization. Projectless recurrence retains a null target. Disabling recurrence clears the stored target. Responses keep `recurrence_spawn_column_id` as the addressed row's stored value. `recurrence_spawn_owner` is null for ordinary tasks, an authorized `{state: "available", issue_id, project_id, spawn_column_id}` projection, or `{state: "unavailable"}` without owner IDs. Read access permits the projection; write access is checked independently. Target-only edits do not move the current task or reset its schedule. Root-owned child edits update the authorized root; send local status, title, assignment, and project edits separately. Moving a series root keeps historic children in their projects. Include a valid destination target with the project move, or omit it to resolve the new project's default atomically. The next task uses the series' current project and selected column even when an older occurrence is completed. A deliberate root move or root preference action establishes root ownership for legacy completion too; untouched legacy completion remains local. Completing a scheduled occurrence creates no immediate successor. The maintenance sweep materializes its next scheduled occurrence in the current series destination. Unreadable owners reveal no IDs; denied destination writes create no successor. Delete a referenced board column with independent `reassignTo` (issue statuses), `releaseReassignTo` (dependency release points), and `recurrenceReassignTo` (nonterminal recurrence targets) mappings. An eligible `reassignTo` is the compatibility fallback for recurring targets. Remaps and deletion are atomic. Explicit new-field requests fail with 503 while the additive migration is unavailable; ordinary requests retain compatibility. ### Recurrence and column deletion parity Both full/private and public plugin MCP expose optional completion recurrence `recurrence_type`, `recurrence_interval`, and nullable `recurrence_spawn_column_id` on `atoll_create_issue` and `atoll_update_issue`. Use only the fields exposed by the connected tool; this does not add scheduled recurrence inputs. Reads expose the addressed stored target and authorized owner projection. A target-only occurrence edit follows existing owner routing. `atoll_delete_board_column` is available in both profiles. It requires exact `confirmation: "DELETE"`, `project_id`, and `column_id`; optional `reassign_to`, `release_reassign_to`, and `recurrence_reassign_to` select the three independent reference destinations. Authorization remains the existing project edit/admin check. The tool is destructive and does not retry an uncertain write. On `core_write_uncertain`, use `atoll_get_project_workflow` and `atoll_get_issue` to reconcile the result before another intent. No provider write occurs. # Actor work recommendations ## Actor work recommendations `GET /api/orgs/{id}/work-recommendations` accepts optional `actor_id` (member UUID, defaults to the caller), `project_id`, `limit` (1–5, default 5), and `cursor`. Machines can read only their own recommendations. A human can inspect self, a manageable agent, or another human with shared write access. All issue and strategy evidence uses the intersection of caller and target permissions. Missing and forbidden targets both return `404`. The read evaluates the complete bounded authorized project scope before global ranking. It scans at most 1,000 source issues, 250 scope rows, 200 queries, 25,000 related physical rows, and 4,000 execution or assignment rows per category. Any exceeded ceiling returns `422 WORK_RECOMMENDATIONS_EVIDENCE_LIMIT` with no partial ranking. Current work is displayed separately, capped at 20 with `current_work_truncated`. Occupation checks remain complete. Any `assigned`, `running`, `waiting`, or `needs_human` execution for the target suppresses all new-work suggestions across the organization, including work outside the project filter and projectless work. Occupation uses immutable execution actor identity and current issue ownership. Hidden occupation yields only the generic `availability_not_established` caveat, with no hidden work identity, title, state, count, or timestamp. Authorized waiting and attention work has inspection actions. Failure inspection uses newest created-at/UUID display chronology across actors; it does not establish retry supersession or permission to dispatch. Succeeded and cancelled executions are terminal. `available_for_recommendation` permits eligible read suggestions in this snapshot. It never reserves an agent, claims runtime capacity, or authorizes execution. Revalidate with the canonical assignment and execution APIs before any write. A managed inactive agent returns only its authorized identity and lifecycle, `availability: inactive`, empty work, no cursor, `can_assign: false`, and `scope.project_id: null`. Former effective scope and work stay concealed. Actor cursors are signed, bound to caller, organization, actor kind, target, and project filter, and expire after 15 minutes. Each page rechecks current permissions and a fingerprint of ranking and execution evidence. Drift returns `409 WORK_RECOMMENDATIONS_CURSOR_STALE`; restart without a cursor. Invalid scope or signatures return `400 WORK_RECOMMENDATIONS_INPUT_INVALID`. `GET /api/orgs/{id}/work-recommendations/actors?project_id=` returns the bounded permitted enabled human/agent selector projection. It contains only `self_id` and `actors` with `id`, `display_name`, and `type`. Use `atoll work recommendations [--actor UUID] [--project UUID] --json`, `atoll work actors --project UUID --json`, or `atoll work project-recommendations --project UUID --json` for the existing project-wide ranking. Full and public MCP expose `atoll_get_work_recommendations` with `view: recommendations` (default), `actors`, or `project`. The selected MCP `profile_ref` stays the authenticated caller; selecting a target never changes that caller. These surfaces return the same server order and reasons.