Files
PaperClipAI/maps/agent-access-map/agents.md
T
DottaandClaude Opus 5.5 6383eb8033 fix(authz): require board authority for agent budget changes on every route (#20213)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - Budgets stop agent spending. The budget hard stop is a control-plane
invariant
> - The budget routes (`PATCH /api/agents/:id/budgets`, `PATCH
/api/companies/:id/budgets`) are board-only
> - `PATCH /api/agents/:id` also accepts `budgetMonthlyCents`, and the
configuration service writes the agent budget policy from it. That route
had no board check for the field
> - So an agent, such as a CEO, a manager or the agent itself, can
change a monthly budget without a board user. This is a second route
around a board-only control, like the pause bypass that #20164 fixed
> - This pull request applies the budget route authority to every route
that writes an agent budget, and gives agents the final board-only
denial with a link to the budget page (#20151)
> - The benefit is that only the board changes budgets, and an agent
that asks gets a final answer that it can pass to the person

## Linked Issues or Issue Description

Refs #17857 (earlier fix, now in conflict with master; this PR rebases
it and adds the budget page link). Refs #20164 and #20151 (same pattern
for PATCH status and board-only denials).

**What happened**

An agent can send `PATCH /api/agents/{id}` with `budgetMonthlyCents`.
The route accepts it, and the configuration service writes the agent
budget policy. This works for the agent's own budget and, with update
permission, for other agents. The same field also reaches budget policy
through a configuration rollback, direct agent creation, an immediate
hire and a built-in agent provision. A chat eval
(`budgets-costs.resolve-budget`) found the route.

**Expected behavior**

Only a board user can change an active budget, as on the dedicated
budget routes. An agent gets `403` with code `board_access_required`.
The denial says it is final and links the agent's budget tab
(`/<prefix>/agents/<id>/budgets`) or the company budgets page
(`/<prefix>/activity/budgets`). An agent can still propose a budget in a
hire that waits for board approval. The approving board user activates
it.

**Steps to reproduce**

1. On master, authenticate as an agent of a company (for example the
CEO).
2. Send `PATCH /api/agents/{agentId}` with body `{"budgetMonthlyCents":
5000}`, for its own id or for another agent.
3. See `200`. The agent budget policy changes with no board action.
4. The new route tests reproduce this: on master source they fail with
`expected 200 to be 403`.

## What Changed

- `PATCH /api/agents/:id`: a changed `budgetMonthlyCents` requires a
board actor. An unchanged amount with other edits still works.
- Configuration rollback: a rollback that changes the budget requires a
board actor.
- `POST /api/companies/:id/agents` and an immediate `agent-hires`: a
positive budget requires a board actor. A hire that needs board approval
keeps the proposed budget and does not activate it before approval.
- Built-in agent provision: a budget override requires a board actor.
- `prepareAgentConfiguration` rejects an agent-originated budget change
again (defense in depth). An agent rollback with an unchanged amount
does not rewrite the policy.
- Board writes keep the actual operator identity. The initial hire
budget is saved in the hire transaction.
- `assertBoard` and `boardAccessRequired` take an optional board page.
Budget denials link the agent's budget tab or the company budgets page,
not the general agent profile.
- Agent access map updated.
- This includes the four commits of #17857 (f970f6b01f, 8c06aba41c,
e5682d22fa, b6cd49d4b6), rebased onto master with the conflicts
resolved, then squashed.

## Verification

- Red on master source, same tests: 12 budget tests fail. The PATCH
tests fail with `expected 200 to be 403` for the agent's own budget and
for a CEO on another agent. Built-in provision fails with `expected 200
to be 403`. Creation and immediate hire fail with `expected 201 to be
403`.
- Green with the fix: `cd server && npx vitest run
src/__tests__/agent-permissions-routes.test.ts
src/__tests__/built-in-agent-routes.test.ts
src/__tests__/built-in-agents.test.ts
src/__tests__/agent-hire-idempotency-routes.test.ts
src/__tests__/board-access-denial.test.ts
src/__tests__/agent-budget-configuration.test.ts`: 222 passed.
- `src/modules/agent-lifecycle/__tests__/lifecycle.test.ts` (embedded
Postgres): 76 passed.
- `agent-skills-routes`, `agent-adapter-validation-routes`,
`openapi-routes`, `agent-cross-tenant-authz-routes`: 275 passed.
- `node scripts/check-maps.mjs`: passed. `git diff --check`: passed.
- Server `tsc --noEmit`: no errors in changed files. One error in
`native-session-executor.ts` comes from a linked runner build in the
local worktree, not from this change. CI runs the full typecheck.

## Risks

- Agent clients that set an active budget directly now get `403`. They
must propose the budget in an approval-gated hire, or ask a board user.
- Agent creation with no budget or a zero budget is not changed. Pending
hire budgets do not activate before approval.
- Trusted internal plugin provisioning keeps its prior behavior and gets
no board identity.
- No schema or migration change.

## Model Used

- Anthropic Claude Opus 5.5 (`claude-opus-5-5`), with tool use and code
execution, in Claude Code. The rebased commits from #17857 were first
written with OpenAI `gpt-6.1-sol` through Codex.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [ ] All Paperclip CI gates are green
- [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-09 02:50:16 -06:00

455 lines
28 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Hiring, agent configuration, and organization — agent access
Product map: [Hiring, agent configuration, and organization](../feature-map/agents.md).
Feature ID: `agents`.
Review date: 2026-10-12. Source commit: `58e16dbddfc9c8d0cf60867f9d9847f0feda055b`.
Native REST transport reconciled in this change; see the
[shared transport contract](README.md#native-rest-transport).
This is a source-reviewed baseline of representative operations and known gaps.
Each capability needs operation-level review before its entire scope can be
qualified. No live agent execution is claimed. Follow the [map contract](../README.md)
for format, permission checks, evidence and maintenance.
Scoped runner-default source review: 2026-10-12 at
`eee0534154eaf5d0d3f2bbc97c1e24d86f34a5a5`, limited to creation/configuration,
approval activation, built-in provisioning and import preservation described
below. The original baseline commit above still governs unrelated entries; this
update does not claim operation-complete review or live agent verification.
Native Cursor Cloud uses a server-derived `provider_api` placement after its
complete native profile is validated. Create/update with `runner: paperclip`
stores `defaultEnvironmentId: null`; the caller cannot supply placement, commands,
working directories or arbitrary environment values. Only the bound
`CURSOR_API_KEY` is passed to the qualified API proxy. Test does not acquire a
Computer lease. Finish setup uses the same validated placement and account check;
it does not inherit a default Computer or its warm-task lifecycle. Incomplete
held drafts stay inactive until the complete profile passes activation validation.
Task/run authority, company boundaries, budgets and per-turn callback scope remain enforced. Local Computer execution stays denied under
managed-sandbox-only policy. Verify the actual saved agent and live run; a board
Test result does not prove agent task-tool access.
On managed-only instances with native Runner enabled, a server-held Cursor setup
draft can resolve an automatic runner to the API controller before it has a
model. Unsaved automatic Test requests use the same advertised default and still
validate the full profile. Existing active Legacy agents and explicit Legacy
choices do not convert automatically. A client-supplied setup flag does not grant
draft status or bypass active model validation.
## `hire`
Capability ID: `agents/hire`.
Review: `baseline`.
API: `present` — representative operation IDs:
- `POST /api/companies/{companyId}/agent-hires`.
- `POST /api/companies/{companyId}/agents`.
Agent access: `partial` — Native hire_agent; REST / CLI agent; runtime inheritance for
native hires.
Creation requests can use `runner: auto | paperclip | legacy`; the server resolves
and persists execution configuration. Claude Auto selects the native ACPX profile
on qualified macOS and GNU/Linux x64/ARM64 targets; unknown environment
qualification remains Legacy. Darwin SSH defaults to Legacy while preserving
explicit native assets and saved execution. Saved runner/model/provider overrides survive edits
and approval activation. This selection does not grant connection access or
bypass hiring authorization. Source: [runner resolver](../../server/src/services/agent-runner-selection.ts).
Policy: Agent creation/configuration uses action grants, resource policies and change
consent; some controls require a board actor.
`agents:read` permits redacted configuration, configured skills, instruction content,
and configuration/instruction history reads. It does not permit changes, restore,
or environment probes. `agents:configure` still includes read/write authority;
`agents:suggest-changes` still includes reads and consented changes. Individual
reads use the target agent and honor target-scoped grants. Agents can read their
own redacted configuration and history without peer-read authority. Company-wide
configuration listings require company-wide read authority. Standard-agent read
defaults and the one-time existing-agent rollout are defined in
[agent permission defaults](../../doc/agent-permission-defaults.md).
The early wizard record (`setupId` on create) and completion of that record
(`setupAgentId` on hire) require a board actor and company-scoped creation
permission. Its creator can finish their own inactive setup with that permission;
changing another person's setup requires configuration permission.
Creation retries reuse only records owned by the caller. Returning a completed
record also requires the normal agent-read and configuration-read checks.
An unfinished record keeps compatibility status `paused` with a
`setup` hold and cannot receive API keys or authenticate with keys or JWTs.
Its standard grants apply at hire. Authorized completion retries recover the
same record and approval without changing the submitted configuration.
Normal agent-authored hiring keeps its existing approval policy. A pending hire may propose a budget, but only board approval activates that policy. Direct creation or an immediate hire with a positive budget requires a board actor.
An agent-owned plugin may prepare the draft and leave its lifecycle in
`verifying` while that setup hold remains. Only bounded Core-issued setup probes
can run there. The creator's company creation permission also covers configuring
and retrying their draft during preparation or stopping; other actors still require the
ordinary configuration permission. This is a board wizard path, not new agent
execution or probe authority. Lifecycle and component regressions cover these
transitions; no permitted-agent or live-provider journey is claimed here.
Companies requiring hire approval keep drafts paused and allocate no agent-owned
resource before approval. Selecting an account there is pending verification,
not approval or execution authority.
The board confirmation follows preparation and verification through the existing
foreground detail query before presenting readiness or enabling first-task
assignment. The handoff updates only an older cached roster record; it cannot
resume an explicit pause, clear an import hold or bypass approval.
The ordinary picker also exposes pending Google Antigravity configuration when
the native Runner adapter is available. This is a board configuration preview: selecting it
does not write native execution settings or remove the inactive draft's setup
hold. Non-secret draft metadata retains only the selected adapter/provider and
runner intent for display and resume; it cannot admit execution. Existing Google connection authorization governs credential setup and
account metadata; Test, hire completion and execution still require the normal
provider release gates. An isolated operator can authorize one company, exact
model and pinned local native candidate until a fixed expiry. Only company-local
adapter discovery projects its agent/model as a Candidate; it never returns the
launch descriptor or stores that authority on the agent. Server validation and
native launch independently enforce the trusted descriptor. The selected managed
home feeds a zero-turn native admission Test; uncertain cleanup returns a bounded
diagnostic and retains the credential home until physical retirement and refresh
handoff, then performs normal writeback. This exception leaves global release
qualification pending. UI discoverability grants no additional agent or probe
authority. Source: [picker](../../ui/src/components/new-agent/AgentBasicsDialog.tsx)
and [setup](../../ui/src/components/new-agent/NewAgentSetup.tsx). This scoped note
is source-only and does not claim a permitted-agent journey or live Antigravity
task acceptance.
The creation boundary resolves the request-level runner before adapter validation
and credential normalization. Omitted/automatic new Codex selection uses the
qualified target's default; explicit Legacy is retained. Disabled adapters and
external overrides affect new selection, while missing credentials/runtime or
incompatible settings remain errors. Existing agents and reviewed pending hires
retain their recorded execution. Native `hire_agent` explicitly inherits its
caller's runtime and remains subject to permission and credential restrictions;
it is not an arbitrary host-configuration or login tool. REST/CLI creation and
hire runner options use the [shared request contract](../../packages/shared/src/validators/agent.ts).
Evidence: `source-only` — [implementation](../../server/src/routes/agents.ts#L1395) at
the reviewed commit above.
Scoped Evidence: `source-only` — [creation policy](../../server/src/services/agent-hiring.ts),
[runner resolution](../../server/src/services/agent-runner-selection.ts),
[native hire binding](../../server/src/services/native-runtime/paperclip-runner-tool-authority.ts),
[frozen approval activation](../../server/src/modules/agent-lifecycle/adapters/approvals.ts)
and [same-harness import preservation](../../server/src/services/company-portability.ts)
at the scoped commit. No permitted-agent journey was executed for this map update.
The board-driven [Antigravity setup/task eval](../../tests/runner-e2e/ANTIGRAVITY-AGENT-JOURNEY.md)
creates its measured agent through the ordinary wizard and reuses only the
signed-in owner's existing personal default Google grant. Its observer may read
the owned records; it cannot seed the hire or manufacture readiness. This case
does not qualify agent-authored hiring, credential administration or a broader
agent permission boundary.
Verification: `not-run` — exercise a listed permitted operation with actual agent
credentials/run context; inspect its result and applicable persistence/attribution.
Assert the relevant denied actor, owner, company or mode from Policy. Review the
remaining operations before qualifying the whole capability.
For this scope, compare automatic and explicit Legacy creation, assert foreign
company/environment and missing-grant denials, then compare pending approval
configuration across restart and activation. An unrelated edit/import update must
not change existing execution; a new package without a runner choice receives
creation defaults. Do not count a board call or component test as agent evidence.
Gaps: Identity/persona hiring works. Operator account login and sensitive
adapter/environment configuration are separate guarded actions.
The runner request does not grant new account, environment-probe or native API
fallback authority; see [validation access](./runs-adapters.md#validation) and
[environment administration](./execution-environments.md#probe). Full access
qualification remains not run.
## `instructions`
The operator's Advanced YAML editor uses the existing configuration GET/PATCH
operations plus the owning instructions, skills, tools, channels, permissions,
secrets, API key, and revision APIs. It does not add aggregate write authority;
each request retains its own company and actor checks. Resource reads fail closed.
The compact YAML editor omits inherited access/history, company catalogs, and
instruction contents. Profile-key references resolve only within the company.
Omitted settings are preserved; named file patches use explicit null for deletion.
The normal domain APIs still enforce every write. Multi-resource writes are
sequential, with preflight comparison and explicit partial-failure recovery;
Core configuration, managed files, and entry revisions enforce their existing
atomic revision/hash preconditions. External supporting files and other
unversioned resource writes retain a race window after preflight. Configuration reads include the complete redacted, revisioned fields
and `configurationRevision`; writes accept an optional
`expectedConfigurationRevision`, checked again under the write lock. A stale
write returns `409`. Revision-guarded writes preserve unchanged redacted values
at their original paths. Configuration read/configure authority, company scope,
instruction-path restrictions, environment/account checks, revision history, and
activity attribution still apply. YAML does not expose a permission-grant or
lifecycle mutation shortcut. See [the format](../../doc/agent-configuration-yaml.md).
Capability ID: `agents/instructions`.
Review: `baseline`.
API: `present` — representative operation IDs:
- `GET /api/agents/{id}/instructions-bundle/file`.
- `GET /api/agents/{id}/project-access` and `POST /api/agents/{id}/project-access`
are board-only. The POST requires `agents:create`, checks selected projects in
the same company, and adds IDs under an agent row lock. It preserves existing
containment, audits new grants and rejects pending-approval agents. Agent keys
cannot use this route to grant themselves access; a read-only board viewer
receives `canManage: false`. Saving never creates a run or wakeup.
- `PUT /api/agents/{id}/instructions-bundle/file`.
- `PATCH /api/agents/{id}` with an explicit `runner: "paperclip"` upgrade.
- `POST /api/agents/{id}/qualify-runner` to qualify the saved effective sandbox before upgrading or testing an existing native runner.
- `PATCH /api/agents/{id}` with `runtimeSettings: { harness, model?, aiConnection?, expected: { model, aiConnection } }` for a narrow roster edit. Each request handles one agent; the UI batches at most four writes and collects per-agent outcomes.
Agent access: `available` — Native read/update/history/restore instruction tools; REST /
CLI.
Policy: Agent creation/configuration uses action grants, resource policies and change
consent; some controls require a board actor.
Changes to the legacy `budgetMonthlyCents` field and built-in provision budget overrides require a board actor, including budget-changing rollbacks.
The roster intent preserves unrelated settings, rejects stale model/connection
previews and harness changes, and checks the full execution configuration under
the lifecycle write lock. It uses the same configuration, company, credential,
environment, and consent checks as other edits. It adds no agent permission or
credential fallback. Pool and externally managed agents use their existing
configuration surfaces. Board browser verification does not qualify agent access.
Ordinary configuration PATCH requests with healthy installed AI accounts validate
current access, compatibility and environment selection without allocating a
computer or sending a provider prompt. Legacy-account adoption, task connection
adoption and Copilot model verification retain their live checks. Explicit Test
and execution keep runtime validation. This changes save latency and validation
timing; it grants no account, environment or execution authority. The isolated
PostgreSQL route fixtures in
[agent-configuration-save.test.ts](../../server/src/__tests__/agent-configuration-save.test.ts)
cover board saves and revoked-account rejection, not native-agent access.
The existing-agent upgrade notice for Claude, Codex, and Grok Build uses this configuration PATCH. It does not
grant configuration, account, or environment access. The server resolves the
saved settings under normal company/configuration authorization. Grok migration preserves
the effective legacy search setting. Task model/effort overrides retain the
agent's account binding and tool policy without granting extra account access. Obsolete Claude
tuning fields are removed with `configurationWarnings`; security incompatibilities
remain errors. Unqualified sandbox upgrades first use the agent-scoped
`POST /api/agents/{id}/qualify-runner` under the same `agent_config:update`
authorization as saving the upgrade. The server resolves the saved computer;
`expectedEnvironmentId` rejects stale state and cannot select another computer.
Qualification checks company binding, returns only its receipt, and audits within
the agent's company. General instance environment probes still require instance
admin. An existing native agent's clean configuration Test uses the same
saved-computer qualification before its runtime test. A current proof is reused;
a missing or stale proof requires a real successful probe and verified cleanup.
Draft settings and target changes do not qualify another computer. No probe runs
merely on page load. Operator browser evidence does not
qualify the agent permission paths for this operation.
Evidence: `source-only` — [implementation](../../server/src/routes/agents.ts#L1395) at
the reviewed commit above.
Verification: `not-run` — exercise a listed permitted operation with actual agent
credentials/run context; inspect its result and applicable persistence/attribution.
Assert the relevant denied actor, owner, company or mode from Policy. Review the
remaining operations before qualifying the whole capability.
Gaps: Canonical entry file, revision guard, company boundary, and protected-change
policy apply.
## `organization`
Capability ID: `agents/organization`.
Review: `baseline`.
API: `present` — representative operation IDs:
- `GET /api/companies/{companyId}/org`.
- `PATCH /api/agents/{id}`.
Agent access: `available` — list_agents/get_agent; native call_api for permitted
configuration fields; REST / CLI.
Policy: Agent creation/configuration uses action grants, resource policies and change
consent; some controls require a board actor.
Evidence: `source-only` — [implementation](../../server/src/routes/agents.ts#L1395) at
the reviewed commit above.
Verification: `not-run` — exercise a listed permitted operation with actual agent
credentials/run context; inspect its result and applicable persistence/attribution.
Assert the relevant denied actor, owner, company or mode from Policy. Review the
remaining operations before qualifying the whole capability.
Gaps: Reporting-line changes need configuration authorization; a title alone gives no
authority.
## `lifecycle`
Capability ID: `agents/lifecycle`.
Review: `baseline`.
API: `present` — representative operation IDs:
- `POST /api/agents/{id}/pause`.
- `POST /api/agents/{id}/resume`.
- `POST /api/agents/{id}/terminate`.
- `DELETE /api/agents/{id}` permanently purges an eligible terminated/rejected agent.
- `POST /api/agents/{id}/lifecycle/retry`.
- `GET /api/agents/{id}` returns the safe failed phase/step and action in `lifecycleError`.
Agent access: `partial` — REST / native `call_api` resume under agent_config:update
change-grant authorization; pause and termination remain board-only.
Policy: Agent creation/configuration uses action grants, resource policies and change
consent; some controls require a board actor.
Permanent deletion is board-only. Retained case handoff references return
`409 agent_case_history_retained` before dependency cleanup; keep the agent terminated.
Failed configuration verification waits for a changed execution configuration
or an authorized explicit retry. That wait does not grant an agent permission
to retry itself, resume execution, or change configuration. Temporary verification
outages retain automatic recovery.
Evidence: `source-only` — [implementation](../../server/src/routes/agents.ts#L1395) at
the reviewed commit above.
Verification: `not-run` — exercise a listed permitted operation with actual agent
credentials/run context; inspect its result and applicable persistence/attribution.
Assert the relevant denied actor, owner, company or mode from Policy. Review the
remaining operations before qualifying the whole capability.
Gaps: Resume has a generic native REST path. Pause and termination remain
enforced actor restrictions.
## `built-in`
Capability ID: `agents/built-in`.
Review: `baseline`.
API: `present` — representative operation IDs:
- `POST /api/companies/{companyId}/built-in-agents/{key}/provision`.
Agent access: `partial` — REST / native fallback for eligible provisioning; built-in
routine controls require board.
Policy: Agent creation/configuration uses action grants, resource policies and change
consent; some controls require a board actor.
Evidence: `source-only` — [implementation](../../server/src/routes/agents.ts#L1395) at
the reviewed commit above.
Verification: `not-run` — exercise a listed permitted operation with actual agent
credentials/run context; inspect its result and applicable persistence/attribution.
Assert the relevant denied actor, owner, company or mode from Policy. Review the
remaining operations before qualifying the whole capability.
Gaps: Provisioning checks agents:create. Enabling/running its built-in routine is not
the same permission path.
Scoped source review: [built-in provisioning](../../server/src/services/built-in-agents.ts)
recognizes the underlying Codex harness of a native company agent. New configured
provisioning resolves the runner, while unrelated reconciliation and same-harness
edits retain existing execution. Verify explicit runner changes preserve compatible
saved settings; the general creation/access policy above still applies. This is
source-only evidence at the scoped commit, not a live provisioning result.
## `primary-agent`
Capability ID: `agents/primary-agent`.
Review: `baseline`.
API: `present` — GET and PUT /api/companies/{companyId}/primary-agent/me.
Agent access: `restricted` — this is the authenticated human's personal
preference. Agent keys and native call_api use agent identity and are denied by
the board gate; no dedicated agent selection tool is present. Native API discovery
directs the person to the chosen agent's profile/crown control and replacement
confirmation; it does not impersonate the person's session or turn the Chat
picker into a preference control.
Policy: Requires board user identity, company access and active membership,
except implicit-local board or instance administrator. Viewers may choose their
own primary. Selection requires a same-company readable, available agent and
is scoped to actor user ID; the request cannot select another user's preference.
Explicit null selection is rejected; leave/termination can clear an unavailable
choice. Initialization stays recorded so clearing does not silently replace it.
Evidence: `source-only` — reviewed on 2026-10-13 at
`60bc0d5fee9a6e48db08fc016521fee3d9f57d67`:
[routes](../../server/src/routes/primary-agent.ts),
[service](../../server/src/services/primary-agent.ts),
[provider](../../ui/src/context/PrimaryAgentProvider.tsx), and
[route tests](../../server/src/__tests__/primary-agent.test.ts).
Verification: `not-run` — select and read the preference as two company users;
assert isolation, wrong-company/unreadable targets, pending/terminated agent
rejection and agent-key denial. Verify replacement confirmation and fallback
precedence in the UI; inspect the cleared state after permitted leave/termination.
Gaps: No agent mutation path for another person's preference. Live human/agent
access is unverified; UI fixture callbacks do not establish persistence or task
and Chat default resolution.
## `grok-bot`
Capability ID: `agents/grok-bot`.
Review: `baseline`.
API: `present` — `POST /api/companies/{companyId}/grok-invitations`, operator-owned Grok invitations and agent-scoped `/grok-binding` setup, routine, verify, stop, recover and disconnect endpoints. Direct HTTPS `/mcp/runner` uses fixed named-agent OAuth. Grok tools expose durable assignment operations and task-bound upload/download grants.
Agent access: `available` — `paperclip_grok_*` through the dedicated agent grant. First-party Paperclip operations execute through the shared Rust Runner. The Bot retains its own apps; Paperclip workspace and third-party app tools are unavailable.
Policy: company/agent/client/resource/authorizer binding; current manage-agent permission for consent and subsequent calls; normal task ownership, controller lease, governance, pause, revocation and recorded budget checks. Execution and file transfers require current task-bound sessions. Secret credentials remain in encrypted secret storage and are redacted from HTTP logs.
Evidence: `source-only` — [routes](../../server/src/routes/grok-bot.ts), [shared authority](../../server/src/services/external-bot-authority.ts), [routine receipts](../../server/src/services/grok-bot/routine.ts) and [Runner broker](../../server/src/services/dot-runner-broker.ts). Temporary actual-client OAuth and an outbound routine wake are qualified separately; they do not prove this candidate’s acceptance.
Verification: `not-run` — deployed acceptance pending; focused protocol/authorization and actual Rust backend tests; run fresh/saved setup, assigned and proactive tasks, duplicate calls, stale sessions, restart, ambiguous delivery, stop and recovery through the real client on the serving managed candidate.
Gaps: deployed two-way work and unattended first-time onboarding remain unqualified; remote termination, provider transcript streaming and usage accounting are unavailable.
## `api-keys`
Capability ID: `agents/api-keys`.
Review: `baseline`.
API: `present` — GET /api/agents/{id}/keys; POST /api/agents/{id}/keys; DELETE /api/agents/{id}/keys/{keyId}.
Agent access: `restricted` — key listing and mutations require board identity and agent-management authority. The CLI token agent commands use authorized board context. Ordinary agent REST/native `call_api` and public assistant capabilities do not grant key-management authority.
Policy: getAccessibleAgent checks company access and agents:create through the shared access evaluator for reads as well as mutations. Creation rejects pending_approval and terminated agents. Keys retain the creating person’s responsibleUserId; only a hash is stored and token plaintext is returned on creation. Revocation checks that the key belongs to the selected agent. Authentication separately applies agent state, revocation, scope, and responsible-user membership intersections.
Evidence: `source-only` — reviewed at `9ef434fe79c57d976b8b03b14c5242db270b8320`. [Keys tab](../../ui/src/pages/AgentDetail.tsx), [key routes](../../server/src/routes/agents.ts), [key service](../../server/src/services/agents.ts), [authentication](../../server/src/middleware/auth.ts), and [CLI token commands](../../cli/src/commands/client/token.ts).
Verification: `not-run` — Create a disposable key as a permitted authenticated board person, prove one harmless agent read, revoke, and retry the same bearer. Assert metadata persistence, once-only token display, activity, missing management permission, agent identity denial, cross-company/cross-agent IDs, ineligible targets, and missing responsible-user binding.
Gaps: Local implicit key creation does not by itself prove a usable responsible-user binding. No ordinary-agent self-management or assistant delegation path is established; browser creation and actual bearer use need live evidence.
## `managed-agent-setup`
Capability ID: `agents/managed-agent-setup`.
Review: `baseline`.
API: `present` — GET and POST /api/companies/{companyId}/managed-agent-profiles. Provisioning separately calls Anthropic /v1/environments, /v1/agents, and /v1/agents/{id}/versions with operator provider credentials; --probe does not resolve a Paperclip client context or call the profile API.
Agent access: `operator-only` — provider qualification/provisioning uses the explicit operator CLI. Persisted profile reads/writes require board/company identity; viewer writes are denied. This does not authorize a company agent to provision external provider resources.
Policy: A profile uses an active same-company, company-scoped secret reference. Qualification requires the source-supported pinned model/version, no tools/MCP/skills/multiagent capability, and a locked no-network/no-packages environment with retention acknowledgement. Qualified configuration revisions are immutable; changed qualified configuration requires a new profile key. Provider API credentials and Paperclip profile authority are separate checks.
Evidence: `source-only` — reviewed at `9ef434fe79c57d976b8b03b14c5242db270b8320`. [Managed-agent CLI](../../cli/src/commands/managed-agent.ts), [profile routes](../../server/src/routes/managed-agent-profiles.ts), [profile service](../../server/src/services/managed-agent-profiles.ts), and [runtime validation](./runs-adapters.md).
Verification: `not-run` — Compare provider and Paperclip state before/after probe, then inspect a permitted create/adopt and repeated resource reuse. Reject missing acknowledgement, unsafe resources, invalid model/version/secret/company, and viewer/agent mutations. Separately run a bounded useful task with the saved qualified profile before claiming runtime readiness.
Gaps: This is a provider-specific setup path, not qualification of every managed service or deployed environment. Mocked setup and source validation do not prove live retention, remote execution, or provider availability.