Merge branch 'codex/claude-runner-default' into codex/claude-runner-platforms

* codex/claude-runner-default:
  fix(adapter-utils): preserve SSH command positional arguments
  feat(runner): qualify native Codex platforms and cache hosted builds
  docs: establish paired feature and agent access maps (#16025)
  fix: retain matching-host runner development overrides
  fix(acpx): record turn activity at the moment a stop fires (#15962)
  refactor(chat): extract channel status, receipts, drafts and authority workflows (#15995)
  fix: preserve saved setup and match sandbox runner targets
  feat: add portable verification skills and refresh the feature map (#15983)
This commit is contained in:
Dotta committed 2026-10-12 15:29:24 -05:00
commit 02ad4267d4
120 files changed
+11143 -3797

No files matched your search

@@ -0,0 +1,47 @@
# create-verification-skill attribution
This skill comes from Paperclip's portable pstack fork in
`paperclipai/agent-plugins`, commit
`410257663e0b344df656e604f1601aa1db95f7e4`, under `vendor/pstack/`.
The fork imported pstack 0.15.15 by Lauren Tan (poteto) from
[cursor/plugins](https://github.com/cursor/plugins/tree/ccb5507cec1546dc88135c1139c811e6c59115ba/pstack),
upstream revision `ccb5507cec1546dc88135c1139c811e6c59115ba`.
Paperclip adapts the workflow to the sibling `maps/feature-map/` and
`maps/agent-access-map/` directories and their shared access contract.
It preserves the invocation policy in `agents/openai.yaml`, removes the
Cursor-specific `disable-model-invocation` frontmatter field, and omits the
separate runtime skill dependency because Paperclip supplies execution.
No upstream Cursor built-in skills are redistributed.
The imported resources include `SKILL.md`, `agents/openai.yaml`, and all three
files in `references/feature-map-example/`. Keep those examples with the skill
when copying or refreshing it.
## License
The original license is reproduced verbatim below.
```text
MIT License
Copyright (c) 2026 Lauren Tan
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
```
@@ -0,0 +1,57 @@
---
name: create-verification-skill
description: "Generate a project-local verification skill that drives your app the way a user does — any language, framework, or platform. Use for /create-verification-skill, \"make a control skill for this repo\", or when a project has no scripted way to prove UI/CLI/service behavior."
---
# Create a verification skill
Every serious project needs a scripted way to drive the real app and prove behavior: launch it, exercise a feature the way a user would, and capture evidence. This skill generates that as a project-local skill (`.agents/skills/verify-<app>/`) tailored to the repo. You write the generator's output for the next agent, not for a human: it will be read cold, mid-task, by an agent that has never seen the app.
## 1. Interview the repo, not the user
Answer these from the codebase and only ask the user what you cannot observe:
- **Surface:** what does a user actually touch? A web UI, a CLI/TUI, a desktop app, an API, a mobile app, a library? A repo can have several; pick the primary one and note the rest.
- **Run:** how does the app start locally? Prefer the repo's own documented dev command (package scripts, Makefile, README quickstart). Note ports, env vars, seed data, auth.
- **Drive:** how can an agent interact with it programmatically? Existing harnesses first — Playwright/Cypress specs, expect scripts, PTY helpers, curl-able endpoints, a debug port. Only then pick a generic recipe: browser/CDP for web and Electron, a tmux/PTY harness for CLI/TUI, plain HTTP for services.
- **Observe:** what evidence can be captured? Screenshots, terminal transcripts, response bodies, logs, exit codes, DB state.
- **Isolate:** can two instances run side by side (ports, data dirs, profiles)? If not, say so in the generated skill: refusing to double-drive a shared instance beats corrupting the user's session.
If the checkout doesn't build or start as-is, fix that first (or report it precisely) before generating; a skill written against a broken base teaches wrong steps. When an irrelevant missing asset blocks startup (a static dir the API never serves, a sample config), the generated skill may create it, clearly marked as verification scaffolding, and remove it in cleanup.
## 2. Generate the skill
Write `.agents/skills/verify-<app>/SKILL.md` with YAML frontmatter (`name: verify-<app>` and a `description` that names the app, the surface, and when to reach for it — without frontmatter the skill never registers) and these sections, each grounded in what the interview actually found (no placeholders left):
- **Launch:** the exact command that starts the app for verification, and how to tell it's ready (a log line, a port answering, a prompt). Include teardown. For a short-lived CLI or TUI there is no server to keep alive: launch means build the binary (or install deps) once, then start each drive in its own isolated PTY or tmux session.
- **Doctor:** one read-only check that answers "is this instance worth driving?" — process up, right version/build, port owned by us, auth valid. An agent runs this first whenever anything looks off.
- **Drive:** the harness recipe with real selectors/commands from this repo, not examples. Prefer stable handles (ARIA labels, data attributes, prompt strings, route paths) over coordinates and tab order.
- **Evidence:** what to capture for a proof and where it goes. State the proof standards: exercise the real user path, not internal setters or test-only endpoints; capture the action and the resulting state, not just the final screen; verify side effects (files written, rows inserted, messages sent) alongside what's visible; mocks only where a production boundary already isolates the external system. When the safe path is a dry-run or test mode, verify what it actually skips by observing (files, network, git refs) rather than trusting its name: some dry-runs still touch the network or open a browser.
- **Cleanup:** how to tear down instances the run created. Never kill by process name; kill what you started. Cleanup removes instances and scratch state, never the evidence: proof artifacts survive the teardown, in a location the skill names.
- **Helpers:** any script the skill ships is executable and its invocation is shown in the skill body. A helper the reader has to reverse-engineer is not a helper.
## 3. Seed the feature map
For Paperclip, read the [map contract](../../../maps/README.md) and use the sibling
`maps/feature-map/` and `maps/agent-access-map/` directories. The generated
verification skill consumes both maps and reports drift; maintenance owns their
updates. Reuse existing feature files and preserve Poteto's product format. Every
new feature file needs a same-named agent access companion with matching stable
sub-feature IDs. Record APIs, actual agent entry points, policy, evidence and gaps
using the contract. Mark representative source inventory as `baseline` /
`source-only`; enumerate operations before claiming full access coverage. Reuse
Paperclip's APIs, admitted tools and existing verification infrastructure. Run
`node scripts/check-maps.mjs` after map changes. Do not create maps inside a skill
directory or generate a second runtime.
For other projects, create `.agents/skills/verify-<app>/features/README.md` plus one file per user-facing feature you can identify (aim for the top 3-5 to start, from routes, commands, menus, or docs). Follow the shape in [`references/feature-map-example/`](references/feature-map-example/), with a README index and one file per feature. Each file answers, from the user's point of view: what the feature is, how to reach it, how to drive it with the harness, and what observable end state proves it works. The four H2s are `Sub-features`, `How to get to it (user POV)`, `Driving it with <harness>`, and `Gotchas`. The map is the repo's maintained verification source; a proof that drives one convenient entry point is incomplete when the map lists others.
## 4. Prove the generated skill before handing it over
Run its own instructions end to end once: launch, doctor, drive ONE mapped feature (one is enough; the map exists so later runs can cover the rest), capture evidence, clean up. After cleanup, confirm the evidence still exists at the named location — a cleanup that eats the proof fails this step. Fix what fails, and run the generated cleanup after every failed iteration too, so broken attempts don't strand processes and ports. A generated skill that was never executed is a draft, not a deliverable.
## 5. Offer the maintenance loop
Point the user at `/maintain-verification-skill` for keeping the map honest as the app changes. Suggest a cadence only if they ask.
Origin and license: [NOTICE.md](NOTICE.md).
@@ -0,0 +1,2 @@
policy:
allow_implicit_invocation: false
@@ -0,0 +1,47 @@
# Notes verification map
This directory is the maintained source for verifying the user-facing behavior of Notes. Read the index before driving the app, then use the matching feature file as the recipe.
## Baseline preconditions
- Launch Notes at `http://127.0.0.1:4173` with a disposable data directory.
- Set `NOTES_DATA_DIR=/tmp/notes-verify-$RUN_ID` so concurrent runs do not share state.
- Seed notes titled `Quarterly plan` and `Grocery list`.
- Put `control-notes` and the `notes` CLI on `PATH`.
- Run `control-notes doctor` and require the expected URL, data directory, and build revision.
- Never drive an instance that was not started by this verification run.
## Driving conventions
- Start every recipe from the baseline state unless its preconditions say otherwise.
- Prefer ARIA roles and accessible names over CSS selectors or DOM position.
- Treat every command as literal. Keep quoted names and flags unchanged.
- Run browser actions through `control-notes browser`.
- Run terminal actions through `control-notes cli -- <command>`.
- Restore seeded data after a mutation. Do not remove proof artifacts during cleanup.
## Proof and skip reporting
- Capture the user action and the resulting state, not only the final screen.
- UI proof includes an ARIA snapshot and a screenshot with the app identity visible.
- CLI proof includes the command, stdout, stderr, and exit code.
- Mutation proof includes a read-only second view of the stored value.
- Record the feature ID and entry point used with every artifact.
- Report an unreachable path with the attempted command and the unmet precondition.
- Do not report a skipped entry point as verified through a different path.
## Feature entry contract
Each feature file starts with an H1 title and one paragraph describing the user-visible behavior. It then uses exactly four H2 sections in this order.
1. `Sub-features` lists short IDs with one line for each behavior.
2. `How to get to it (user POV)` lists every user entry point.
3. `Driving it with <harness>` starts with `Preconditions:` and uses labeled bullets that pair each user action with an exact command and observable result.
4. `Gotchas` lists traps that can waste or invalidate a verification run.
Keep implementation details out of the map. Name only user paths, stable handles, required state, commands, and observable proof.
## Features
- [Create a note](./create-note.md) covers browser and CLI creation, cancellation, persistence, and cleanup.
- [Search notes](./search.md) covers toolbar, keyboard, and CLI search with matching, empty, and clear states.
@@ -0,0 +1,39 @@
# Create a note
Create note lets a user save a titled note from the browser or CLI, cancel an unfinished draft, and confirm the saved note from a second user-facing view.
## Sub-features
- `create-open` opens a blank editor from each browser entry point.
- `create-save` persists a title and body.
- `create-cancel` discards an unfinished browser draft.
- `create-cli` creates the same note shape from the terminal.
## How to get to it (user POV)
- Choose the `New note` button in the browser toolbar.
- Press `n` in the browser while focus is outside an editable field.
- Run `notes create --title <title> --body <body>` in a terminal.
## Driving it with control-notes
Preconditions:
- Notes is healthy at `http://127.0.0.1:4173`.
- No note is titled `Release checklist`.
- `control-notes doctor` reports the expected URL and disposable data directory.
- **Open editor.** Choose `New note`. Run `control-notes browser click --role button --name "New note"`. A form named `Note editor` appears with focus in the `Title` textbox.
- **Enter content.** Type the title and body. Run `control-notes browser fill --role textbox --name "Title" --value "Release checklist"` and `control-notes browser fill --role textbox --name "Body" --value "Tag and publish"`. The `Save note` button becomes enabled.
- **Save note.** Choose `Save note`. Run `control-notes browser click --role button --name "Save note"`. A status named `Note saved` appears and the heading reads `Release checklist`.
- **Confirm persistence.** Return to the note list and reopen the note. Run `control-notes browser click --role link --name "All notes"` and `control-notes browser click --role link --name "Release checklist"`. The editor shows both saved values.
- **Cancel draft.** Open a new note, enter `Discard me`, and choose `Cancel`. Run `control-notes browser click --role button --name "New note"`, `control-notes browser fill --role textbox --name "Title" --value "Discard me"`, and `control-notes browser click --role button --name "Cancel"`. The note list returns and has no `Discard me` link.
- **CLI entry.** Create a second note. Run `control-notes cli -- notes create --title "CLI note" --body "Created from terminal" --format json`. Exit code `0` and stdout contain the new note ID and title.
- **Proof.** Reopen both saved notes from `All notes`. Run `control-notes browser snapshot --aria --path artifacts/create-note/list.aria.txt` and `control-notes browser screenshot --path artifacts/create-note/list.png`. The artifacts show `Release checklist` and `CLI note`.
## Gotchas
- Pressing `n` while a textbox has focus types the character instead of opening a new editor.
- Titles are trimmed on save. Assert the rendered title, not the draft input value.
- A save status alone is insufficient proof. Reopen the note from the list.
- Remove `Release checklist` and `CLI note` during fixture cleanup, but retain their proof artifacts.
@@ -0,0 +1,45 @@
# Search notes
Search lets a user find notes by title or body text, inspect a matching note, and distinguish no matches from an unavailable search.
## Sub-features
- `search-open` opens search from each supported browser entry point.
- `search-match` returns title and body matches without changing note data.
- `search-open-result` opens a result in the note editor.
- `search-empty` shows a complete empty state for a query with no matches.
- `search-clear` removes the query and restores the recent-notes view.
- `search-cli` returns the same matching notes from the terminal.
## How to get to it (user POV)
- Choose the `Search` button in the browser toolbar.
- Press `/` in the browser while focus is outside an editable field.
- Run `notes search <query>` in a terminal.
## Driving it with control-notes
Preconditions:
- Notes is healthy at `http://127.0.0.1:4173`.
- The disposable data directory contains `Quarterly plan` with body text `Draft budget`.
- `control-notes doctor` reports the expected URL and data directory.
- **Toolbar entry.** Choose the `Search` button. Run `control-notes browser click --role button --name "Search"`. A dialog named `Search notes` appears with focus in its searchbox.
- **Keyboard entry.** Close the dialog, focus the page, and press `/`. Run `control-notes browser press --key "/"`. The same dialog appears and the page does not insert a slash.
- **Title match.** Type `quarterly`. Run `control-notes browser fill --role searchbox --name "Search notes" --value "quarterly"`. The `Search results` list contains `Quarterly plan` and does not contain `Grocery list`.
- **Body match.** Replace the query with `budget`. Run `control-notes browser fill --role searchbox --name "Search notes" --value "budget"`. The result `Quarterly plan` remains visible with a body-match excerpt.
- **Open result.** Choose `Quarterly plan`. Run `control-notes browser click --role link --name "Quarterly plan"`. The dialog closes and the editor heading reads `Quarterly plan`.
- **Empty state.** Reopen search and enter `volcano`. Run `control-notes browser fill --role searchbox --name "Search notes" --value "volcano"`. A status named `No matching notes` appears after search completes.
- **Clear query.** Choose `Clear search`. Run `control-notes browser click --role button --name "Clear search"`. The searchbox is empty and the `Recent notes` region replaces the result list.
- **CLI match.** Search from the terminal. Run `control-notes cli -- notes search "quarterly" --format json`. Exit code `0` and stdout contain one object whose title is `Quarterly plan`.
- **CLI miss.** Search for an absent value. Run `control-notes cli -- notes search "volcano" --format json`. Exit code `0` and stdout are `[]`.
- **Proof.** Capture the populated result state. Run `control-notes browser snapshot --aria --path artifacts/search/results.aria.txt` and `control-notes browser screenshot --path artifacts/search/results.png`. Both artifacts identify Notes, the query, and `Quarterly plan`.
## Gotchas
- Pressing `/` while the editor or searchbox has focus inserts text instead of opening search.
- Results update after a short debounce. Wait for the results list or empty status, not a fixed sleep.
- Archived notes are excluded unless the user enables `Include archived`.
- The CLI defaults to human-readable output. Use `--format json` for stable assertions.
- Opening a result changes browser state. Reopen search before proving another query.
@@ -0,0 +1,47 @@
# maintain-verification-skill attribution
This skill comes from Paperclip's portable pstack fork in
`paperclipai/agent-plugins`, commit
`410257663e0b344df656e604f1601aa1db95f7e4`, under `vendor/pstack/`.
The fork imported pstack 0.15.15 by Lauren Tan (poteto) from
[cursor/plugins](https://github.com/cursor/plugins/tree/ccb5507cec1546dc88135c1139c811e6c59115ba/pstack),
upstream revision `ccb5507cec1546dc88135c1139c811e6c59115ba`.
Paperclip adapts the workflow to the sibling `maps/feature-map/` and
`maps/agent-access-map/` directories and their shared access contract.
It preserves the invocation policy in `agents/openai.yaml`, removes the
Cursor-specific `disable-model-invocation` frontmatter field, and omits the
separate runtime skill dependency because Paperclip supplies execution.
No upstream Cursor built-in skills are redistributed.
The imported resources include `SKILL.md` and `agents/openai.yaml`.
The workflow uses the examples shipped with
[`create-verification-skill`](../create-verification-skill/references/feature-map-example/).
## License
The original license is reproduced verbatim below.
```text
MIT License
Copyright (c) 2026 Lauren Tan
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
```
@@ -0,0 +1,124 @@
---
name: maintain-verification-skill
description: "Keep a project's verification skill and product/agent access maps aligned with current source and real evidence. Use for /maintain-verification-skill, auditing the verify skill, or reconciling feature and agent access coverage."
---
# Maintain a verification skill and its maps
Keep user journeys and agent access aligned with the app. For Paperclip, read the
[map contract](../../../maps/README.md), the
[feature index](../../../maps/feature-map/README.md), and the
[agent access index](../../../maps/agent-access-map/README.md). These are sibling
maps under `maps/`, with the same area filenames and capability IDs. Preserve
[Poteto's product format](../create-verification-skill/references/feature-map-example/).
Agent companions follow the shared contract; they do not duplicate user recipes.
An API endpoint, an OpenAPI actor label, a declared scenario tool and an admitted
production agent path are different evidence. Verify which permitted agent
surface can actually express an operation. Track source review, operation review
and executed proof separately. A source-only baseline is useful, but cannot
certify complete coverage or live behavior.
## Outcomes
Pick one and report source scope, live scope and remaining gaps separately:
- **clean** — the requested scope got source and live coverage, with no corrections.
- **changed** — proven skill/map/check corrections are ready to review; name any
access gaps or unexecuted coverage that remains.
- **blocked** — requested coverage or a proven correction could not finish; name
the unmet prerequisite and evidence captured so far.
A targeted audit covers its named areas; do not present it as a full pass. A full
pass reads every area from source and exercises every reachable feature, plus
relevant permitted-agent and denial paths. Report unreachable prerequisites and
not-run operations rather than silently reducing the scope.
## Edit scope
For Paperclip, edit the target verification skill, these maintenance instructions
when needed, `maps/`, and the map-specific structural check
`scripts/check-maps.mjs` / `scripts/check-maps.test.mjs`. Fix references to those
maps in contributor docs or skill instructions when their locations/IDs change.
Keep the maps in `maps/{feature-map,agent-access-map}/`, outside skill directories.
For other projects, maintain their existing verification skill and map locations;
the Paperclip directory convention does not authorize relocating another repo.
Never edit product APIs, permission enforcement, tool bindings or UI behavior
in a maintenance run. Record product/access gaps for implementation separately;
a permission denial is not authorization to widen access.
## Pass
0. **Locate the target and scope.** Find the project-local verification skill
(usually `.agents/skills/verify-*/`). Several candidates: ask which; none:
point to `/create-verification-skill`. Honor a requested narrower audit.
Record the source commit and the last review for affected map entries.
1. **Check both indexes.** Pair same-named feature and agent files, then match
stable sub-feature IDs. Fix orphan/missing entries and broken references.
For Paperclip run `node scripts/check-maps.mjs`. This checks structure,
not API authorization, real tool bindings or live behavior.
2. **Source wave.** Use read-only subagents per area, with each reader owning
the feature file and its access companion; schedule within available slots.
Readers never edit or drive the app. Each returns the user capability/source
entry points, likely drift with citations, meaningful operations, their APIs,
actor/grant/resource/run/mode boundaries, real agent entry points by surface,
missing access/discovery/policy decisions, and a concise verification recipe.
Follow recent changes to routes, contracts, authorization, native tool
admission, CLI and MCP as well as UI. Inspect actual route/service policy;
compare it with OpenAPI and production bindings, not only scenario catalogs.
3. **Reconcile both maps.** Spot-check cited drift and merge recipes into as
few app states as practical. Every affected business operation needs an API
and a permitted agent path, or an explicit gap. A dedicated tool is optional
when existing API/CLI/MCP fallback suffices. Distinguish native/remote access
from legacy REST and personal assistant OAuth. Record field/scope limits,
unavailable clients, protocol requirements and native fallback restrictions.
Keep justified local/developer/operator exceptions, but split shared data
operations from presentation. A board-only route records a restriction and
any existing request/result handoff; an unresolved delegation question stays
visible. Split broad baselines into per-operation records before marking
them operation-reviewed. Add newly discovered capabilities only with concrete
source; add their companion at the same time.
4. **Live pass.** Required for a verification maintenance pass even if source
looks clean. The coordinator owns serial driving, using the target skill's
existing launch/doctor/evidence/cleanup workflow and Paperclip's existing
API/runner/MCP fixtures. Exercise the real user path and the relevant actual
agent path separately. For access checks use the permitted agent identity,
run, mode and target; assert results and relevant denials. A board request or
board test-as-agent does not replace agent-credential proof. Use disposable
fixtures for mutation/denial tests and record simulated providers honestly.
Never assume an optional client is admitted to a native run.
Keep three invariants: health-check before driving and after surprises;
verify captured evidence survives cleanup; clean up everything the drive
owned once no longer needed. Reset a wedged UI even if process health passes.
Follow the target skill's session model: one long-lived owned server/UI
instance, or isolated short-lived CLI sessions. After a skill-induced failure,
fix within edit scope and retry once, restarting only what was invalidated.
Record missing auth/provider/environment prerequisites and attempted paths.
Re-drive changed harness helpers before shipping them. Final teardown follows
the last proof attempt and preserves evidence.
5. **Triage and record.** User description/recipe drift updates the product map;
endpoint/path/permission/discovery drift updates its companion. Missing or
broken product behavior stays a product gap, with evidence. Never rewrite a
recipe or mark an access exception to bless a failure. Map evidence states
remain source-only/not-run unless an actual proof supports the named operation
and surface. Keep run artifacts/results in the evidence location or issue;
`maps/feature-map/coverage.json` remains documentation scope.
6. **Review corrections.** Re-read changed files, check paired IDs/references and
run the smallest relevant validation. Report outcome and source/live coverage
honestly. If shipping is requested or already authorized, update the existing
task PR where appropriate, or create at most one PR of proven corrections.
A clean pass needs no branch or PR. Do not implement access-policy changes
merely to make the maintenance report green.
Keep concise run notes and proof artifacts in the target skill's named evidence
location; do not commit ephemeral run logs as map content.
Origin and license: [NOTICE.md](NOTICE.md).
@@ -0,0 +1,2 @@
policy:
allow_implicit_invocation: false
+170
View File
@@ -0,0 +1,170 @@
---
name: verify-paperclip
description: Launch an isolated Paperclip instance, drive its real web UI or CLI using the existing feature-map recipes, capture evidence, and clean up owned processes. Use to verify user-facing Paperclip behavior.
---
# Verify Paperclip
Read the [map contract](../../../maps/README.md), then use the
[feature map](../../../maps/feature-map/README.md) to select user verification
recipes. For API/agent access, read the same-named
[agent access companion](../../../maps/agent-access-map/README.md) and use the
actual permitted agent identity, target and work mode. Follow existing API/runner/MCP
fixtures for access proof; a board request does not prove agent access. Report
recipe or access drift with evidence; map updates belong to
[maintain-verification-skill](../maintain-verification-skill/SKILL.md).
Read [development instructions](../../../doc/DEVELOPING.md) for current commands.
## Launch
Run from the repository root with Node 24.11+, Python 3, `lsof`, and dependencies
installed with `pnpm install --frozen-lockfile`. Browser driving uses the existing
`@playwright/test` dependency. If Chromium is unavailable, run
`node node_modules/@playwright/test/cli.js install chromium`, or select an installed
browser with `PAPERCLIP_PLAYWRIGHT_CHANNEL=chrome`.
Create separate, unique data and evidence directories. Keep the evidence outside
the data directory:
```sh
VERIFY_DATA_DIR=$(mktemp -d "${TMPDIR:-/tmp}/paperclip-verify-XXXXXX")
VERIFY_EVIDENCE_DIR=$(mktemp -d "${TMPDIR:-/tmp}/paperclip-proof-XXXXXX")
python3 .agents/skills/verify-paperclip/scripts/launch.py \
--data-dir "$VERIFY_DATA_DIR" --evidence-dir "$VERIFY_EVIDENCE_DIR"
```
Keep this command in a foreground terminal/session. The helper runs the supported
`onboard --yes --bind loopback --no-install-service --run` command, with isolated
embedded PostgreSQL, a free loopback port, no inherited instance routing or cwd
`.env`, and no automatic browser opening. It records `launch.json` in the evidence
directory. Source startup builds its required shared/plugin packages and migrates
the empty database; readiness can take longer on the first run.
This path starts an empty instance without model credentials. Create company and
agent state through the journey being checked. A UI check that stops before model
execution does not prove an agent run. For a preconfigured company/CEO and live
model work, use the documented [test-drive](../../../doc/DEVELOPING.md#one-command-isolated-manual-test-drive)
command with an authorized environment-backed credential and `--no-browser`.
Record its printed data directory, URL, runtime PID and commit before driving;
never use a fake credential to claim provider verification.
For Paperclip-managed reusable services, follow
[dev-workspace run/verify/fix](../paperclip-dev-workspace-run-verify-fix/SKILL.md)
instead of launching a second server. Its cloned-data/login requirements differ
from this empty local instance.
## Doctor
After startup, and again after any surprising behavior, run:
```sh
python3 .agents/skills/verify-paperclip/scripts/doctor.py \
--evidence-dir "$VERIFY_EVIDENCE_DIR"
```
This read-only check compares the recorded launcher, runtime PID, port owner,
process cwd, configuration, served Git commit, health/bootstrap readiness, root
HTML response, and company-list access. It writes `doctor.json` or exits nonzero.
Do not trust a root 200 or CLI doctor output alone. The CLI doctor checks whether
the port is available before startup; it is not proof of a running server's
ownership. Browser readiness still requires the expected visible page. Reset or
relaunch a wedged browser even when the process health passes.
## Drive
Use accessible roles, labels, and placeholders from the latest page state.
Existing Playwright specs in `tests/e2e/` supply recipes and selectors; their
configured servers and fixtures are separate from this live instance. Run a named
suite through its own configuration only when that is the evidence needed.
The executable onboarding smoke drives `onboarding.md` / `web-wizard`: open
`/onboarding` in the disposable self-hosted instance,
enter a unique organization name, choose Continue, reach the agent-name field,
reopen `/<company-prefix>/onboarding`, reload, and corroborate the saved company
through read-only API checks:
```sh
node .agents/skills/verify-paperclip/scripts/onboarding-smoke.mjs \
--evidence-dir "$VERIFY_EVIDENCE_DIR"
```
This covers company creation and setup resumption, with no mocked responses or
provider calls. Hiring, first task execution, and the alternate CLI entry remain
separate journeys. The script requires an empty instance and refuses a non-owned
or non-loopback target. For other features, reuse the owned URL and follow the
map's entry points. Company routes normally require the selected company's
`issuePrefix`, for example `/<PREFIX>/goals`; use current navigation rather than
guessing resource URLs. The unprefixed `/onboarding` route starts naming; use the
company-prefixed onboarding route to resume its agent setup. Check relevant
experimental gates and actor permissions.
For CLI checks, discover exact flags with
`node cli/node_modules/tsx/dist/cli.mjs cli/src/index.ts <command> --help`, then
select the disposable data directory/API/company explicitly. API reads can
corroborate UI writes; API-created state does not prove a creation UI.
## Evidence
Record feature file, sub-feature and entry-point ID, commit/dirty state, owned URL,
company/user, flags, runtime/harness, live versus simulated dependencies, command,
exit code, expected and observed behavior, and evidence links. Report each entry
as passed, failed, blocked with its prerequisite, or not run.
The smoke saves before/after/reload screenshots, visible-page text, a Playwright
trace, and `result.json` with company ID and API corroboration. On failure it
retains the trace, visible state, and failure result; rerun doctor before retrying.
Preserve launch output and relevant application logs without secrets. Reopen or
reload changed state and verify persistence/continuation, not just a success toast.
One passing sub-feature does not certify the entire feature family or other
surfaces. A full maintenance pass must exercise every mapped feature or report
incomplete coverage.
For Paperclip-assigned work, attach important proof through
[the artifact workflow](../../../doc/AGENT-ARTIFACTS.md). Keep runtime results in
the evidence directory or issue, not in the map; `coverage.json` describes
documentation coverage rather than live test health.
## Cleanup
Close the browser context you created (the smoke does this in `finally`). Stop the owned runtime with:
```sh
python3 .agents/skills/verify-paperclip/scripts/stop.py \
--evidence-dir "$VERIFY_EVIDENCE_DIR"
```
The helper verifies the runtime's port, cwd, and launch ancestry before sending
SIGTERM to that PID, then waits for runtime exit and checks that its HTTP
listener and embedded database have stopped. Signaling the runtime PID lets the server drain before stopping
PostgreSQL; a terminal group interrupt can reach the database first. Do this after
failed drives as well as successful runs. If startup fails before a runtime record
exists, stop only the foreground session you created and inspect its recorded data
directory for residue. Never kill by process name or stop another checkout's server.
Verify the recorded HTTP port has no listener and the owned runtime PID has
exited. Embedded PostgreSQL should stop with the server; inspect only the recorded
data directory if shutdown is incomplete. Retain the data directory for diagnosis
until no owned process uses it; remove only that exact temporary directory when
it is no longer useful. Never delete the evidence directory during teardown.
Confirm screenshots, trace, `result.json`, `launch.json`, and `doctor.json` still
exist after shutdown. A failed launch leaves its evidence intact.
## Helpers
All helper invocations are shown above. `launch.py`, `doctor.py`, and `stop.py` use Python's
standard library and the repo CLI; `onboarding-smoke.mjs` uses the repo's existing
Playwright dependency. They introduce no new package dependency or test framework.
## Helper safety check
Run the standard-library ownership test before changing launch/doctor/stop helpers:
```sh
python3 -m unittest discover -s .agents/skills/verify-paperclip/tests -v
```
It starts an owned fixture in another temporary checkout and confirms that both
doctor and stop reject its claimed port/PID without stopping the server. A second
fixture closes its listener before exiting and proves that cleanup waits for
runtime exit. These checks do
not qualify Paperclip startup, database readiness, or onboarding.
+60
View File
@@ -0,0 +1,60 @@
#!/usr/bin/env python3
"""Read-only identity and readiness check for an owned verification launch."""
import argparse
import json
import os
from pathlib import Path
import subprocess
import sys
import urllib.request
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument('--evidence-dir', required=True, type=Path)
args = parser.parse_args()
evidence = args.evidence_dir.resolve()
try:
launch = json.loads((evidence / 'launch.json').read_text())
repo = Path(launch['repo']).resolve()
assert repo == Path(__file__).resolve().parents[4], 'Launch belongs to another checkout.'
runtime = json.loads((Path(launch['dataDir']) / 'instances/default/runtime-info.json').read_text())
assert runtime['dashboardUrl'] == launch['url'], 'Runtime URL changed.'
assert runtime['port'] == launch['port'], 'Runtime port changed.'
assert runtime['host'] == '127.0.0.1', 'Expected trusted loopback.'
pid = runtime['pid']
os.kill(pid, 0)
listeners = subprocess.check_output(['lsof', '-nP', f'-iTCP:{launch["port"]}',
'-sTCP:LISTEN', '-t'], text=True).split()
assert set(listeners) == {str(pid)}, 'Port owner does not match runtime PID.'
if sys.platform == 'darwin':
rows = subprocess.check_output(['lsof', '-a', '-p', str(pid), '-d', 'cwd', '-Fn'], text=True).splitlines()
cwd = Path(next(row[1:] for row in rows if row.startswith('n'))).resolve()
else:
cwd = Path(f'/proc/{pid}/cwd').resolve(strict=True)
assert cwd == repo or repo in cwd.parents, 'Port owner cwd belongs to another checkout.'
ancestor = pid
seen = set()
while ancestor != launch['launcherPid']:
assert ancestor > 1 and ancestor not in seen, 'Runtime is not descended from this launch.'
seen.add(ancestor)
ancestor = int(subprocess.check_output(['ps', '-p', str(ancestor), '-o', 'ppid='], text=True).strip())
config = json.loads((Path(launch['dataDir']) / 'instances/default/config.json').read_text())
assert config['database']['mode'] == 'embedded-postgres', 'Expected isolated embedded database.'
assert Path(config['database']['embeddedPostgresDataDir']).resolve().is_relative_to(Path(launch['dataDir'])), 'Database path escaped isolation.'
with urllib.request.urlopen(launch['url'] + '/api/health', timeout=15) as response:
health = json.load(response)
assert health['status'] == 'ok' and health['bootstrapStatus'] == 'ready', 'Instance is not ready.'
assert health['deploymentMode'] == 'local_trusted' and health['authReady'], 'Unexpected auth mode.'
commit = subprocess.check_output(['git', '-C', str(repo), 'rev-parse', 'HEAD'], text=True).strip()
assert health['commit'] == launch['commit'] == commit, 'Served commit differs from checkout/launch.'
with urllib.request.urlopen(launch['url'], timeout=15) as response:
assert response.status == 200 and 'text/html' in response.headers.get('Content-Type', ''), 'Root UI is unavailable.'
with urllib.request.urlopen(launch['url'] + '/api/companies', timeout=15) as response:
companies = json.load(response)
assert isinstance(companies, list), 'Board company access failed.'
result = {'status': 'passed', 'pid': pid, 'cwd': str(cwd), 'url': launch['url'],
'health': health, 'companyIds': [company['id'] for company in companies]}
(evidence / 'doctor.json').write_text(json.dumps(result, indent=2) + '\n')
print(f'PASS: owned PID {pid}, {launch["url"]}, commit {commit}, ready board UI/API.')
except Exception as error:
(evidence / 'doctor-failure.json').write_text(json.dumps({'status': 'failed', 'error': str(error)}, indent=2) + '\n')
raise SystemExit(f'Doctor failed: {error}')
+52
View File
@@ -0,0 +1,52 @@
#!/usr/bin/env python3
"""Run the repository's credential-free isolated foreground onboarding path."""
import argparse
import json
import os
from pathlib import Path
import socket
import subprocess
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument('--data-dir', required=True, type=Path)
parser.add_argument('--evidence-dir', required=True, type=Path)
args = parser.parse_args()
repo = Path(__file__).resolve().parents[4]
data = args.data_dir.resolve()
evidence = args.evidence_dir.resolve()
if data == evidence or data in evidence.parents or evidence in data.parents:
parser.error('Data and evidence directories must be separate.')
data.mkdir(parents=True, exist_ok=True)
evidence.mkdir(parents=True, exist_ok=True)
if any(data.iterdir()) or (evidence / 'launch.json').exists():
parser.error('Use a fresh empty data directory and a new evidence directory.')
cli = repo / 'cli/node_modules/tsx/dist/cli.mjs'
if not cli.is_file():
parser.error('Install checkout dependencies first: pnpm install --frozen-lockfile')
for port in range(3100, 4100):
try:
with socket.socket() as probe:
probe.bind(('127.0.0.1', port))
break
except OSError:
continue
else:
raise RuntimeError('No available verification port between 3100 and 4099.')
excluded = {'DATABASE_URL', 'DATABASE_MIGRATION_URL', 'HOST', 'PORT', 'SERVE_UI',
'BETTER_AUTH_URL', 'BETTER_AUTH_BASE_URL', 'NODE_OPTIONS'}
env = {key: value for key, value in os.environ.items()
if not key.startswith('PAPERCLIP_') and key not in excluded}
env.update({'PAPERCLIP_HOME': str(data), 'PAPERCLIP_INSTANCE_ID': 'default',
'PAPERCLIP_DISABLE_CWD_ENV_FILE': 'true', 'PAPERCLIP_NO_BROWSER': 'true',
'PAPERCLIP_OPEN_ON_LISTEN': 'false', 'PAPERCLIP_UPDATE_CHECK': '0',
'PAPERCLIP_TELEMETRY_DISABLED': '1', 'PAPERCLIP_DEPLOYMENT_MODE': 'local_trusted',
'PAPERCLIP_DEPLOYMENT_EXPOSURE': 'private', 'PAPERCLIP_BIND': 'loopback',
'HOST': '127.0.0.1', 'PORT': str(port)})
record = {'dataDir': str(data), 'evidenceDir': str(evidence), 'repo': str(repo),
'launcherPid': os.getpid(), 'port': port, 'url': f'http://127.0.0.1:{port}',
'commit': subprocess.check_output(['git', '-C', str(repo), 'rev-parse', 'HEAD'], text=True).strip()}
(evidence / 'launch.json').write_text(json.dumps(record, indent=2) + '\n')
print(json.dumps(record), flush=True)
os.chdir(repo)
os.execvpe('node', ['node', str(cli), 'cli/src/index.ts', 'onboard', '--data-dir',
str(data), '--yes', '--bind', 'loopback', '--no-install-service', '--run'], env)
@@ -0,0 +1,79 @@
#!/usr/bin/env node
import assert from 'node:assert/strict';
import fs from 'node:fs/promises';
import path from 'node:path';
import { createRequire } from 'node:module';
import { fileURLToPath } from 'node:url';
import { execFileSync } from 'node:child_process';
const repo = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../../../..');
const require = createRequire(path.join(repo, 'package.json'));
const { chromium, expect } = require('@playwright/test');
assert.equal(process.argv[2], '--evidence-dir', 'Usage: onboarding-smoke.mjs --evidence-dir <path>');
assert.ok(process.argv[3]);
const evidence = path.resolve(process.argv[3]);
execFileSync('python3', [path.join(repo, '.agents/skills/verify-paperclip/scripts/doctor.py'), '--evidence-dir', evidence], { stdio: 'inherit' });
const launch = JSON.parse(await fs.readFile(path.join(evidence, 'launch.json'), 'utf8'));
assert.equal(new URL(launch.url).hostname, '127.0.0.1');
const browser = await chromium.launch({ headless: true, ...(process.env.PAPERCLIP_PLAYWRIGHT_CHANNEL ? { channel: process.env.PAPERCLIP_PLAYWRIGHT_CHANNEL } : {}) });
const context = await browser.newContext({ viewport: { width: 1440, height: 1000 }, serviceWorkers: 'block' });
const page = await context.newPage();
const errors = [];
page.on('pageerror', error => errors.push(error.message));
const companyName = `Verification ${Date.now()}`;
const result = { feature: 'onboarding.md', subFeatures: ['company', 'resume'], entryPoint: 'web-wizard', commit: launch.commit, url: launch.url, actor: 'local_trusted board', providerCalls: false, mockedResponses: false, companyName, status: 'failed' };
await context.tracing.start({ screenshots: true, snapshots: true, sources: true });
async function capture(name) {
await page.screenshot({ path: path.join(evidence, `${name}.png`), fullPage: true });
await fs.writeFile(path.join(evidence, `${name}.txt`), await page.locator('body').innerText());
}
try {
const before = await page.request.get(`${launch.url}/api/companies`);
assert.equal(before.ok(), true);
assert.deepEqual(await before.json(), [], 'Smoke requires a fresh instance.');
await page.goto(`${launch.url}/onboarding`);
const start = page.getByRole('button', { name: /Start Onboarding|New Organization|Add Agent/ });
if (await start.count()) await start.first().click();
const create = page.getByRole('button', { name: /Build a new organization/ });
if (await create.count()) await create.first().click();
await expect(page.getByRole('heading', { name: 'What is the name of your organization?' })).toBeVisible({ timeout: 60_000 });
await page.getByPlaceholder('e.g. Northwind Labs').fill(companyName);
await capture('before-create');
await page.getByRole('button', { name: /^Continue/ }).click();
await expect(page.locator('#onboarding-agent-name')).toBeVisible({ timeout: 30_000 });
await capture('after-create');
const companiesResponse = await page.request.get(`${launch.url}/api/companies`);
assert.equal(companiesResponse.ok(), true);
const companies = await companiesResponse.json();
const company = companies.find(item => item.name === companyName);
assert.ok(company, 'UI-created company must be persisted.');
result.companyId = company.id;
const goalsResponse = await page.request.get(`${launch.url}/api/companies/${company.id}/goals`);
assert.equal(goalsResponse.ok(), true);
assert.deepEqual(await goalsResponse.json(), [], 'Naming must not invent a mission.');
await page.goto(`${launch.url}/${company.issuePrefix}/onboarding`);
await expect(page.locator('#onboarding-agent-name')).toBeVisible({ timeout: 30_000 });
await capture('after-reopen');
await page.reload();
await expect(page.locator('#onboarding-agent-name')).toBeVisible({ timeout: 30_000 });
await capture('after-reload');
const persistedResponse = await page.request.get(`${launch.url}/api/companies`);
assert.equal(persistedResponse.ok(), true);
const persisted = await persistedResponse.json();
assert.equal(persisted.length, 1, 'Resume must not create another company.');
assert.equal(persisted[0].id, company.id);
assert.deepEqual(errors, [], 'No browser exceptions.');
result.status = 'passed';
result.observed = 'Company persisted; onboarding resumed at the agent step after reload; no mission invented.';
result.notRun = ['agent hiring', 'first task/model execution', 'cli-setup entry point'];
} catch (error) {
result.error = error.message;
await capture('failure').catch(() => {});
process.exitCode = 1;
} finally {
result.browserErrors = errors;
await context.tracing.stop({ path: path.join(evidence, 'trace.zip') });
await browser.close();
await fs.writeFile(path.join(evidence, 'result.json'), `${JSON.stringify(result, null, 2)}\n`);
console.log(JSON.stringify(result));
}
+65
View File
@@ -0,0 +1,65 @@
#!/usr/bin/env python3
"""Stop only an owned verification runtime and check that its database exits."""
import argparse
import json
import os
from pathlib import Path
import signal
import subprocess
import sys
import time
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument('--evidence-dir', required=True, type=Path)
args = parser.parse_args()
evidence = args.evidence_dir.resolve()
launch = json.loads((evidence / 'launch.json').read_text())
repo = Path(launch['repo']).resolve()
assert repo == Path(__file__).resolve().parents[4], 'Launch belongs to another checkout.'
instance = Path(launch['dataDir']) / 'instances/default'
runtime_file = instance / 'runtime-info.json'
runtime = json.loads(runtime_file.read_text()) if runtime_file.exists() else None
pid = None
if runtime:
assert runtime['port'] == launch['port'] and runtime['dashboardUrl'] == launch['url']
pid = runtime['pid']
owners = subprocess.run(['lsof', '-nP', f'-iTCP:{launch["port"]}', '-sTCP:LISTEN', '-t'], capture_output=True, text=True).stdout.split()
assert set(owners) == {str(pid)}, 'Refusing to signal a different or unverified port owner.'
if sys.platform == 'darwin':
rows = subprocess.check_output(['lsof', '-a', '-p', str(pid), '-d', 'cwd', '-Fn'], text=True).splitlines()
cwd = Path(next(row[1:] for row in rows if row.startswith('n'))).resolve()
else:
cwd = Path(f'/proc/{pid}/cwd').resolve(strict=True)
assert cwd == repo or repo in cwd.parents, 'Refusing to signal another checkout.'
ancestor = pid
seen = set()
while ancestor != launch['launcherPid']:
assert ancestor > 1 and ancestor not in seen, 'Runtime is not descended from this launch.'
seen.add(ancestor)
ancestor = int(subprocess.check_output(['ps', '-p', str(ancestor), '-o', 'ppid='], text=True).strip())
os.kill(pid, signal.SIGTERM)
def runtime_exited():
if pid is None:
return True
try:
os.kill(pid, 0)
except ProcessLookupError:
return True
# An exited child can remain a zombie until its launcher reaps it.
state = subprocess.run(['ps', '-p', str(pid), '-o', 'stat='],
capture_output=True, text=True)
return state.returncode == 0 and state.stdout.strip().startswith('Z')
deadline = time.monotonic() + 45
while time.monotonic() < deadline:
owners = subprocess.run(['lsof', '-nP', f'-iTCP:{launch["port"]}', '-sTCP:LISTEN', '-t'], capture_output=True, text=True).stdout.split()
if not owners and not (instance / 'db/postmaster.pid').exists() and runtime_exited():
result = {'status': 'passed', 'port': launch['port'], 'serverStopped': True,
'databaseStopped': True, 'runtimeExited': True, 'evidenceRetained': sorted(p.name for p in evidence.iterdir())}
(evidence / 'cleanup.json').write_text(json.dumps(result, indent=2) + '\n')
print(f'PASS: owned runtime/database stopped; evidence retained at {evidence}.')
break
time.sleep(0.5)
else:
raise SystemExit('Shutdown incomplete; retain data and evidence and inspect only this owned instance.')
@@ -0,0 +1,124 @@
"""Check that verification helpers cannot take ownership of another checkout."""
import json
import os
import time
from pathlib import Path
import subprocess
import sys
import tempfile
import unittest
import urllib.request
class OwnershipSafety(unittest.TestCase):
def test_foreign_checkout_server_remains_alive(self):
repo = Path(__file__).resolve().parents[4]
helpers = repo / '.agents/skills/verify-paperclip/scripts'
with tempfile.TemporaryDirectory(prefix='paperclip-ownership-test-') as temp:
root = Path(temp)
foreign = root / 'another-checkout'
foreign.mkdir()
server = subprocess.Popen(
[sys.executable, '-u', '-c',
"from http.server import HTTPServer, BaseHTTPRequestHandler\n"
"class Handler(BaseHTTPRequestHandler):\n"
" def do_GET(self):\n"
" self.send_response(200); self.end_headers(); self.wfile.write(b'foreign fixture alive')\n"
" def log_message(self, *args): pass\n"
"server = HTTPServer(('127.0.0.1', 0), Handler)\n"
"print(server.server_port, flush=True)\n"
"server.serve_forever()\n"],
cwd=foreign, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
text=True,
)
try:
port = int(server.stdout.readline().strip())
url = f'http://127.0.0.1:{port}'
data = root / 'verification-data'
instance = data / 'instances/default'
instance.mkdir(parents=True)
evidence = root / 'evidence'
evidence.mkdir()
# The claimed PID really owns this port, but its cwd is foreign.
(evidence / 'launch.json').write_text(json.dumps({
'repo': str(repo), 'dataDir': str(data), 'port': port,
'url': url, 'launcherPid': server.pid,
}))
(instance / 'runtime-info.json').write_text(json.dumps({
'pid': server.pid, 'port': port, 'dashboardUrl': url,
'host': '127.0.0.1',
}))
for helper in ['doctor.py', 'stop.py']:
with self.subTest(helper=helper):
result = subprocess.run(
[sys.executable, str(helpers / helper),
'--evidence-dir', str(evidence)],
capture_output=True, text=True, timeout=10,
)
self.assertNotEqual(result.returncode, 0)
self.assertIn('checkout', result.stdout + result.stderr)
self.assertIsNone(server.poll(), 'Helper killed foreign server')
with urllib.request.urlopen(url, timeout=5) as response:
self.assertEqual(response.read(), b'foreign fixture alive')
self.assertFalse((evidence / 'cleanup.json').exists())
finally:
server.terminate()
try:
server.communicate(timeout=5)
except subprocess.TimeoutExpired:
server.kill()
server.communicate()
def test_cleanup_waits_for_exit_after_listener_closes(self):
repo = Path(__file__).resolve().parents[4]
with tempfile.TemporaryDirectory(prefix='paperclip-delayed-exit-test-') as temp:
root = Path(temp)
instance = root / 'data/instances/default'
instance.mkdir(parents=True)
evidence = root / 'evidence'
evidence.mkdir()
marker = root / 'listener-closed'
server = subprocess.Popen(
[sys.executable, '-u', '-c',
"import signal, socket, sys, time\n"
"from pathlib import Path\n"
"listener = socket.socket(); listener.bind(('127.0.0.1', 0)); listener.listen()\n"
"def stop(signum, frame):\n"
" listener.close(); Path(sys.argv[1]).write_text('closed')\n"
" time.sleep(2); sys.exit(0)\n"
"signal.signal(signal.SIGTERM, stop)\n"
"print(listener.getsockname()[1], flush=True)\n"
"signal.pause()\n", str(marker)],
cwd=repo, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True,
)
try:
port = int(server.stdout.readline().strip())
url = f'http://127.0.0.1:{port}'
(evidence / 'launch.json').write_text(json.dumps({
'repo': str(repo), 'dataDir': str(root / 'data'),
'port': port, 'url': url, 'launcherPid': os.getpid(),
}))
(instance / 'runtime-info.json').write_text(json.dumps({
'pid': server.pid, 'port': port, 'dashboardUrl': url,
}))
started = time.monotonic()
result = subprocess.run(
[sys.executable, str(repo / '.agents/skills/verify-paperclip/scripts/stop.py'),
'--evidence-dir', str(evidence)],
capture_output=True, text=True, timeout=12,
)
self.assertEqual(result.returncode, 0, result.stdout + result.stderr)
self.assertTrue(marker.exists(), 'Fixture did not close its listener')
self.assertGreaterEqual(time.monotonic() - started, 2)
self.assertEqual(server.poll(), 0, 'Cleanup returned before runtime exit')
cleanup = json.loads((evidence / 'cleanup.json').read_text())
self.assertTrue(cleanup['runtimeExited'])
finally:
if server.poll() is None:
server.kill()
server.communicate(timeout=5)
if __name__ == '__main__':
unittest.main()
+7 -1
View File
@@ -152,10 +152,16 @@ Notes:
## 7. Verification Before Hand-off
[feature-map/README.md](feature-map/README.md) is an optional reference for user
[maps/feature-map/README.md](maps/feature-map/README.md) is an optional reference for user
entry points, verification recipes, and coverage gaps. The map records coverage
scope, not proof that a live journey passed.
The sibling [agent access map](maps/agent-access-map/README.md) records APIs,
agent entry points and permission boundaries using the same capability IDs.
Follow [the map contract](maps/README.md): update affected entries when mapped
behavior or access changes, and run `node scripts/check-maps.mjs` after map edits.
Its structural checks do not prove live behavior or authorization.
Default local/agent test path:
```sh
+7 -1
View File
@@ -495,11 +495,17 @@ npx paperclipai allowed-hostname dotta-macbook-pro
## Test Commands
The [feature map](../feature-map/README.md) is an optional reference for user
The [feature map](../maps/feature-map/README.md) is an optional reference for user
entry points, targeted tests, manual verification recipes, and coverage gaps.
Its page inventory is a source snapshot. The documented journeys have separate
verification steps and do not run automatically from the map.
The sibling [agent access map](../maps/agent-access-map/README.md) describes API
and agent reachability for the same capabilities. The [map contract](../maps/README.md)
defines synchronization, permissions and evidence. After map edits, run
`node scripts/check-maps.mjs` for structural/reference checks; it does not start an
instance or qualify access as an agent.
Use the cheap local default unless you are specifically working on browser flows:
```sh
+11
View File
@@ -638,6 +638,17 @@ pending. Recent events do not prove useful progress. These fields contain only
numbers and a boolean, never tool names, IDs, arguments, or event content, and
do not change the execution timeout, cancellation, or recovery policy.
A stopped turn (wall-clock timeout or operator stop) also records
`acpLastEventAgeAtStopMs` and `acpOldestPendingToolAgeAtStopMs`, measured at the
moment the stop fired. A cancel can make the agent emit closing events, so the
finalization age alone cannot separate a turn that went silent long before its
deadline from one that was still working. For a stopped turn, pending tools
means the tools pending when the stop fired, so a tool the cancel closes still
counts; `acpPendingToolCount` keeps its finalization-time meaning. When tools are
pending, `acpPendingToolKinds` lists their ACP tool kinds as a sorted, comma-separated
string drawn only from the closed ACP `ToolKind` enum plus `unknown`; the
server drops the field if any other value appears.
ACP and legacy OpenCode results retain the adapter's resolved wall-clock timeout as
`adapterExecutionTimeout` in the instance run result. Finalization uses it for
`effectiveTimeoutSec`, `timeoutSource`, and `timeoutConfigured`. Sources are
+100 -3
View File
@@ -2,9 +2,62 @@
Updated 2026-10-12.
## Latest checkpoint: ARM qualification and master integration
## Latest checkpoint: runtime prerequisite and authorized merges
The native runtime, protocol, Codex adapter/driver, selection code, and provider
The user authorizes preparing and merging ready PRs in dependency order.
Production deployment and provisioning-default promotion remain separate actions.
The Codex-default candidate is preserved at
`bb7591dfd0c4c8569e2a0b4303ff06de8ca3e9e2`; its running test-drive remains at
[3125](http://127.0.0.1:3125/COD/agents/all). No existing agent changes runner.
Its qualification work grew the review to 135 files. Extract the independent
runtime, installed-package and hosted-build changes onto
`codex/runner-native-platform-prerequisites`, based on master
`7d9b93aee2b79b2f035c5838741ce0b94168ec83`. This prerequisite contains 39 source
files and this record. Creation policy and experimental gates remain identical
to that master. README activation text and eight existing default-selection
controls stay in the dependent [Codex PR #15683](https://github.com/paperclipai/paperclip/pull/15683),
whose expected review is 98 files. Preserve all work and both branches.
The isolated extraction passes 276 existing focused controls. Runner no-emit
passes. The standard server no-emit initially finds a linked dependency-output
skew: the new master's ACP constants are absent from the old checkout's compiled
adapter-utils. A source-aware diagnostic passes; canonical verification remains
pending until its matching JavaScript dependency is prepared. Full hosted CI,
native compilation and fresh review are still required for the extracted head.
Do not count the diagnostic as a passing standard command.
Retained qualification keeps literal identities: four producers and Linux x64
and both Mac consumers pass at `a200495`; installed ARM native startup passes
with scoped stock Ubuntu prerequisites in
[38291535914](https://github.com/paperclipai/paperclip/actions/runs/38291535914).
Those artifacts are not relabeled as the extracted source. The Linux baseline
is GNU libc 2.39+, on x64/AArch64. Windows and Alpine remain deferred.
Cargo caches and overlapping JavaScript/native preparation use existing hosted
workflows. No local Docker/Rust builds or bundled Codex payloads are introduced.
Merge order is runtime prerequisite, Codex defaults, then the existing Claude
[protocol #15994](https://github.com/paperclipai/paperclip/pull/15994),
[default #15993](https://github.com/paperclipai/paperclip/pull/15993), and
[platform #15997](https://github.com/paperclipai/paperclip/pull/15997) PRs.
The authorized Claude chat owns its verification and fixes; this task coordinates
normal squash merges after applicable gates. The older Grok Cloud PR is an
independent lane, with its own missing snapshot-cleanup access and live proof.
The extracted [runtime prerequisite #16028](https://github.com/paperclipai/paperclip/pull/16028)
is open at `ddcd746eb6a01f2bbe9b4adeec238ba35bde5adb`. The default branch is
composed on it with all 134 owned implementation/test files identical to
`bb7591dfd0`; this record retains every historical checkpoint.
Next action: require current-source CI/review and remotely prepare the exact
composed Codex staging image and DB/shared pair. The existing QA tenant remains pinned to
old `2dbe43a4`. Managed Codex retains its $2.50 setup/task envelope and $2 cleanup;
historical unknown holds remain within the original $250 ceiling. Claude has
its separately authorized $50 ceiling. Missing live proof remains unresolved.
## Retained checkpoint: ARM qualification and master integration
The Rust daemon, protocol, Codex driver, creation policy, and provider
requirements remain unchanged from qualified source
`a200495cc7488f4d59da570407e516cf702e5af8`. Its verified 18-package archive
retains that literal identity. All four hosted daemon producers, Linux x64 clean
@@ -53,7 +106,51 @@ The last verified preview restart serves `2026.1005.0+352.git.0690801f13` at
configurations and both historical native runs. The downloaded Apple Silicon
daemon requires no source build or binary override.
Next action: require fresh CI/review on the integrated candidate, refresh the
Fresh review at `665c155` reports three valid findings. Remote sandbox setup and
execution now share the existing actual-target OS/architecture resolver rather
than selecting the Mac controller's daemon. Thirteen new baseline failures
reproduce the issue; 124 target/setup/backend and retained-artifact/version
controls pass after the fix, with server typecheck. Header, digest, preinstalled
artifact, and remote build-metadata verification stay strict. Foreign artifacts
are read/hashed on the controller and executed through the remote launcher.
Local and non-Codex paths remain unchanged. Receipt:
`/private/tmp/codex-default-sandbox-target-fix-receipt.json`.
Unchanged saved setup choices now bypass only new-selection resolution, retaining
later secret, company/environment, authentication, and runtime validation. The
actual disabled legacy baseline returned 422 before its probe. Treatment passes
175 existing controls plus a native-provider switch negative, with server
typecheck. New, explicit, draft, and changed-harness choices keep the disabled
adapter policy. Receipt: `/private/tmp/pr2-disabled-saved-codex-owned-receipt.json`.
The actual served Codex guide reproduces stale Mac/ARM legacy text at `665c155`.
It now uses the shared GNU libc floor, lists qualified Linux/Mac architectures,
distinguishes legacy fields, and preserves existing-runner and failure semantics.
Adapter typecheck passes; the updated served guide needs final-preview proof.
These corrections update server setup/execution and guide source. The qualified
`a200495` package startup and historical task evidence retain their literal
component boundaries; no new managed live proof or paid turn is claimed.
Fresh review at `e79254b` verifies the preceding fixes and reports one valid
development override edge. The common remote resolver now preserves
`PAPERCLIP_RUNNER_BINARY` only when the measured target OS/CPU matches the
controller. Explicit remote overrides retain priority; every selected artifact
still requires a matching native header. Cross-target selection ignores the
controller override. Seven new baseline failures reproduce the defect; 133
target/setup/backend/retained/version controls and server typecheck pass after
the correction. Receipt:
`/private/tmp/codex-default-same-host-override-fix-receipt.json`.
The `e79254b` preview restart preserves all four configurations and both
historical native runs. Its actual served guide now reports the shared GNU floor
and qualified Mac/ARM targets. No native build, Docker build, or provider call
runs locally. Main CI's selector remains unallocated; other PRs share this queue.
No environment approval, owned concurrency conflict, or routing failure was
found. Org capacity versus GitHub allocation is unconfirmed. Receipt:
`/private/tmp/pr2-e792-selector-queue-investigation.json`. Required final CI
aggregates and fresh review remain pending, not passed.
Next action: require fresh CI/review on the final corrected candidate, refresh the
matched preview, and publish final conclusions in the canonical PR's evidence
index. Human code-owner approval, managed staging onboarding, and actual
post-merge Cloud composition remain outstanding. No merge or production
@@ -0,0 +1,124 @@
# Chat channel transport workflows, batch three
Base: `a2ac5c27157ab033a2e0e2731b1b8e35bf20e7b9`. The preceding stack
(#15976, #15979, #15981, #15985, #15987) is merged. The original service is
29,897 lines / 1,170,080 bytes. This batch creates five stacked PRs; merging is
separate work.
| Order / boundary | Destination | Approximate lines moved / net reduction | Inputs and outputs | State and effects | Verification |
| --- | --- | --- | --- | --- | --- |
| 1. Slack session status | `chat-channels/slack/session-status.ts` | 342 / 330 | Endpoint lookup, credential lease, runtime fence, publication run identity, credentials and fetch; return processed count | Claim and settle existing durable status actions. Keep selected revision, attempt ownership and live test barrier. No worker or new state. | Existing public-service status, restart, rate-limit, concurrent selection, stop and Idle cases before/after. |
| 2. Slack accepted-file receipts | `chat-channels/slack/file-receipts.ts` | 900 / 840 | Runtime/credential authorization, publication eligibility and endpoint lookup; record/recover accepted upload receipts | Preserve same-attempt leases, exact receipt identities, publication links and transaction boundaries. Keep generic publication transport shared. | Existing upload recovery, competing retry deadline, revoked reach and no-duplicate-upload cases before/after. |
| 3. Telegram publication drafts | `chat-channels/telegram/publication-drafts.ts` | 394 / 370 | Current runtime and callback fence, source publication authority; reserve draft or handle stopped generation | Preserve runtime map identity, stop scope, draft revision and transactional invalidation. Keep maintenance and shared publication admission in their existing owners. | Existing durable private draft Stop, stale generation and publication recovery cases before/after. |
| 4. Photon incoming events and responses | `chat-channels/imessage-photon/events.ts` | 820 / 780 | Runtime callbacks, principal authorization, question delivery and shared inbound admission | Preserve receiver sequence/lease checks, native interaction binding, transaction ordering and deferred publication. No receiver/startup or credential-inspection ownership move. | Existing Photon public-service integration suite before/after. |
| 5. Teams file-transfer authority | `chat-channels/microsoft-teams/file-transfer-authority.ts` | 940 / 900 | Source proof, runtime/credential fence, principal authorization; return current recipient and immutable file authority | Keep source, recipient, Board intent and byte identity proofs together. Preserve map lifetimes and no-wait locks. Transport, maintenance cooldowns and cleanup stay with the publication worker. | Existing Teams current file authority, consent, composed Board transfer and stale-runtime cases before/after. |
Use named, typed contracts and channel folders. Keep shared message admission,
provider startup/shutdown, generic publication transport and shared authorization
in the service. Do not introduce a mutable context bag or a runtime import back
to the service. Reconsider a candidate if its actual dependency contract proves
too broad.
For each slice, inspect its execution path and callers, run baseline tests, move
mechanically, compare normalized syntax, rerun the same public entry-point tests,
and check server types and module boundaries. Finish CI and current-head review
before opening the next PR. Run broad local gates once at the cumulative handoff.
Record failures and skipped groups accurately; a retry does not erase a failed
run. Fixtures exercise assembled services and persistence, not live providers.
The starting service function is 27,835 lines. Its 212 nested functions span
27,146 lines; 51 wiring/state/API statements span 435 lines. Imports span 423
lines. The largest shared function remains `processMessage` at 2,166 lines.
Remap these measurements after the fifth extraction and stop at five PRs.
## Slice 1: Slack session status
- Service: 29,897 lines / 1,170,080 bytes → 29,553 lines / 1,156,944 bytes.
- Destination: 408 lines / 15,730 bytes. The durable claim, provider status call
and conditional settlement remain in one function. No state or worker moves.
- All six selected public-service cases passed before and after. They exercise
restart/rate-limit recovery, stale selection, Stop and publication-driven Idle.
Server typecheck, module boundaries, whitespace and normalized syntax parity
passed. The selection hook remains live through an options getter.
- Next: accepted-file receipt recovery. Keep the generic outbound publication
link writer shared and pass it as a typed callback to the Slack module.
## Slice 2: Slack accepted-file receipts
- Service: 29,553 lines / 1,156,944 bytes → 28,620 lines / 1,122,992 bytes.
- Destination: 1,000 lines / 36,807 bytes. Thirteen declarations move together:
receipt validation, recording, authorization, recovery, settlement and due-work
selection. The generic outbound-link writer remains shared.
- All nine selected public-service cases passed before and after. They cover
accepted upload recovery without reposting, original-attempt ownership,
competing retry deadlines, revoked reach and selected file publication.
Server typecheck, module boundaries and syntax parity passed. No state or
worker is added. Credential lease identity and all transactions are unchanged.
- Next: Telegram private draft reservation and stopped-generation callbacks,
retaining shared runtime-map identity and source-publication authorization.
## Slice 3: Telegram publication drafts
- Service: 28,620 lines / 1,122,992 bytes → 28,219 lines / 1,108,711 bytes.
- Destination: 461 lines / 16,860 bytes. Both functions preserve their original
bodies. Runtime maps remain the same per-service objects; the source authority
callback and credential guard are unchanged.
- All 34 durable private-draft Stop cases passed before and after, including
restart, bot-global identity allocation, concurrent Stop, transaction failure,
uncertain final delivery and retained stale callbacks. Server typecheck,
boundaries, whitespace and normalized syntax parity passed.
- Reassessment: Photon event handling can move without moving its receiver or
setup inspection. For Teams, extract source/recipient/file authority as a
coherent transaction-level API; keep transport protocol and scheduler lifetime
in the service to avoid passing unrelated runtime/worker dependencies.
## Slice 4: Photon events
- Service: 28,219 lines / 1,108,711 bytes → 27,398 lines / 1,079,439 bytes.
- Destination: 903 lines / 33,080 bytes. Provider failure, incoming event and
native response handling preserve all three function bodies. The receiver,
lease ownership, checkpoint callbacks and setup inspection remain in the
service; question delivery uses the original service object.
- All 18 Photon channel integration cases passed before and after. They use the
assembled Chat SDK runtime, provider fixture streams and a disposable database
to cover poll/confirmation responses, separate participant drafts, stale
controls, receiver lease fencing, groups, echoes, restart and continuation.
Server typecheck, boundaries, whitespace and syntax parity passed.
- Next: Teams file-transfer authority, with no transport or timer ownership move.
## Slice 5: Teams file-transfer authority
- Service: 27,398 lines / 1,079,439 bytes → 26,461 lines / 1,046,711 bytes.
- Destination: 1,041 lines / 36,532 bytes. Eleven declarations move into a
transaction-level authority factory exposing Board intent staging and fresh
authority derivation. It takes no database instance and starts no work.
- The original per-service runtime maps and retry-proof callbacks are passed
after the retry factory initializes. No-wait row locks, identity advisory
locks, source ordering and byte/recipient proof hashes preserve their bodies.
- All 50 selected Teams public-service cases passed before and after, including
exact recipient admission, retained source continuation, composed Board file
transfers, stale runtime callbacks and consent/file receipt recovery. Server
typecheck, module boundaries, whitespace and normalized syntax parity passed.
## Reassessment after batch three
The service falls from 29,897 lines / 1,170,080 bytes to 26,461 lines /
1,046,711 bytes: 3,436 lines (11.5%) and 123,369 bytes removed. The five new
modules total 3,813 lines / 139,009 bytes. All 117 selected cases passed before
and after their respective extractions.
The service function spans 24,484 lines. Its 191 nested functions span 23,829
lines; 54 state/wiring/API statements span 425 lines. Imports span 412 lines.
The largest remaining functions are `processMessage` (2,166 lines),
`handleAction` (1,074), `configureWithCredentialLease` (868),
`processSelectedPublication` (729), `handleModalSubmit` (708), `handleWebhook`
(685), `processLifecycleDelivery` (657), `applyProviderLifecycleEffect` (593),
and `ingestAttachments` (574).
Future candidates include receipt-reaction recovery, provider-effect dispatch,
attachment ingestion and inbound delivery persistence/drain ownership. Teams
transport protocol and scheduling can be reconsidered after their lifetime
contract is explicit; this batch deliberately moved only authority proofs.
Do not move a large shared admission function wholesale merely to reduce LOC.
Stop this batch at five PRs. Cumulative local gates and current-head CI/review
results are recorded in the final PR; per-slice PRs retain their own evidence.
-55
View File
@@ -1,55 +0,0 @@
# Documents, attachments, and work products
People read and revise task documents, annotate specific content, open attached files, and inspect the outputs an agent hands back. The artifact library provides another route to the same work.
Implementation: [task documents](../ui/src/components/IssueDocumentsSection.tsx), [artifact library](../ui/src/pages/Artifacts.tsx), [document panel](../ui/src/components/task-side-panel/TaskDocumentPanel.tsx).
## Sub-features
- `documents`: edit versioned task documents and inspect or restore revisions.
- `annotations`: attach feedback to document content and inspect resolution state.
- `attachments`: upload, preview, and download allowed files with company access checks.
- `work-products`: link deliverables to their source task, resource, and review context.
- `library`: search, filter, group, and open artifact stacks.
## How to get to it (user POV)
### `task-document`
Open a document from the task thread or document side panel.
### `task-output`
Open an attachment, output card, or file link from a task.
### `artifact-library`
Open `/artifacts` and its grouping, search, and media controls.
## Driving it
Preconditions: follow the [baseline](./README.md#before-driving-a-journey). Use a task with a text document, a small attachment, and a generated work product. Use nonsensitive fixture files.
### `task-document`
Automated: [documents service](../server/src/__tests__/documents-service.test.ts), [annotations](../server/src/__tests__/document-annotations-service.test.ts), and [revision restore](../server/src/__tests__/issue-document-restore-routes.test.ts) cover server contracts.
Manual: Edit a paragraph, save, reload, and compare revisions. Add an annotation to a specific selection and inspect it after another edit. Resolve it through the supported action. Restore a disposable revision and confirm the new current document and history agree.
### `task-output`
Automated: [attachment routes](../server/src/__tests__/issue-attachment-routes.test.ts) and [work products](../server/src/__tests__/work-products.test.ts) cover data/access behavior; [artifact arrival browser suite](../tests/e2e/artifact-tab-arrival.spec.ts) targets the arrival experience.
Manual: Upload a fixture and have the test task produce an output. Preview and download each, compare the contents, and follow the source task link. Reload and test an inaccessible user/company; verify missing workspace-only resources have an explicit state.
### `artifact-library`
Automated: [artifact page](../ui/src/pages/Artifacts.test.tsx) covers grouping, search requests, and pagination using mocks.
Manual: Find the task’s output through search and grouping, open its stack, page through results, and reload a direct stack link. Confirm the same file/content appears as from the task.
## Gotchas
- A local path is not automatically an uploaded artifact accessible to another user.
- A preview screenshot is not proof that download bytes or revision references are correct.
- Version conflicts and stale annotations must stay visible rather than silently targeting different content.
-45
View File
@@ -1,45 +0,0 @@
# Onboarding and first work
An operator can start an instance, create a company, configure its first agent, and reach a real first task. Instance setup and company onboarding are separate steps.
Implementation: [web wizard](../ui/src/components/OnboardingWizard.tsx), [CLI setup](../cli/src/commands/onboard.ts).
## Sub-features
- `instance`: choose local instance configuration and start the server.
- `company`: create a company with its identity and initial agent.
- `adapter`: choose an available harness, model, account, and execution environment.
- `first-task`: leave setup with a task whose execution or missing prerequisite is visible.
- `resume`: return to an incomplete wizard without losing saved state.
## How to get to it (user POV)
### `web-wizard`
Open `/onboarding` or the onboarding launcher in an empty company context.
### `cli-setup`
Use `paperclipai onboard --help` or `paperclipai run --help` to select an isolated data directory before setup.
## Driving it
Preconditions: follow the [baseline](./README.md#before-driving-a-journey). Use a new isolated data directory and record deployment mode. A configured adapter may still need account authentication.
### `web-wizard`
Automated: [wizard tests](../ui/src/components/OnboardingWizard.test.tsx) cover mocked wizard behavior; [onboarding browser suite](../tests/e2e/onboarding.spec.ts) supplies its own test environment. Live model execution is a separate check.
Manual: Create a disposable company and first agent. Save and leave midway, reopen, and finish. Follow the created first task, verify the selected agent and company, and inspect its output or explicit authentication gate. Reload both company and task.
### `cli-setup`
Automated: [CLI onboarding](../cli/src/__tests__/onboard.test.ts) and [isolated test drive](../cli/src/__tests__/test-drive.test.ts) cover their setup contracts; they do not establish that every model account is usable.
Manual: Run setup in the disposable directory, open the URL it prints, and confirm the instance identity and company. Restart using that same configuration and verify saved state. Exercise an unavailable adapter and confirm an actionable error.
## Gotchas
- An empty company, an empty instance, and an unauthenticated browser are different states.
- Creating an agent does not prove its provider login or first execution succeeded.
- See [access](./access.md) for authenticated deployments and [agents](./agents.md) for later hiring.
+135
View File
@@ -0,0 +1,135 @@
# Paperclip maps
The maps describe the same capabilities from two perspectives:
- [Feature map](feature-map/README.md): what a person can do, where to reach it,
and how to verify the user journey. Preserve its Poteto format.
- [Agent access map](agent-access-map/README.md): the APIs and agent entry points
for those capabilities, their permission boundaries, and access verification.
These are sibling directories under `maps/`. Each feature file has a same-named
agent access companion. Reuse the product map's sub-feature IDs, so `tasks/create`
identifies the same capability in both maps. Product behavior remains governed by
[the implementation spec](../doc/SPEC-implementation.md); a map cannot grant
authority or redefine a permission denial as success.
## Access contract
Every business operation needs both an API and a usable agent entry point for an
actor authorized to perform it. A dedicated tool is optional when REST, the CLI,
an assigned MCP client, or native `search_api` / `call_api` already provides the
operation. Record which agent surfaces actually have that path; an installed CLI
or optional MCP package cannot be assumed available to every native/remote run.
Track these independently:
| Dimension | Values and meaning |
| --- | --- |
| API | `present`, `missing`, `not-applicable`, or `unreviewed`. Use exact methods/paths; distinguish protocols from REST. |
| Agent access | `available`, `partial`, `missing`, `restricted`, `operator-only`, `not-applicable`, or `unreviewed`. Name the supported surface and actual entry point. |
| Policy | Actor, action/grant, company/resource/ownership scope, responsible-user intersection, run requirements, work modes, and gates relevant to the operation. |
| Evidence | `source-only`, `verified`, `failed`, `blocked`, or `not-run`. Source presence and successful board calls are not agent verification. |
| Review depth | `baseline` records representative operations and known gaps; `operation-reviewed` enumerates the capability's meaningful operations and their individual access contracts. |
Broad capabilities such as task properties must be split into operations before
they count as operation-reviewed: renaming, metadata edits, assignment,
dependencies, and lifecycle changes can use different tools and permission rules.
An available read path cannot certify a write path. List/get/create/update/delete,
execution/control, credential handling, and resolution are separate where their
authority or transport differs. Do not duplicate request schemas from OpenAPI.
### Exceptions and restrictions
Presentation-only state, static developer fixtures, and pre-start/local operator
work may use `not-applicable` for a domain API, with a concrete reason and the
existing local path. When a capability combines shared data with presentation,
split the operations: browser recents do not exempt resource lookup from API
coverage. Promoting local state to a shared feature requires revisiting the entry.
A board-only endpoint is `restricted` for agent identity, not an automatic
exception or a missing API. Cite the enforced policy and record whether the
agent can request the authorized human's action and observe its result. An
unresolved delegation question remains in **Gaps**. Company access, a job title,
a personal assistant's OAuth grant, or an accepted interaction does not grant
board identity. Keep budget, approval, secret and execution authority intact.
Check actual route/service authorization and production tool admission. OpenAPI
actor labels and scenario/evaluation tool declarations are supporting metadata;
record disagreements rather than using them as proof of access. Native API
fallback restrictions, tool field/scope limits, and rollout settings are part of
the agent path, even when a legacy agent can call the REST endpoint directly.
## Companion file format
Each `agent-access-map/<area>.md` has an H1, a relative link to its product file,
review date and source commit, followed by one H2 backticked ID per product
sub-feature. Each capability contains these fields:
- **Review:** `baseline` or `operation-reviewed`.
- **API:** presence state and exact operation IDs, or a reasoned exception.
- **Agent access:** availability state and concrete entry points by surface.
- **Policy:** relevant permission and runtime boundaries, with source references.
- **Evidence:** evidence state, reviewed commit and sources or executed proof.
- **Verification:** allowed/denied assertions and observable result; record what
has actually run separately from the proposed recipe.
- **Gaps:** missing APIs/paths, discovery drift, unreviewed operations or policy
decisions; use `none` only for the enumerated scope that was reviewed.
For an operation-reviewed capability, use H3 backticked operation IDs and repeat
API, Agent access, Policy, Evidence, Verification and Gaps for each operation.
Use small operation names such as `create`, `update`, `read`, or `run-now`.
The enclosing capability has `Review: operation-reviewed` only after its
meaningful operations have been enumerated. The following excerpt shows one
operation; include the others before using that review label:
```markdown
## `definition`
Review: `operation-reviewed`.
### `create`
API: `present` — POST /api/companies/{companyId}/routines.
Agent access: `partial` — agent REST and CLI routine create; default native
mutation binding missing, and call_api blocks routine mutations.
Policy: same company; assigneeAgentId must be the calling agent; cite the
routine authorization and native API policy sources.
Evidence: `source-only` — reviewed commit and source links; no live proof.
Verification: `not-run` — create an owned routine; reject assignment to another
agent; inspect saved configuration, attribution and retry behavior.
Gaps: default native create path; verify using the real permitted agent context.
```
## Keeping the maps synchronized
When a change adds/removes a capability or changes its behavior, API, permission,
tool binding, CLI support, or work mode, update the affected companion and product
recipe as appropriate in the same change. Preserve IDs across renames where the
capability is unchanged; update both indexes and cross-links together. An API-only
change may update the companion without rewriting unchanged user instructions.
[maintain-verification-skill](../.agents/skills/maintain-verification-skill/SKILL.md)
owns reconciliation of both maps. It follows changed source and authorization,
checks real agent reachability, and records product gaps without implementing
them during a maintenance pass. The creation skill uses this structure.
[verify-paperclip](../.agents/skills/verify-paperclip/SKILL.md) consumes the relevant
recipes and reports evidence/drift; map editing belongs to maintenance.
Run the structural check after map changes:
```sh
node scripts/check-maps.mjs
```
It checks paired areas/IDs, indexes, required fields, and local references. It
does not certify endpoint authorization, production bindings, operation
completeness, or live behavior. Source audits must check those against the
existing API and tool contracts; avoid a second schema catalog or runtime.
For live access proof, use Paperclip's existing API/runner/MCP fixtures or an owned
isolated instance. Use the actual agent identity, target and work mode. Assert the
allowed result and relevant denial (another company/private resource, wrong
owner, missing grant, invalid run, restricted mode or resolver). Mutations also
need persisted state/attribution and retry behavior. Capture evidence using the
[existing artifact workflow](../doc/AGENT-ARTIFACTS.md); keep executed run results
separate from product-map `coverage.json`, which records documentation scope.
+69
View File
@@ -0,0 +1,69 @@
# Paperclip agent access map
This map accompanies the [feature map](../feature-map/README.md). It records APIs,
agent entry points, permission boundaries and verification for the same capability IDs.
The [shared contract](../README.md) defines the format and maintenance rules.
Initial inventory: **35 areas and 171 sub-features**, source-reviewed on 2026-10-12
at `f981fa3cc10cb8663a87dec60345fbff46d54d0a`. All entries are `baseline` and `source-only`; none
claims complete operation enumeration or freshly verified agent access. Existing
API paths, native gaps, actor restrictions and local/operator exceptions are
recorded separately. These statuses do not represent a live pass rate.
## Areas
| Area | Product map | Capabilities |
| --- | --- | --- |
| [Login, invitations, and access](access.md) | [access](../feature-map/access.md) | 5 |
| [Dashboards, activity, and audit trails](activity.md) | [activity](../feature-map/activity.md) | 5 |
| [Agent conversations and project handoff](agent-chat.md) | [agent-chat](../feature-map/agent-chat.md) | 4 |
| [Hiring, agent configuration, and organization](agents.md) | [agents](../feature-map/agents.md) | 5 |
| [App access, action permissions, and testing](app-permissions.md) | [app-permissions](../feature-map/app-permissions.md) | 5 |
| [Costs, budgets, and spending controls](budgets-costs.md) | [budgets-costs](../feature-map/budgets-costs.md) | 4 |
| [Cases and structured work records](cases.md) | [cases](../feature-map/cases.md) | 4 |
| [External chat and email conversations](chat-channels.md) | [chat-channels](../feature-map/chat-channels.md) | 5 |
| [CLI, API clients, and local worktrees](cli-operations.md) | [cli-operations](../feature-map/cli-operations.md) | 5 |
| [Companies and portability](companies.md) | [companies](../feature-map/companies.md) | 4 |
| [Connection setup](connection-setup.md) | [connection-setup](../feature-map/connection-setup.md) | 8 |
| [Developer previews and diagnostic labs](developer-labs.md) | [developer-labs](../feature-map/developer-labs.md) | 4 |
| [Documents, attachments, and work products](documents-artifacts.md) | [documents-artifacts](../feature-map/documents-artifacts.md) | 5 |
| [Local, SSH, and sandbox environments](execution-environments.md) | [execution-environments](../feature-map/execution-environments.md) | 5 |
| [Tool gateways and access profiles](gateways-profiles.md) | [gateways-profiles](../feature-map/gateways-profiles.md) | 5 |
| [Goals and work alignment](goals.md) | [goals](../feature-map/goals.md) | 3 |
| [Inbox, decisions, and search](inbox-search.md) | [inbox-search](../feature-map/inbox-search.md) | 4 |
| [Installation, configuration, updates, and backups](instance-operations.md) | [instance-operations](../feature-map/instance-operations.md) | 5 |
| [Navigation, profile, and announcements](navigation-preferences.md) | [navigation-preferences](../feature-map/navigation-preferences.md) | 5 |
| [Onboarding and first work](onboarding.md) | [onboarding](../feature-map/onboarding.md) | 5 |
| [Pipelines, review queues, and learnings](pipelines.md) | [pipelines](../feature-map/pipelines.md) | 4 |
| [Plugins and contributed product surfaces](plugins.md) | [plugins](../feature-map/plugins.md) | 4 |
| [Projects and repositories](projects.md) | [projects](../feature-map/projects.md) | 4 |
| [Questions and approvals](questions-and-approvals.md) | [questions-and-approvals](../feature-map/questions-and-approvals.md) | 8 |
| [Recovery](recovery.md) | [recovery](../feature-map/recovery.md) | 8 |
| [Routines, schedules, and triggers](routines.md) | [routines](../feature-map/routines.md) | 5 |
| [Runs, harnesses, and model accounts](runs-adapters.md) | [runs-adapters](../feature-map/runs-adapters.md) | 4 |
| [Secrets, personal credentials, and proposals](secrets.md) | [secrets](../feature-map/secrets.md) | 5 |
| [Skill discovery, authoring, and policy](skills.md) | [skills](../feature-map/skills.md) | 5 |
| [Status cards and refreshed summaries](status-cards.md) | [status-cards](../feature-map/status-cards.md) | 4 |
| [Steering and queued messages](steering.md) | [steering](../feature-map/steering.md) | 7 |
| [Delegation, dependencies, and signoff](task-coordination.md) | [task-coordination](../feature-map/task-coordination.md) | 4 |
| [Task creation and lifecycle](tasks.md) | [tasks](../feature-map/tasks.md) | 5 |
| [Team packages and catalog installation](teams.md) | [teams](../feature-map/teams.md) | 4 |
| [Execution workspaces, services, and files](workspaces.md) | [workspaces](../feature-map/workspaces.md) | 5 |
## Using an entry
Read its Policy and Gaps before selecting an agent path. Native fallback, legacy
REST/CLI, stdio MCP and a personal assistant connection can have different
authority and availability. Use a real admitted production binding; a scenario
declaration is not an installed tool. A `restricted` entry records current
enforcement and leaves any unresolved delegation decision visible.
For API catalog disagreements, follow the route/service authorization and record
discovery drift. For `not-applicable`, retain the concrete exception and local
path. Split shared business operations from client-only presentation.
Use `maintain-verification-skill` to reconcile changed source and both maps.
Use `verify-paperclip` and existing API/runner/MCP fixtures to collect the
permitted-agent and denial evidence; report blocked/not-run coverage honestly.
Run `node scripts/check-maps.mjs` after editing. The structural check does not
certify permissions, API catalog coverage, tool admission or live behavior.
+136
View File
@@ -0,0 +1,136 @@
# Login, invitations, and access — agent access
Product map: [Login, invitations, and access](../feature-map/access.md).
Review date: 2026-10-12. Source commit: `f981fa3cc10cb8663a87dec60345fbff46d54d0a`.
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.
## `login`
Review: `baseline`.
API: `present` — representative operation IDs:
- `GET /api/auth/get-session`.
- `POST /api/bootstrap/claim`.
Agent access: `restricted` — Agent authenticates with its own issued bearer; board login
uses human/client auth.
Policy: Company access plus action-specific grants; instance administration requires a
board administrator.
Evidence: `source-only` — [implementation](../../server/src/routes/access.ts#L3018) at
the reviewed commit above.
Verification: `not-run` — assert the documented agent denial with an owned test fixture;
verify any listed agent request/result path separately. A delegated operation needs its
own policy and access review.
Gaps: An agent identity is not a board login or board claim; explicit delegation is a
product-policy decision.
## `invitations`
Review: `baseline`.
API: `present` — representative operation IDs:
- `POST /api/companies/{companyId}/invites`.
- `POST /api/invites/{token}/accept`.
Agent access: `partial` — REST with invite permission; CLI access; native call_api
blocks invite credentials.
Policy: Company access plus action-specific grants; instance administration requires a
board administrator.
Evidence: `source-only` — [implementation](../../server/src/routes/access.ts#L3018) 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: Invite creation has an agent permission branch. Human joining and agent onboarding
are different operations.
## `membership`
Review: `baseline`.
API: `present` — representative operation IDs:
- `GET /api/companies/{companyId}/members`.
- `PATCH /api/companies/{companyId}/members/{memberId}/permissions`.
Agent access: `partial` — REST with the specific company permission; native fallback for
unrestricted operations.
Policy: Company access plus action-specific grants; instance administration requires a
board administrator.
Evidence: `source-only` — [implementation](../../server/src/routes/access.ts#L3018) 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: Company membership APIs include agent grants; instance-admin user operations stay
board-only.
## `resources`
Review: `baseline`.
API: `present` — representative operation IDs:
- `GET /api/issues/{id}`.
- `GET /api/projects/{id}`.
Agent access: `available` — REST or scoped task/project tools.
Policy: Company access plus action-specific grants; instance administration requires a
board administrator.
Evidence: `source-only` — [implementation](../../server/src/routes/access.ts#L3018) 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: Company/resource authorization is implemented; a negative test must cover private
resources and another company.
## `cli-auth`
Review: `baseline`.
API: `present` — representative operation IDs:
- `POST /api/cli-auth/challenges`.
- `POST /api/cli-auth/revoke-current`.
Agent access: `restricted` — Board CLI authorization; agents use issued agent
credentials.
Policy: Company access plus action-specific grants; instance administration requires a
board administrator.
Evidence: `source-only` — [implementation](../../server/src/routes/access.ts#L3018) at
the reviewed commit above.
Verification: `not-run` — assert the documented agent denial with an owned test fixture;
verify any listed agent request/result path separately. A delegated operation needs its
own policy and access review.
Gaps: CLI board login/revocation cannot be counted as agent self-authentication.
+129
View File
@@ -0,0 +1,129 @@
# Dashboards, activity, and audit trails — agent access
Product map: [Dashboards, activity, and audit trails](../feature-map/activity.md).
Review date: 2026-10-12. Source commit: `f981fa3cc10cb8663a87dec60345fbff46d54d0a`.
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.
## `overview`
Review: `baseline`.
API: `present` — representative operation IDs:
- `GET /api/companies/{companyId}/dashboard`.
Agent access: `available` — REST / native call_api / CLI dashboard.
Policy: Same company plus visibility/audit/cost/run permissions where the route requires
them.
Evidence: `source-only` — [implementation](../../server/src/routes/activity.ts#L224) 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: Dashboard data is accessible; live-work rendering and event streaming are separate
surfaces.
## `activity`
Review: `baseline`.
API: `present` — representative operation IDs:
- `GET /api/companies/{companyId}/activity`.
Agent access: `available` — REST / native call_api / CLI activity.
Policy: Same company plus visibility/audit/cost/run permissions where the route requires
them.
Evidence: `source-only` — [implementation](../../server/src/routes/activity.ts#L224) 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: Audit export and raw activity creation have extra restrictions; do not equate them
with activity reading.
## `runs`
Review: `baseline`.
API: `present` — representative operation IDs:
- `GET /api/companies/{companyId}/heartbeat-runs`.
- `GET /api/heartbeat-runs/{runId}/events`.
Agent access: `available` — REST / native call_api / CLI run.
Policy: Same company plus visibility/audit/cost/run permissions where the route requires
them.
Evidence: `source-only` — [implementation](../../server/src/routes/activity.ts#L224) 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: Telemetry/run visibility is checked independently from seeing the source task.
## `routine-audit`
Review: `baseline`.
API: `present` — representative operation IDs:
- `GET /api/routines/{id}/runs`.
Agent access: `available` — REST / native call_api / CLI routine runs.
Policy: Same company plus visibility/audit/cost/run permissions where the route requires
them.
Evidence: `source-only` — [implementation](../../server/src/routes/activity.ts#L224) 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: Routine execution history is distinct from configuration revisions and scheduling
changes.
## `timeline`
Review: `baseline`.
API: `present` — representative operation IDs:
- `GET /api/companies/{companyId}/timeline`.
Agent access: `available` — REST / native call_api.
Policy: Same company plus visibility/audit/cost/run permissions where the route requires
them.
Evidence: `source-only` — [implementation](../../server/src/routes/activity.ts#L224) 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: API exists; no dedicated timeline tool is necessary for this requirement.
+113
View File
@@ -0,0 +1,113 @@
# Agent conversations and project handoff — agent access
Product map: [Agent conversations and project handoff](../feature-map/agent-chat.md).
Review date: 2026-10-12. Source commit: `f981fa3cc10cb8663a87dec60345fbff46d54d0a`.
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.
## `discovery`
Review: `baseline`.
API: `present` — representative operation IDs:
- `GET /api/companies/{companyId}/chats`.
- `GET /api/companies/{companyId}/chats/{agentRef}`.
Agent access: `restricted` — Board-user REST; the responding agent gets its assigned
conversation context.
Policy: Conversation discovery/creation requires a board user and the Agent Chat gate;
task access follows task visibility.
Evidence: `source-only` — [implementation](../../server/src/routes/issues.ts#L18077) at
the reviewed commit above.
Verification: `not-run` — assert the documented agent denial with an owned test fixture;
verify any listed agent request/result path separately. A delegated operation needs its
own policy and access review.
Gaps: Agents cannot enumerate or create another person's standing chats. Detail route is
missing from the generated API catalog.
## `history`
Review: `baseline`.
API: `present` — representative operation IDs:
- `GET /api/issues/{id}/comments`.
- `POST /api/issues/{id}/comments`.
Agent access: `partial` — Assigned conversation task tools / REST for eligible task
history and replies.
Policy: Conversation discovery/creation requires a board user and the Agent Chat gate;
task access follows task visibility.
Evidence: `source-only` — [implementation](../../server/src/routes/issues.ts#L18077) 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: Agent responses are supported; creating the person's chat and impersonating their
messages are different actions.
## `handoff`
Review: `baseline`.
API: `present` — representative operation IDs:
- `POST /api/companies/{companyId}/projects`.
- `POST /api/companies/{companyId}/issues`.
Agent access: `available` — Native list_projects/create_project/create_task; project MCP
tools; REST.
Policy: Conversation discovery/creation requires a board user and the Agent Chat gate;
task access follows task visibility.
Evidence: `source-only` — [implementation](../../server/src/routes/issues.ts#L18077) 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: Agent handoff is implemented; execution readiness, assignment permission, and
repository access still apply.
## `conference-room`
Review: `baseline`.
API: `present` — representative operation IDs:
- `POST /api/board/chat/stream`.
Agent access: `partial` — Existing SSE client in local_trusted mode with the
experimental gate.
Policy: Conversation discovery/creation requires a board user and the Agent Chat gate;
task access follows task visibility.
Evidence: `source-only` — [implementation](../../server/src/routes/issues.ts#L18077) 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: Not callable through generic REST tooling: protocol and deployment constraints
apply. This route is not guarded by assertBoard, so its intended agent policy needs
clarification.
+140
View File
@@ -0,0 +1,140 @@
# Hiring, agent configuration, and organization — agent access
Product map: [Hiring, agent configuration, and organization](../feature-map/agents.md).
Review date: 2026-10-12. Source commit: `f981fa3cc10cb8663a87dec60345fbff46d54d0a`.
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.
## `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.
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: Identity/persona hiring works. Operator account login and sensitive
adapter/environment configuration are separate guarded actions.
## `instructions`
Review: `baseline`.
API: `present` — representative operation IDs:
- `GET /api/agents/{id}/instructions-bundle/file`.
- `PUT /api/agents/{id}/instructions-bundle/file`.
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.
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`
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`
Review: `baseline`.
API: `present` — representative operation IDs:
- `POST /api/agents/{id}/pause`.
- `POST /api/agents/{id}/resume`.
- `POST /api/agents/{id}/terminate`.
Agent access: `partial` — REST resume under change grant; pause/terminate require board;
native call_api blocks all three.
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: Resume is agent-eligible but lacks a default native binding. Pause and termination
are actor-boundary decisions.
## `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.
+132
View File
@@ -0,0 +1,132 @@
# App access, action permissions, and testing — agent access
Product map: [App access, action permissions, and
testing](../feature-map/app-permissions.md).
Review date: 2026-10-12. Source commit: `f981fa3cc10cb8663a87dec60345fbff46d54d0a`.
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.
## `agent-access`
Review: `baseline`.
API: `present` — representative operation IDs:
- `PUT /api/tool-connections/{connectionId}/installs`.
Agent access: `restricted` — Board management API; agents use their resulting assigned
app tools.
Policy: Connection/profile/policy management routes require a board user; tool use
separately evaluates agent grants and action policies.
Evidence: `source-only` — [implementation](../../server/src/routes/tool-access.ts#L517)
at the reviewed commit above.
Verification: `not-run` — assert the documented agent denial with an owned test fixture;
verify any listed agent request/result path separately. A delegated operation needs its
own policy and access review.
Gaps: Granting access is distinct from using access. No equivalent agent management path
exists in these routes.
## `action-policy`
Review: `baseline`.
API: `present` — representative operation IDs:
- `POST /api/tool-profiles/{profileId}/entries`.
Agent access: `restricted` — Board management API; agent execution follows
off/ask/allowed.
Policy: Connection/profile/policy management routes require a board user; tool use
separately evaluates agent grants and action policies.
Evidence: `source-only` — [implementation](../../server/src/routes/tool-access.ts#L517)
at the reviewed commit above.
Verification: `not-run` — assert the documented agent denial with an owned test fixture;
verify any listed agent request/result path separately. A delegated operation needs its
own policy and access review.
Gaps: An agent cannot authorize itself by editing the policy. Decide whether any
explicitly delegated administration should be supported.
## `catalog-change`
Review: `baseline`.
API: `present` — representative operation IDs:
- `POST /api/tool-profiles/{profileId}/new-tools/review`.
Agent access: `restricted` — Board catalog-review API; agents can discover authorized
tools.
Policy: Connection/profile/policy management routes require a board user; tool use
separately evaluates agent grants and action policies.
Evidence: `source-only` — [implementation](../../server/src/routes/tool-access.ts#L517)
at the reviewed commit above.
Verification: `not-run` — assert the documented agent denial with an owned test fixture;
verify any listed agent request/result path separately. A delegated operation needs its
own policy and access review.
Gaps: Catalog refresh/review and quarantined-action enablement are management
operations.
## `test-action`
Review: `baseline`.
API: `present` — representative operation IDs:
- `POST /api/tool-connections/{connectionId}/test-calls`.
Agent access: `restricted` — Board test-as-agent API; agent executes its own assigned
tools normally.
Policy: Connection/profile/policy management routes require a board user; tool use
separately evaluates agent grants and action policies.
Evidence: `source-only` — [implementation](../../server/src/routes/tool-access.ts#L517)
at the reviewed commit above.
Verification: `not-run` — assert the documented agent denial with an owned test fixture;
verify any listed agent request/result path separately. A delegated operation needs its
own policy and access review.
Gaps: A board test performed as an agent is not proof the agent can manage or invoke the
testing endpoint.
## `account-maintenance`
Review: `baseline`.
API: `present` — representative operation IDs:
- `POST /api/tool-connections/{connectionId}/reconnect`.
- `GET /api/tool-connections/{connectionId}/activity`.
Agent access: `restricted` — Board account management; native
connections_search/connection_request can request human setup.
Policy: Connection/profile/policy management routes require a board user; tool use
separately evaluates agent grants and action policies.
Evidence: `source-only` — [implementation](../../server/src/routes/tool-access.ts#L517)
at the reviewed commit above.
Verification: `not-run` — assert the documented agent denial with an owned test fixture;
verify any listed agent request/result path separately. A delegated operation needs its
own policy and access review.
Gaps: Agent requests and continued tool use exist; reconnect/revoke/audit management are
human paths.
+108
View File
@@ -0,0 +1,108 @@
# Costs, budgets, and spending controls — agent access
Product map: [Costs, budgets, and spending controls](../feature-map/budgets-costs.md).
Review date: 2026-10-12. Source commit: `f981fa3cc10cb8663a87dec60345fbff46d54d0a`.
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.
## `cost-reporting`
Review: `baseline`.
API: `present` — representative operation IDs:
- `GET /api/companies/{companyId}/costs/summary`.
- `GET /api/companies/{companyId}/costs/by-agent`.
Agent access: `available` — REST / native call_api / CLI cost.
Policy: Reading costs uses company/resource cost policy. Budget policies and incident
resolution require a board actor.
Evidence: `source-only` — [implementation](../../server/src/routes/costs.ts#L346) 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: Cost visibility applies. Provider accounting imports and quota-window inspection
have additional board gates.
## `budgets`
Review: `baseline`.
API: `present` — representative operation IDs:
- `GET /api/companies/{companyId}/budgets/overview`.
- `POST /api/companies/{companyId}/budgets/policies`.
Agent access: `restricted` — Agent-readable overview where allowed; board-only
configuration.
Policy: Reading costs uses company/resource cost policy. Budget policies and incident
resolution require a board actor.
Evidence: `source-only` — [implementation](../../server/src/routes/costs.ts#L346) at the
reviewed commit above.
Verification: `not-run` — assert the documented agent denial with an owned test fixture;
verify any listed agent request/result path separately. A delegated operation needs its
own policy and access review.
Gaps: Read API exists; no agent-write path for budget policies, including agents with
ordinary company access.
## `incidents`
Review: `baseline`.
API: `present` — representative operation IDs:
- `GET /api/companies/{companyId}/budgets/overview`.
Agent access: `available` — REST / native call_api for allowed visibility.
Policy: Reading costs uses company/resource cost policy. Budget policies and incident
resolution require a board actor.
Evidence: `source-only` — [implementation](../../server/src/routes/costs.ts#L346) 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: Inspection is supported; hard-stop or pause relief does not follow from seeing the
incident.
## `resolution`
Review: `baseline`.
API: `present` — representative operation IDs:
- `POST /api/companies/{companyId}/budget-incidents/{incidentId}/resolve`.
Agent access: `restricted` — Board resolution API; agent requests the authorized
person's action.
Policy: Reading costs uses company/resource cost policy. Budget policies and incident
resolution require a board actor.
Evidence: `source-only` — [implementation](../../server/src/routes/costs.ts#L346) at the
reviewed commit above.
Verification: `not-run` — assert the documented agent denial with an owned test fixture;
verify any listed agent request/result path separately. A delegated operation needs its
own policy and access review.
Gaps: A governance-policy decision is needed before delegating budget increases or
incident resolution.
+108
View File
@@ -0,0 +1,108 @@
# Cases and structured work records — agent access
Product map: [Cases and structured work records](../feature-map/cases.md).
Review date: 2026-10-12. Source commit: `f981fa3cc10cb8663a87dec60345fbff46d54d0a`.
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.
## `browse`
Review: `baseline`.
API: `present` — representative operation IDs:
- `GET /api/companies/{companyId}/cases`.
Agent access: `available` — REST / native call_api; agent cases reference.
Policy: enableCases gate; company/case/task boundaries, active run where required,
source trust, and checked-out mutation ownership.
Evidence: `source-only` — [implementation](../../server/src/routes/cases.ts#L592) 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: No dedicated production list_cases binding is required because the REST fallback
exists.
## `structure`
Review: `baseline`.
API: `present` — representative operation IDs:
- `POST /api/companies/{companyId}/cases`.
- `PATCH /api/cases/{id}`.
Agent access: `available` — REST / native call_api; parentCaseId and JSON fields.
Policy: enableCases gate; company/case/task boundaries, active run where required,
source trust, and checked-out mutation ownership.
Evidence: `source-only` — [implementation](../../server/src/routes/cases.ts#L592) 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: Structured case data is supported; grouping/rendering is presentation, not a new
endpoint requirement.
## `history`
Review: `baseline`.
API: `present` — representative operation IDs:
- `GET /api/cases/{id}/events`.
- `GET /api/cases/{id}/documents/{key}/revisions`.
Agent access: `available` — REST / native call_api.
Policy: enableCases gate; company/case/task boundaries, active run where required,
source trust, and checked-out mutation ownership.
Evidence: `source-only` — [implementation](../../server/src/routes/cases.ts#L592) 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: Source-backed access only; case visibility and document locks still apply.
## `task-links`
Review: `baseline`.
API: `present` — representative operation IDs:
- `POST /api/cases/{id}/links`.
- `GET /api/issues/{issueId}/cases`.
Agent access: `available` — REST / native call_api.
Policy: enableCases gate; company/case/task boundaries, active run where required,
source trust, and checked-out mutation ownership.
Evidence: `source-only` — [implementation](../../server/src/routes/cases.ts#L592) 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: Case/task association exists; source trust and issue visibility must be tested
with agent credentials.
+132
View File
@@ -0,0 +1,132 @@
# External chat and email conversations — agent access
Product map: [External chat and email conversations](../feature-map/chat-channels.md).
Review date: 2026-10-12. Source commit: `f981fa3cc10cb8663a87dec60345fbff46d54d0a`.
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.
## `providers`
Review: `baseline`.
API: `present` — representative operation IDs:
- `POST /api/companies/{companyId}/chat-endpoints`.
Agent access: `restricted` — Board setup APIs; native connection request can ask for
setup.
Policy: Endpoint management/identity linking requires a board user; delivery is
server-owned and agent tools use scoped assignments.
Evidence: `source-only` — [implementation](../../server/src/routes/chat-channels.ts#L75)
at the reviewed commit above.
Verification: `not-run` — assert the documented agent denial with an owned test fixture;
verify any listed agent request/result path separately. A delegated operation needs its
own policy and access review.
Gaps: Provider installation and account enrollment are not available to an ordinary
agent actor.
## `identity`
Review: `baseline`.
API: `present` — representative operation IDs:
- `POST /api/chat-identity-links/confirm`.
Agent access: `restricted` — Human identity-link flow.
Policy: Endpoint management/identity linking requires a board user; delivery is
server-owned and agent tools use scoped assignments.
Evidence: `source-only` — [implementation](../../server/src/routes/chat-channels.ts#L75)
at the reviewed commit above.
Verification: `not-run` — assert the documented agent denial with an owned test fixture;
verify any listed agent request/result path separately. A delegated operation needs its
own policy and access review.
Gaps: No impersonation path; native call_api additionally blocks identity-link
operations.
## `conversation`
Review: `baseline`.
API: `present` — representative operation IDs:
- `POST /api/chat-endpoints/{endpointId}/conversations/{conversationId}/publications`.
Agent access: `partial` — Assigned-agent reply pipeline; native completion; provider
tools where assigned.
Policy: Endpoint management/identity linking requires a board user; delivery is
server-owned and agent tools use scoped assignments.
Evidence: `source-only` — [implementation](../../server/src/routes/chat-channels.ts#L75)
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: Normal agent replies work through server delivery. Explicit endpoint publication
APIs are board management paths.
## `attachments`
Review: `baseline`.
API: `present` — representative operation IDs:
- `GET /api/issues/{id}/attachments`.
- `POST /api/companies/{companyId}/issues/{issueId}/attachments`.
Agent access: `partial` — Native register_deliverable / attachment tools when admitted;
agent REST; server-owned delivery.
Policy: Endpoint management/identity linking requires a board user; delivery is
server-owned and agent tools use scoped assignments.
Evidence: `source-only` — [implementation](../../server/src/routes/chat-channels.ts#L75)
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: Uploading/registering is supported. Provider delivery status and board replay are
separate operations.
## `lifecycle`
Review: `baseline`.
API: `present` — representative operation IDs:
- `GET /api/chat-endpoints/{endpointId}/activity`.
- `PATCH /api/chat-endpoints/{endpointId}`.
Agent access: `restricted` — Board lifecycle APIs; agent requests repair when blocked.
Policy: Endpoint management/identity linking requires a board user; delivery is
server-owned and agent tools use scoped assignments.
Evidence: `source-only` — [implementation](../../server/src/routes/chat-channels.ts#L75)
at the reviewed commit above.
Verification: `not-run` — assert the documented agent denial with an owned test fixture;
verify any listed agent request/result path separately. A delegated operation needs its
own policy and access review.
Gaps: Activity/repair/replay/disable use board endpoint access, not the agent's ability
to reply.
+134
View File
@@ -0,0 +1,134 @@
# CLI, API clients, and local worktrees — agent access
Product map: [CLI, API clients, and local worktrees](../feature-map/cli-operations.md).
Review date: 2026-10-12. Source commit: `f981fa3cc10cb8663a87dec60345fbff46d54d0a`.
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.
## `context`
Review: `baseline`.
API: `not-applicable` — Local CLI configuration has no matching domain REST resource;
explicitly classify local operator configuration.
Agent access: `operator-only` — CLI context/profile options and issued agent
environment.
Policy: CLI preserves the selected bearer identity and run header; installing a CLI does
not grant board rights.
Evidence: `source-only` — [implementation](../../cli/src/commands/client/common.ts#L49)
at the reviewed commit above.
Verification: `not-run` — exercise the listed local workflow in an authorized, owned
operator environment. Verify its isolation and result; do not count local machine
authority as company-agent API access.
Gaps: Local CLI configuration has no matching domain REST resource; explicitly classify
local operator configuration.
## `domain-commands`
Review: `baseline`.
API: `present` — representative operation IDs:
- `GET /api/agents/me`.
- `GET /api/companies/{companyId}/issues`.
Agent access: `available` — CLI client commands with agent bearer; REST and native
tools.
Policy: CLI preserves the selected bearer identity and run header; installing a CLI does
not grant board rights.
Evidence: `source-only` — [implementation](../../cli/src/commands/client/common.ts#L49)
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: Each command reuses API authorization; a command listed in help is not necessarily
allowed to this agent.
## `outputs`
Review: `baseline`.
API: `present` — representative operation IDs:
- `PUT /api/issues/{id}/documents/{key}`.
- `POST /api/issues/{id}/work-products`.
Agent access: `available` — CLI issue/asset/skill commands; REST; native
document/deliverable tools.
Policy: CLI preserves the selected bearer identity and run header; installing a CLI does
not grant board rights.
Evidence: `source-only` — [implementation](../../cli/src/commands/client/common.ts#L49)
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: Binary transfers, document versions and work-product registration need distinct
assertions.
## `run-controls`
Review: `baseline`.
API: `present` — representative operation IDs:
- `GET /api/heartbeat-runs/{runId}`.
- `POST /api/agents/{id}/heartbeat/invoke`.
Agent access: `partial` — CLI run/agent commands; read API; board-only
invocation/control routes.
Policy: CLI preserves the selected bearer identity and run header; installing a CLI does
not grant board rights.
Evidence: `source-only` — [implementation](../../cli/src/commands/client/common.ts#L49)
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: Agent credentials can read eligible runs. Operator invocation/cancellation must
not be counted as ordinary agent access.
## `worktree-instances`
Review: `baseline`.
API: `not-applicable` — Local checkout and pre-start provisioning use local tools, not
company REST authorization. No new runtime is needed.
Agent access: `operator-only` — CLI worktree/test-drive/dev service commands on an
authorized owned checkout.
Policy: CLI preserves the selected bearer identity and run header; installing a CLI does
not grant board rights.
Evidence: `source-only` — [implementation](../../cli/src/commands/client/common.ts#L49)
at the reviewed commit above.
Verification: `not-run` — exercise the listed local workflow in an authorized, owned
operator environment. Verify its isolation and result; do not count local machine
authority as company-agent API access.
Gaps: Local checkout and pre-start provisioning use local tools, not company REST
authorization. No new runtime is needed.
+115
View File
@@ -0,0 +1,115 @@
# Companies and portability — agent access
Product map: [Companies and portability](../feature-map/companies.md).
Review date: 2026-10-12. Source commit: `f981fa3cc10cb8663a87dec60345fbff46d54d0a`.
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.
## `selection`
Review: `baseline`.
API: `present` — representative operation IDs:
- `GET /api/companies/{companyId}`.
- `GET /api/companies`.
- `POST /api/companies`.
Agent access: `partial` — Agent reads its bound company; CLI context chooses it; board
lists/creates companies.
Policy: Same-company CEO or board for identity/import operations; list/create/archive
convenience endpoint is board-gated.
Evidence: `source-only` — [implementation](../../server/src/routes/companies.ts#L1245)
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: A worker cannot enumerate/create companies via its company agent key. Browser
selection is local state.
## `identity`
Review: `baseline`.
API: `present` — representative operation IDs:
- `PATCH /api/companies/{companyId}`.
- `PATCH /api/companies/{companyId}/branding`.
Agent access: `available` — Same-company CEO REST / native call_api / CLI company.
Policy: Same-company CEO or board for identity/import operations; list/create/archive
convenience endpoint is board-gated.
Evidence: `source-only` — [implementation](../../server/src/routes/companies.ts#L1245)
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: The CEO restriction is a real policy, not a missing API; ordinary employees need
denial evidence.
## `archive`
Review: `baseline`.
API: `present` — representative operation IDs:
- `POST /api/companies/{companyId}/archive`.
- `PATCH /api/companies/{companyId}`.
Agent access: `partial` — Board archive endpoint; CEO company PATCH can express status
changes.
Policy: Same-company CEO or board for identity/import operations; list/create/archive
convenience endpoint is board-gated.
Evidence: `source-only` — [implementation](../../server/src/routes/companies.ts#L1245)
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: Convenience archive and general company PATCH have different authorization. Review
equivalence rather than declaring all archival human-only.
## `portability`
Review: `baseline`.
API: `present` — representative operation IDs:
- `POST /api/companies/{companyId}/exports`.
- `POST /api/companies/{companyId}/imports/preview`.
- `POST /api/companies/{companyId}/imports/apply`.
Agent access: `partial` — CEO REST / CLI company; native export restricted, eligible
same-company import uses fallback.
Policy: Same-company CEO or board for identity/import operations; list/create/archive
convenience endpoint is board-gated.
Evidence: `source-only` — [implementation](../../server/src/routes/companies.ts#L1245)
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: Secure exports lack a default native binding; new-company/ZIP import flows have
different board and transport constraints.
+207
View File
@@ -0,0 +1,207 @@
# Connection setup — agent access
Product map: [Connection setup](../feature-map/connection-setup.md).
Review date: 2026-10-12. Source commit: `f981fa3cc10cb8663a87dec60345fbff46d54d0a`.
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.
## `catalog`
Review: `baseline`.
API: `present` — representative operation IDs:
- `POST /runtime-tools/connections/search`.
Agent access: `available` — Native connections_search / run-bound runtime-tools MCP.
Policy: Setup and credentials belong to the addressed authorized human; active-run tools
can search/request access.
Evidence: `source-only` —
[implementation](../../server/src/routes/connection-intents.ts#L130) 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: Runtime tool broker searches available services without granting connection
administration.
## `identity-and-access`
Review: `baseline`.
API: `present` — representative operation IDs:
- `POST /api/companies/{companyId}/tools/connections`.
Agent access: `restricted` — Board setup API plus agent connection_request.
Policy: Setup and credentials belong to the addressed authorized human; active-run tools
can search/request access.
Evidence: `source-only` —
[implementation](../../server/src/routes/connection-intents.ts#L130) at the reviewed
commit above.
Verification: `not-run` — assert the documented agent denial with an owned test fixture;
verify any listed agent request/result path separately. A delegated operation needs its
own policy and access review.
Gaps: Selecting account ownership/eligible agents is management; an agent can request
the intended connection.
## `credentials`
Review: `baseline`.
API: `present` — representative operation IDs:
- `POST /api/agents/me/connections/{connectionId}/start-authorization`.
Agent access: `partial` — Scoped start-authorization/request flow; human provider login.
Policy: Setup and credentials belong to the addressed authorized human; active-run tools
can search/request access.
Evidence: `source-only` —
[implementation](../../server/src/routes/connection-intents.ts#L130) 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: An initiation endpoint exists; it is not authorization to complete the person's
credential flow.
## `handoff`
Review: `baseline`.
API: `present` — representative operation IDs:
- `POST /api/connection-intents/{interactionId}/complete`.
Agent access: `restricted` — Addressed-user completion; server wakes the agent with
updated access.
Policy: Setup and credentials belong to the addressed authorized human; active-run tools
can search/request access.
Evidence: `source-only` —
[implementation](../../server/src/routes/connection-intents.ts#L130) at the reviewed
commit above.
Verification: `not-run` — assert the documented agent denial with an owned test fixture;
verify any listed agent request/result path separately. A delegated operation needs its
own policy and access review.
Gaps: OAuth/callback and addressed-user checks are deliberate separate boundaries.
## `draft-recovery`
Review: `baseline`.
API: `present` — representative operation IDs:
- `POST /api/connection-intents/{interactionId}/phase`.
- `POST /api/tool-connections/{connectionId}/reconnect`.
Agent access: `restricted` — Human setup/resume APIs; agent request state and
continuation.
Policy: Setup and credentials belong to the addressed authorized human; active-run tools
can search/request access.
Evidence: `source-only` —
[implementation](../../server/src/routes/connection-intents.ts#L130) at the reviewed
commit above.
Verification: `not-run` — assert the documented agent denial with an owned test fixture;
verify any listed agent request/result path separately. A delegated operation needs its
own policy and access review.
Gaps: Board setup recovery exists. Browser-only navigation state is not automatically an
agent API gap.
## `task-request`
Review: `baseline`.
API: `present` — representative operation IDs:
- `POST /runtime-tools/connections/request`.
Agent access: `available` — Native connection_request / run-bound runtime-tools MCP.
Policy: Setup and credentials belong to the addressed authorized human; active-run tools
can search/request access.
Evidence: `source-only` —
[implementation](../../server/src/routes/connection-intents.ts#L130) 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: This is the existing agent bridge for human-required setup; do not invent a second
approval system.
## `channel-setup`
Review: `baseline`.
API: `present` — representative operation IDs:
- `POST /api/companies/{companyId}/chat-endpoints`.
Agent access: `restricted` — Board channel management; agent requests required setup.
Policy: Setup and credentials belong to the addressed authorized human; active-run tools
can search/request access.
Evidence: `source-only` —
[implementation](../../server/src/routes/connection-intents.ts#L130) at the reviewed
commit above.
Verification: `not-run` — assert the documented agent denial with an owned test fixture;
verify any listed agent request/result path separately. A delegated operation needs its
own policy and access review.
Gaps: Provider endpoint, represented agent and linked sender are operator choices today.
## `failure`
Review: `baseline`.
API: `present` — representative operation IDs:
- `POST /api/tool-connections/{connectionId}/health-check`.
Agent access: `partial` — Agent observes connection tool errors; board repair APIs.
Policy: Setup and credentials belong to the addressed authorized human; active-run tools
can search/request access.
Evidence: `source-only` —
[implementation](../../server/src/routes/connection-intents.ts#L130) 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: Error reporting and human repair exist; no generic agent permission to reconnect
accounts.
+99
View File
@@ -0,0 +1,99 @@
# Developer previews and diagnostic labs — agent access
Product map: [Developer previews and diagnostic labs](../feature-map/developer-labs.md).
Review date: 2026-10-12. Source commit: `f981fa3cc10cb8663a87dec60345fbff46d54d0a`.
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.
## `design`
Review: `baseline`.
API: `not-applicable` — No domain API required for static component examples; label this
as an explicit exception.
Agent access: `not-applicable` — Browser/Storybook / existing UI tooling.
Policy: Synthetic developer fixtures; no persisted company feature or agent authority
represented by the fixture.
Evidence: `source-only` — [implementation](../../ui/src/App.tsx) at the reviewed commit
above.
Verification: `not-run` — use the product recipe for the local/developer surface. Verify
listed shared-resource reads separately; local presentation alone is not agent API
evidence.
Gaps: No domain API required for static component examples; label this as an explicit
exception.
## `interaction-labs`
Review: `baseline`.
API: `not-applicable` — A synthetic card's API parity belongs to the real feature, not
to a new lab API.
Agent access: `not-applicable` — Browser fixture plus the corresponding real interaction
API in its owning area.
Policy: Synthetic developer fixtures; no persisted company feature or agent authority
represented by the fixture.
Evidence: `source-only` — [implementation](../../ui/src/App.tsx) at the reviewed commit
above.
Verification: `not-run` — use the product recipe for the local/developer surface. Verify
listed shared-resource reads separately; local presentation alone is not agent API
evidence.
Gaps: A synthetic card's API parity belongs to the real feature, not to a new lab API.
## `performance`
Review: `baseline`.
API: `not-applicable` — There is no domain REST action for scrolling a static fixture;
capture browser evidence separately.
Agent access: `not-applicable` — Browser performance fixture and measurement tooling.
Policy: Synthetic developer fixtures; no persisted company feature or agent authority
represented by the fixture.
Evidence: `source-only` — [implementation](../../ui/src/App.tsx) at the reviewed commit
above.
Verification: `not-run` — use the product recipe for the local/developer surface. Verify
listed shared-resource reads separately; local presentation alone is not agent API
evidence.
Gaps: There is no domain REST action for scrolling a static fixture; capture browser
evidence separately.
## `route-gates`
Review: `baseline`.
API: `not-applicable` — Route registration and feature gates are not interchangeable; no
universal developer-only gate exists.
Agent access: `not-applicable` — Build/route inspection; relevant instance
feature-setting API for actual gates.
Policy: Synthetic developer fixtures; no persisted company feature or agent authority
represented by the fixture.
Evidence: `source-only` — [implementation](../../ui/src/App.tsx) at the reviewed commit
above.
Verification: `not-run` — use the product recipe for the local/developer surface. Verify
listed shared-resource reads separately; local presentation alone is not agent API
evidence.
Gaps: Route registration and feature gates are not interchangeable; no universal
developer-only gate exists.
@@ -0,0 +1,139 @@
# Documents, attachments, and work products — agent access
Product map: [Documents, attachments, and work
products](../feature-map/documents-artifacts.md).
Review date: 2026-10-12. Source commit: `f981fa3cc10cb8663a87dec60345fbff46d54d0a`.
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.
## `documents`
Review: `baseline`.
API: `present` — representative operation IDs:
- `GET /api/issues/{id}/documents`.
- `PUT /api/issues/{id}/documents/{key}`.
- `POST /api/issues/{id}/documents/{key}/revisions/{revisionId}/restore`.
Agent access: `available` — Native list/read/write documents; other-task bridge; REST /
CLI / MCP.
Policy: Task/resource visibility, mutation/checkout ownership, revision/lock guards and
permitted deliverable context.
Evidence: `source-only` — [implementation](../../server/src/routes/issues.ts#L10299) 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: Supported. Native helpers focus on the active task; generic API or explicit
other-task tools cover additional scope.
## `annotations`
Review: `baseline`.
API: `present` — representative operation IDs:
- `POST /api/issues/{id}/documents/{key}/annotations`.
- `PATCH /api/issues/{id}/documents/{key}/annotations/{threadId}`.
Agent access: `available` — REST / native call_api.
Policy: Task/resource visibility, mutation/checkout ownership, revision/lock guards and
permitted deliverable context.
Evidence: `source-only` — [implementation](../../server/src/routes/issues.ts#L10299) 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: Annotation operations exist without a special annotation tool; check revision
anchors and resolver authority.
## `attachments`
Review: `baseline`.
API: `present` — representative operation IDs:
- `POST /api/companies/{companyId}/issues/{issueId}/attachments`.
- `GET /api/assets/{assetId}/content`.
Agent access: `available` — Native register_deliverable and API multipart/binary
support; REST / CLI / MCP transfers.
Policy: Task/resource visibility, mutation/checkout ownership, revision/lock guards and
permitted deliverable context.
Evidence: `source-only` — [implementation](../../server/src/routes/issues.ts#L10299) 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: Native API uploads are bounded; attachment reading has target/provider and
permission conditions.
## `work-products`
Review: `baseline`.
API: `present` — representative operation IDs:
- `POST /api/issues/{id}/work-products`.
- `PATCH /api/work-products/{id}`.
Agent access: `available` — Native register_deliverable for file outputs; REST / native
call_api for metadata.
Policy: Task/resource visibility, mutation/checkout ownership, revision/lock guards and
permitted deliverable context.
Evidence: `source-only` — [implementation](../../server/src/routes/issues.ts#L10299) 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: A registered reference does not prove uploaded bytes, external delivery, or
accepted review.
## `library`
Review: `baseline`.
API: `present` — representative operation IDs:
- `GET /api/companies/{companyId}/artifacts`.
Agent access: `available` — REST / native call_api.
Policy: Task/resource visibility, mutation/checkout ownership, revision/lock guards and
permitted deliverable context.
Evidence: `source-only` — [implementation](../../server/src/routes/issues.ts#L10299) 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: Library search/filter uses the artifact API; no new tool needed merely to mirror
the UI.
@@ -0,0 +1,132 @@
# Local, SSH, and sandbox environments — agent access
Product map: [Local, SSH, and sandbox
environments](../feature-map/execution-environments.md).
Review date: 2026-10-12. Source commit: `f981fa3cc10cb8663a87dec60345fbff46d54d0a`.
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.
## `configuration`
Review: `baseline`.
API: `present` — representative operation IDs:
- `GET /api/companies/{companyId}/environments`.
- `POST /api/companies/{companyId}/environments`.
Agent access: `restricted` — Board read/admin management REST / CLI environment.
Policy: Environment management is instance administrator/board; permitted assignment
uses agent/project policy.
Evidence: `source-only` — [implementation](../../server/src/routes/environments.ts#L353)
at the reviewed commit above.
Verification: `not-run` — assert the documented agent denial with an owned test fixture;
verify any listed agent request/result path separately. A delegated operation needs its
own policy and access review.
Gaps: API exists; an agent cannot use instance environment management as an ordinary
company actor.
## `capabilities`
Review: `baseline`.
API: `present` — representative operation IDs:
- `GET /api/companies/{companyId}/environments/capabilities`.
Agent access: `partial` — Board environment capabilities endpoint; native run gets
server-selected runtime context.
Policy: Environment management is instance administrator/board; permitted assignment
uses agent/project policy.
Evidence: `source-only` — [implementation](../../server/src/routes/environments.ts#L353)
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: Endpoint discovery and already-bound run capabilities differ; decide whether a
safe agent-readable capability listing is desired.
## `probe`
Review: `baseline`.
API: `present` — representative operation IDs:
- `POST /api/environments/{id}/probe`.
- `POST /api/companies/{companyId}/environments/probe-config`.
Agent access: `restricted` — Board/admin probes / CLI environment.
Policy: Environment management is instance administrator/board; permitted assignment
uses agent/project policy.
Evidence: `source-only` — [implementation](../../server/src/routes/environments.ts#L353)
at the reviewed commit above.
Verification: `not-run` — assert the documented agent denial with an owned test fixture;
verify any listed agent request/result path separately. A delegated operation needs its
own policy and access review.
Gaps: Reachability probes are not granted by an agent's right to execute assigned work.
## `assignment`
Review: `baseline`.
API: `present` — representative operation IDs:
- `PATCH /api/agents/{id}`.
- `PATCH /api/projects/{id}`.
Agent access: `partial` — Permitted agent/project REST / native fallback, subject to
protected configuration policy.
Policy: Environment management is instance administrator/board; permitted assignment
uses agent/project policy.
Evidence: `source-only` — [implementation](../../server/src/routes/environments.ts#L353)
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: Choosing among permitted targets differs from creating/configuring host targets;
test authorized and denied selection.
## `images`
Review: `baseline`.
API: `present` — representative operation IDs:
- `POST /api/environments/{environmentId}/custom-image-setup-sessions`.
Agent access: `restricted` — Board/admin image APIs and existing terminal protocol.
Policy: Environment management is instance administrator/board; permitted assignment
uses agent/project policy.
Evidence: `source-only` — [implementation](../../server/src/routes/environments.ts#L353)
at the reviewed commit above.
Verification: `not-run` — assert the documented agent denial with an owned test fixture;
verify any listed agent request/result path separately. A delegated operation needs its
own policy and access review.
Gaps: No default agent custom-image administration/terminal path; this is a policy
decision before adding a tool.
+131
View File
@@ -0,0 +1,131 @@
# Tool gateways and access profiles — agent access
Product map: [Tool gateways and access profiles](../feature-map/gateways-profiles.md).
Review date: 2026-10-12. Source commit: `f981fa3cc10cb8663a87dec60345fbff46d54d0a`.
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.
## `gateway`
Review: `baseline`.
API: `present` — representative operation IDs:
- `POST /api/companies/{companyId}/tools/gateways`.
Agent access: `restricted` — Board tools:admin REST; CLI connections/configuration where
supported.
Policy: Named gateway/profile administration and credentials are board tools:admin;
agent sessions/tool use use separate scoped authority.
Evidence: `source-only` — [implementation](../../server/src/routes/tool-gateway.ts#L353)
at the reviewed commit above.
Verification: `not-run` — assert the documented agent denial with an owned test fixture;
verify any listed agent request/result path separately. A delegated operation needs its
own policy and access review.
Gaps: No agent named-gateway management path; assigned tool use exists separately.
## `profiles`
Review: `baseline`.
API: `present` — representative operation IDs:
- `POST /api/companies/{companyId}/tools/profiles`.
- `PATCH /api/tool-profiles/{profileId}`.
Agent access: `restricted` — Board management REST; agent receives effective tool
assignment.
Policy: Named gateway/profile administration and credentials are board tools:admin;
agent sessions/tool use use separate scoped authority.
Evidence: `source-only` — [implementation](../../server/src/routes/tool-gateway.ts#L353)
at the reviewed commit above.
Verification: `not-run` — assert the documented agent denial with an owned test fixture;
verify any listed agent request/result path separately. A delegated operation needs its
own policy and access review.
Gaps: Agent access to tools does not permit profile editing.
## `client-connect`
Review: `baseline`.
API: `present` — representative operation IDs:
- `GET /api/tool-gateway/gateways/{gatewayId}/mcp`.
- `POST /api/tool-gateway/sessions`.
Agent access: `partial` — Existing scoped MCP client/session flow; assigned native app
tools.
Policy: Named gateway/profile administration and credentials are board tools:admin;
agent sessions/tool use use separate scoped authority.
Evidence: `source-only` — [implementation](../../server/src/routes/tool-gateway.ts#L353)
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: Agent tool consumption exists. Copying/managing the endpoint and its client
credentials remain management operations.
## `tokens`
Review: `baseline`.
API: `present` — representative operation IDs:
- `POST /api/tool-gateway/gateways/{gatewayId}/tokens`.
- `POST /api/tool-gateway/gateway-tokens/{tokenId}/revoke`.
Agent access: `restricted` — Board tools:admin token management.
Policy: Named gateway/profile administration and credentials are board tools:admin;
agent sessions/tool use use separate scoped authority.
Evidence: `source-only` — [implementation](../../server/src/routes/tool-gateway.ts#L353)
at the reviewed commit above.
Verification: `not-run` — assert the documented agent denial with an owned test fixture;
verify any listed agent request/result path separately. A delegated operation needs its
own policy and access review.
Gaps: Native call_api blocks credential management; a grant to use an app does not
create gateway-token authority.
## `activity`
Review: `baseline`.
API: `present` — representative operation IDs:
- `GET /api/tool-gateway/audit`.
Agent access: `restricted` — Board tools:view_audit; agent receives its own tool
receipts/errors.
Policy: Named gateway/profile administration and credentials are board tools:admin;
agent sessions/tool use use separate scoped authority.
Evidence: `source-only` — [implementation](../../server/src/routes/tool-gateway.ts#L353)
at the reviewed commit above.
Verification: `not-run` — assert the documented agent denial with an owned test fixture;
verify any listed agent request/result path separately. A delegated operation needs its
own policy and access review.
Gaps: Audit management API exists but broad audit visibility is not an agent use-path
guarantee.
+87
View File
@@ -0,0 +1,87 @@
# Goals and work alignment — agent access
Product map: [Goals and work alignment](../feature-map/goals.md).
Review date: 2026-10-12. Source commit: `f981fa3cc10cb8663a87dec60345fbff46d54d0a`.
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.
## `hierarchy`
Review: `baseline`.
API: `present` — representative operation IDs:
- `GET /api/companies/{companyId}/goals`.
- `POST /api/companies/{companyId}/goals`.
- `PATCH /api/goals/{id}`.
Agent access: `available` — REST / native call_api / CLI goal / MCP read helpers.
Policy: Same-company access; related project/task assignments have their own resource
permissions.
Evidence: `source-only` — [implementation](../../server/src/routes/goals.ts#L14) 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: Real REST path exists. Scenario list_goals declarations are not evidence of a
production native binding.
## `alignment`
Review: `baseline`.
API: `present` — representative operation IDs:
- `PATCH /api/projects/{id}`.
- `PATCH /api/issues/{id}`.
Agent access: `available` — REST / native call_api for permitted non-lifecycle fields.
Policy: Same-company access; related project/task assignments have their own resource
permissions.
Evidence: `source-only` — [implementation](../../server/src/routes/goals.ts#L14) 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: Goal association is data access, separate from completing or reassigning the task.
## `navigation`
Review: `baseline`.
API: `present` — representative operation IDs:
- `GET /api/goals/{id}`.
- `GET /api/projects/{id}`.
- `GET /api/issues/{id}`.
Agent access: `available` — REST and task/project/goal read tools; links returned as
context.
Policy: Same-company access; related project/task assignments have their own resource
permissions.
Evidence: `source-only` — [implementation](../../server/src/routes/goals.ts#L14) 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: Navigation renders records already exposed by APIs; no separate click-navigation
API is required.
+112
View File
@@ -0,0 +1,112 @@
# Inbox, decisions, and search — agent access
Product map: [Inbox, decisions, and search](../feature-map/inbox-search.md).
Review date: 2026-10-12. Source commit: `f981fa3cc10cb8663a87dec60345fbff46d54d0a`.
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.
## `views`
Review: `baseline`.
API: `present` — representative operation IDs:
- `GET /api/agents/me/inbox-lite`.
- `GET /api/agents/me/inbox/mine`.
- `GET /api/companies/{companyId}/issues`.
Agent access: `partial` — REST / native call_api; MCP inbox/task search.
Policy: Own agent context; responsible-user inbox policy and explicit opt-in/grants for
cross-user archive; decision policy separately.
Evidence: `source-only` — [implementation](../../server/src/routes/agents.ts#L3952) 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: Agent inbox and Mine support exist; board attention/unread/dismissal aggregation
is a separate user-only surface.
## `triage`
Review: `baseline`.
API: `present` — representative operation IDs:
- `POST /api/issues/{id}/inbox-archive`.
- `DELETE /api/issues/{id}/inbox-archive`.
Agent access: `partial` — REST / native call_api; existing garden-inbox workflow.
Policy: Own agent context; responsible-user inbox policy and explicit opt-in/grants for
cross-user archive; decision policy separately.
Evidence: `source-only` — [implementation](../../server/src/routes/agents.ts#L3952) 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: Archive has an agent-aware responsible-user policy. Personal read/unread/dismissal
does not have equivalent agent semantics everywhere.
## `decisions`
Review: `baseline`.
API: `present` — representative operation IDs:
- `GET /api/companies/{companyId}/decision-queues`.
- `GET /api/companies/{companyId}/decision-queues/{key}/items`.
Agent access: `partial` — REST / native call_api under decision queue authorization.
Policy: Own agent context; responsible-user inbox policy and explicit opt-in/grants for
cross-user archive; decision policy separately.
Evidence: `source-only` — [implementation](../../server/src/routes/agents.ts#L3952) 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: Queue browsing/managing may be allowed; governed approval decisions still have
separate board/resolver boundaries.
## `search`
Review: `baseline`.
API: `present` — representative operation IDs:
- `GET /api/companies/{companyId}/search`.
- `GET /api/companies/{companyId}/issues`.
Agent access: `available` — Native search_tasks for tasks; REST / native call_api for
broader search.
Policy: Own agent context; responsible-user inbox policy and explicit opt-in/grants for
cross-user archive; decision policy separately.
Evidence: `source-only` — [implementation](../../server/src/routes/agents.ts#L3952) 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: General company search and dedicated task search are different result sets; use
the appropriate one.
@@ -0,0 +1,130 @@
# Installation, configuration, updates, and backups — agent access
Product map: [Installation, configuration, updates, and
backups](../feature-map/instance-operations.md).
Review date: 2026-10-12. Source commit: `f981fa3cc10cb8663a87dec60345fbff46d54d0a`.
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.
## `install-update`
Review: `baseline`.
API: `not-applicable` — No uniform company REST updater API. Treat pre-start
installation as an operator exception or design an explicit delegated operator API.
Agent access: `operator-only` — Existing CLI install/update/rollback commands.
Policy: Local machine operator and instance-administrator authority; distinct from
company-scoped agent keys.
Evidence: `source-only` — [implementation](../../cli/src/index.ts#L91) at the reviewed
commit above.
Verification: `not-run` — exercise the listed local workflow in an authorized, owned
operator environment. Verify its isolation and result; do not count local machine
authority as company-agent API access.
Gaps: No uniform company REST updater API. Treat pre-start installation as an operator
exception or design an explicit delegated operator API.
## `server-service`
Review: `baseline`.
API: `present` — representative operation IDs:
- `GET /api/health`.
Agent access: `operator-only` — Existing CLI service/dev controls; health REST; owned
workspace services have separate agent APIs.
Policy: Local machine operator and instance-administrator authority; distinct from
company-scoped agent keys.
Evidence: `source-only` — [implementation](../../cli/src/index.ts#L91) at the reviewed
commit above.
Verification: `not-run` — exercise the listed local workflow in an authorized, owned
operator environment. Verify its isolation and result; do not count local machine
authority as company-agent API access.
Gaps: Instance start/stop and task workspace start/stop are different capabilities.
Local service control is not agent company authority.
## `configuration`
Review: `baseline`.
API: `present` — representative operation IDs:
- `GET /api/instance/settings`.
- `PATCH /api/instance/settings`.
Agent access: `restricted` — Board/admin instance settings; CLI configure/env; local
configuration files.
Policy: Local machine operator and instance-administrator authority; distinct from
company-scoped agent keys.
Evidence: `source-only` — [implementation](../../cli/src/index.ts#L91) at the reviewed
commit above.
Verification: `not-run` — assert the documented agent denial with an owned test fixture;
verify any listed agent request/result path separately. A delegated operation needs its
own policy and access review.
Gaps: Settings APIs cover parts of configuration; pre-start database/binding/storage
configuration is local operator tooling.
## `diagnostics`
Review: `baseline`.
API: `present` — representative operation IDs:
- `GET /api/health`.
Agent access: `partial` — REST health plus local CLI doctor.
Policy: Local machine operator and instance-administrator authority; distinct from
company-scoped agent keys.
Evidence: `source-only` — [implementation](../../cli/src/index.ts#L91) 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: Health is an API; full local doctor/repair inspects host configuration and is not
equivalent to that response.
## `backup`
Review: `baseline`.
API: `present` — representative operation IDs:
- `POST /api/instance/database-backups`.
Agent access: `restricted` — Board/admin backup API; local CLI db:backup; restore into
an authorized separate target.
Policy: Local machine operator and instance-administrator authority; distinct from
company-scoped agent keys.
Evidence: `source-only` — [implementation](../../cli/src/index.ts#L91) at the reviewed
commit above.
Verification: `not-run` — assert the documented agent denial with an owned test fixture;
verify any listed agent request/result path separately. A delegated operation needs its
own policy and access review.
Gaps: API creation exists. Restore/lifecycle are operator workflows rather than ordinary
company agent capabilities.
@@ -0,0 +1,138 @@
# Navigation, profile, and announcements — agent access
Product map: [Navigation, profile, and
announcements](../feature-map/navigation-preferences.md).
Review date: 2026-10-12. Source commit: `f981fa3cc10cb8663a87dec60345fbff46d54d0a`.
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.
## `navigation`
Review: `baseline`.
API: `present` — representative operation IDs:
- `GET /api/companies/{companyId}/projects`.
- `GET /api/companies/{companyId}/resource-memberships/me`.
Agent access: `partial` — Resource APIs plus user-specific stars; browser-local recents.
Policy: Persisted user preferences require board user context; resource reads still
apply company visibility.
Evidence: `source-only` —
[implementation](../../server/src/routes/sidebar-preferences.ts#L8) 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: Underlying resources have APIs; recents are client-local, and personal starring
needs its own identity policy.
## `preferences`
Review: `baseline`.
API: `present` — representative operation IDs:
- `GET /api/sidebar-preferences/me`.
- `PUT /api/sidebar-preferences/me`.
Agent access: `restricted` — Board-user preference API; browser section collapse.
Policy: Persisted user preferences require board user context; resource reads still
apply company visibility.
Evidence: `source-only` —
[implementation](../../server/src/routes/sidebar-preferences.ts#L8) at the reviewed
commit above.
Verification: `not-run` — assert the documented agent denial with an owned test fixture;
verify any listed agent request/result path separately. A delegated operation needs its
own policy and access review.
Gaps: Catalog metadata says board_or_agent, but requireBoardUserId rejects agents.
Collapse is in-memory; global collapse is disabled.
## `profile`
Review: `baseline`.
API: `present` — representative operation IDs:
- `GET /api/companies/{companyId}/users/{userSlug}/profile`.
- `PATCH /api/auth/profile`.
Agent access: `partial` — Agent can read eligible company profile; changing personal
identity requires board user.
Policy: Persisted user preferences require board user context; resource reads still
apply company visibility.
Evidence: `source-only` —
[implementation](../../server/src/routes/sidebar-preferences.ts#L8) 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: Reading another visible user's profile and editing a person's identity are
distinct permission paths.
## `announcements`
Review: `baseline`.
API: `present` — representative operation IDs:
- `GET /api/announcements/current`.
- `POST /api/announcements/{id}/dismiss`.
Agent access: `restricted` — Board-user announcement API.
Policy: Persisted user preferences require board user context; resource reads still
apply company visibility.
Evidence: `source-only` —
[implementation](../../server/src/routes/sidebar-preferences.ts#L8) at the reviewed
commit above.
Verification: `not-run` — assert the documented agent denial with an owned test fixture;
verify any listed agent request/result path separately. A delegated operation needs its
own policy and access review.
Gaps: User-specific instance-wide dismissal has no agent delegation path today.
## `fallbacks`
Review: `baseline`.
API: `present` — representative operation IDs:
- `GET /api/issues/{id}`.
- `GET /api/projects/{id}`.
Agent access: `partial` — API not-found/access semantics; browser router redirects.
Policy: Persisted user preferences require board user context; resource reads still
apply company visibility.
Evidence: `source-only` —
[implementation](../../server/src/routes/sidebar-preferences.ts#L8) at the reviewed
commit above.
Verification: `not-run` — use the product recipe for the local/developer surface. Verify
listed shared-resource reads separately; local presentation alone is not agent API
evidence.
Gaps: Record lookup exists. Route redirects/fallback presentation do not need a separate
domain API.
+136
View File
@@ -0,0 +1,136 @@
# Onboarding and first work — agent access
Product map: [Onboarding and first work](../feature-map/onboarding.md).
Review date: 2026-10-12. Source commit: `f981fa3cc10cb8663a87dec60345fbff46d54d0a`.
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.
## `instance`
Review: `baseline`.
API: `not-applicable` — Bootstrapping an instance cannot depend solely on an API served
by that not-yet-running instance.
Agent access: `operator-only` — Existing CLI onboard/run/doctor / test-drive.
Policy: Instance setup is operator work; company creation is board; agent creation/task
creation retain their individual permissions.
Evidence: `source-only` —
[implementation](../../ui/src/components/OnboardingWizard.tsx#L279) at the reviewed
commit above.
Verification: `not-run` — exercise the listed local workflow in an authorized, owned
operator environment. Verify its isolation and result; do not count local machine
authority as company-agent API access.
Gaps: Bootstrapping an instance cannot depend solely on an API served by that
not-yet-running instance.
## `company`
Review: `baseline`.
API: `present` — representative operation IDs:
- `POST /api/companies`.
- `POST /api/companies/{companyId}/agents`.
Agent access: `partial` — Board company creation; authorized in-company agent hiring
API.
Policy: Instance setup is operator work; company creation is board; agent creation/task
creation retain their individual permissions.
Evidence: `source-only` —
[implementation](../../ui/src/components/OnboardingWizard.tsx#L279) 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: API building blocks exist; an ordinary agent cannot create its parent company with
a company key.
## `adapter`
Review: `baseline`.
API: `present` — representative operation IDs:
- `GET /api/companies/{companyId}/adapters/{type}/models`.
- `POST /api/companies/{companyId}/adapters/{type}/test-environment`.
Agent access: `partial` — Permitted agent/model API; operator
provider-account/environment setup.
Policy: Instance setup is operator work; company creation is board; agent creation/task
creation retain their individual permissions.
Evidence: `source-only` —
[implementation](../../ui/src/components/OnboardingWizard.tsx#L279) 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: Account authorization, environment administration and model selection need
separate checks.
## `first-task`
Review: `baseline`.
API: `present` — representative operation IDs:
- `POST /api/companies/{companyId}/issues`.
Agent access: `available` — Native create_task / agent REST / CLI issue.
Policy: Instance setup is operator work; company creation is board; agent creation/task
creation retain their individual permissions.
Evidence: `source-only` —
[implementation](../../ui/src/components/OnboardingWizard.tsx#L279) 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: Task creation is agent-accessible where permitted; scheduling/readiness does not
follow from successful creation.
## `resume`
Review: `baseline`.
API: `not-applicable` — No server onboarding-draft API for this browser-local state;
classify explicitly or intentionally make it a cross-client product feature.
Agent access: `not-applicable` — Browser localStorage wizard draft; persisted resources
use their domain APIs.
Policy: Instance setup is operator work; company creation is board; agent creation/task
creation retain their individual permissions.
Evidence: `source-only` —
[implementation](../../ui/src/components/OnboardingWizard.tsx#L279) at the reviewed
commit above.
Verification: `not-run` — use the product recipe for the local/developer surface. Verify
listed shared-resource reads separately; local presentation alone is not agent API
evidence.
Gaps: No server onboarding-draft API for this browser-local state; classify explicitly
or intentionally make it a cross-client product feature.
+109
View File
@@ -0,0 +1,109 @@
# Pipelines, review queues, and learnings — agent access
Product map: [Pipelines, review queues, and learnings](../feature-map/pipelines.md).
Review date: 2026-10-12. Source commit: `f981fa3cc10cb8663a87dec60345fbff46d54d0a`.
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.
## `stages`
Review: `baseline`.
API: `present` — representative operation IDs:
- `POST /api/pipelines/{pipelineId}/stages`.
- `PATCH /api/pipelines/{pipelineId}/stages/{stageId}`.
Agent access: `available` — REST / native call_api / CLI pipelines where supported.
Policy: Company access, active agent run for mutations, case/issue source trust and
ownership, and review audience.
Evidence: `source-only` — [implementation](../../server/src/routes/pipelines.ts#L265) 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: Configuration paths exist. Generic fallback blocks case automation execution
paths; do not conflate configuration and dispatch.
## `items`
Review: `baseline`.
API: `present` — representative operation IDs:
- `GET /api/pipelines/{pipelineId}/cases`.
- `POST /api/pipelines/{pipelineId}/cases`.
Agent access: `available` — REST / native call_api / CLI pipelines.
Policy: Company access, active agent run for mutations, case/issue source trust and
ownership, and review audience.
Evidence: `source-only` — [implementation](../../server/src/routes/pipelines.ts#L265) 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: Agents need run ID on mutations; task-linked changes also check issue
mutation/checkout ownership.
## `review`
Review: `baseline`.
API: `present` — representative operation IDs:
- `GET /api/companies/{companyId}/review-cases`.
- `POST /api/cases/{caseId}/review`.
Agent access: `available` — REST / native call_api / CLI pipeline case review.
Policy: Company access, active agent run for mutations, case/issue source trust and
ownership, and review audience.
Evidence: `source-only` — [implementation](../../server/src/routes/pipelines.ts#L265) 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: Review policy and actor ownership still apply; existence of the endpoint is not
blanket review authority.
## `learnings`
Review: `baseline`.
API: `present` — representative operation IDs:
- `GET /api/companies/{companyId}/case-events`.
Agent access: `available` — REST / native call_api / CLI case events.
Policy: Company access, active agent run for mutations, case/issue source trust and
ownership, and review audience.
Evidence: `source-only` — [implementation](../../server/src/routes/pipelines.ts#L265) 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: Learning view is a filtered case-event projection; no separate learning API is
necessary.
+107
View File
@@ -0,0 +1,107 @@
# Plugins and contributed product surfaces — agent access
Product map: [Plugins and contributed product surfaces](../feature-map/plugins.md).
Review date: 2026-10-12. Source commit: `f981fa3cc10cb8663a87dec60345fbff46d54d0a`.
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.
## `installation`
Review: `baseline`.
API: `present` — representative operation IDs:
- `POST /api/plugins/install`.
Agent access: `restricted` — Instance-admin REST / CLI plugin.
Policy: Instance plugin management requires board/admin; declared tools and scoped APIs
apply their own company/agent policy.
Evidence: `source-only` — [implementation](../../server/src/routes/plugins.ts#L965) at
the reviewed commit above.
Verification: `not-run` — assert the documented agent denial with an owned test fixture;
verify any listed agent request/result path separately. A delegated operation needs its
own policy and access review.
Gaps: No ordinary agent install path; installing executable plugin code is an explicit
authority decision.
## `configuration`
Review: `baseline`.
API: `present` — representative operation IDs:
- `GET /api/plugins/{pluginId}/config`.
- `POST /api/plugins/{pluginId}/config`.
Agent access: `restricted` — Board read/admin write; CLI plugin.
Policy: Instance plugin management requires board/admin; declared tools and scoped APIs
apply their own company/agent policy.
Evidence: `source-only` — [implementation](../../server/src/routes/plugins.ts#L965) at
the reviewed commit above.
Verification: `not-run` — assert the documented agent denial with an owned test fixture;
verify any listed agent request/result path separately. A delegated operation needs its
own policy and access review.
Gaps: Company-scoped configuration value does not turn the instance management route
into an agent route.
## `contributions`
Review: `baseline`.
API: `present` — representative operation IDs:
- `GET /api/plugins/tools`.
- `POST /api/plugins/tools/execute`.
Agent access: `partial` — Agent REST plus assigned native/gateway plugin tools and
scoped plugin APIs.
Policy: Instance plugin management requires board/admin; declared tools and scoped APIs
apply their own company/agent policy.
Evidence: `source-only` — [implementation](../../server/src/routes/plugins.ts#L965) 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: Actual plugin tool use exists; a contributed UI route alone does not prove that
plugin's API/tool coverage.
## `lifecycle`
Review: `baseline`.
API: `present` — representative operation IDs:
- `POST /api/plugins/{pluginId}/enable`.
- `POST /api/plugins/{pluginId}/disable`.
Agent access: `restricted` — Instance-admin REST / CLI plugin; dev watcher for reload.
Policy: Instance plugin management requires board/admin; declared tools and scoped APIs
apply their own company/agent policy.
Evidence: `source-only` — [implementation](../../server/src/routes/plugins.ts#L965) at
the reviewed commit above.
Verification: `not-run` — assert the documented agent denial with an owned test fixture;
verify any listed agent request/result path separately. A delegated operation needs its
own policy and access review.
Gaps: Disable/remove and development reload are management workflows with no default
company agent access.
+113
View File
@@ -0,0 +1,113 @@
# Projects and repositories — agent access
Product map: [Projects and repositories](../feature-map/projects.md).
Review date: 2026-10-12. Source commit: `f981fa3cc10cb8663a87dec60345fbff46d54d0a`.
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.
## `lifecycle`
Review: `baseline`.
API: `present` — representative operation IDs:
- `POST /api/companies/{companyId}/projects`.
- `PATCH /api/projects/{id}`.
- `DELETE /api/projects/{id}`.
Agent access: `available` — Native create_project/list_projects; REST / CLI / MCP.
Policy: Company/project visibility, protected configuration/runtime policies; some
repository/privacy management requires board.
Evidence: `source-only` — [implementation](../../server/src/routes/projects.ts#L278) 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: Actual data operations exist; project discovery and private-resource permissions
still apply.
## `task-context`
Review: `baseline`.
API: `present` — representative operation IDs:
- `GET /api/companies/{companyId}/issues`.
- `POST /api/companies/{companyId}/issues`.
Agent access: `available` — Native create_task/search_tasks; REST / CLI / MCP.
Policy: Company/project visibility, protected configuration/runtime policies; some
repository/privacy management requires board.
Evidence: `source-only` — [implementation](../../server/src/routes/projects.ts#L278) 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: Use explicit project context; task creation, assignment, and execution remain
separate checks.
## `repositories`
Review: `baseline`.
API: `present` — representative operation IDs:
- `GET /api/companies/{companyId}/project-repositories`.
- `PUT /api/projects/{id}/repositories`.
Agent access: `partial` — Native list_project_repositories/create_project for initial
selection; board-only replacement API.
Policy: Company/project visibility, protected configuration/runtime policies; some
repository/privacy management requires board.
Evidence: `source-only` — [implementation](../../server/src/routes/projects.ts#L278) 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: Authorized initial selection works. Replacement of repositories on an existing
project hard-requires board and needs a delegation decision.
## `defaults`
Review: `baseline`.
API: `present` — representative operation IDs:
- `PATCH /api/projects/{id}`.
- `GET /api/projects/{id}/workspaces`.
Agent access: `partial` — REST / native call_api for permitted fields; CLI
project/workspace.
Policy: Company/project visibility, protected configuration/runtime policies; some
repository/privacy management requires board.
Evidence: `source-only` — [implementation](../../server/src/routes/projects.ts#L278) 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: Description/goal/target selection exist; host workspace command mutation is denied
to agents and budget policy is board-managed.
@@ -0,0 +1,212 @@
# Questions and approvals — agent access
Product map: [Questions and approvals](../feature-map/questions-and-approvals.md).
Review date: 2026-10-12. Source commit: `f981fa3cc10cb8663a87dec60345fbff46d54d0a`.
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.
## `questions`
Review: `baseline`.
API: `present` — representative operation IDs:
- `POST /api/issues/{id}/interactions`.
- `POST /api/issues/{id}/interactions/{interactionId}/respond`.
Agent access: `partial` — Native request_human_input; REST / MCP forms; authorized
responder endpoint.
Policy: Current task/run and named audience/resolver policy; governed approval decisions
require board independently of an ordinary interaction.
Evidence: `source-only` — [implementation](../../server/src/routes/issues.ts#L16638) 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: Agent creates questions. It cannot fabricate a human answer; answering follows
resolver policy.
## `dismiss-and-reopen`
Review: `baseline`.
API: `present` — representative operation IDs:
- `GET /api/issues/{id}/interactions`.
Agent access: `partial` — Persisted question API plus browser card state.
Policy: Current task/run and named audience/resolver policy; governed approval decisions
require board independently of an ordinary interaction.
Evidence: `source-only` — [implementation](../../server/src/routes/issues.ts#L16638) at
the reviewed commit above.
Verification: `not-run` — use the product recipe for the local/developer surface. Verify
listed shared-resource reads separately; local presentation alone is not agent API
evidence.
Gaps: Presentation dismissal/reopening does not resolve the question and does not
require a new mutation API.
## `confirmations`
Review: `baseline`.
API: `present` — representative operation IDs:
- `POST /api/issues/{id}/interactions`.
- `POST /api/issues/{id}/interactions/{interactionId}/resolve-from-comment`.
Agent access: `partial` — Native request_human_input and call_api resolve-from-comment;
authorized REST resolver.
Policy: Current task/run and named audience/resolver policy; governed approval decisions
require board independently of an ordinary interaction.
Evidence: `source-only` — [implementation](../../server/src/routes/issues.ts#L16638) 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: Conversational confirmation is supported under resolver policy; generic
acceptance/response controls remain restricted.
## `plan-review`
Review: `baseline`.
API: `present` — representative operation IDs:
- `PUT /api/issues/{id}/documents/{key}`.
- `POST /api/issues/{id}/interactions`.
Agent access: `partial` — Native write_document/request_human_input; explicit review
recipient.
Policy: Current task/run and named audience/resolver policy; governed approval decisions
require board independently of an ordinary interaction.
Evidence: `source-only` — [implementation](../../server/src/routes/issues.ts#L16638) 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: Plan revision and confirmation work. Accepting as a human is not a generic agent
capability.
## `audience`
Review: `baseline`.
API: `present` — representative operation IDs:
- `GET /api/issues/{id}/interactions`.
Agent access: `available` — API resolver checks; assigned review context/resolve_review
for a native review run.
Policy: Current task/run and named audience/resolver policy; governed approval decisions
require board independently of an ordinary interaction.
Evidence: `source-only` — [implementation](../../server/src/routes/issues.ts#L16638) 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: Audience is a permission boundary to test, not an endpoint that creates new
authority.
## `governance`
Review: `baseline`.
API: `present` — representative operation IDs:
- `POST /api/companies/{companyId}/approvals`.
- `POST /api/approvals/{id}/approve`.
- `POST /api/approvals/{id}/reject`.
Agent access: `restricted` — Agent REST/MCP can request/read/comment/resubmit; formal
approve/reject require board.
Policy: Current task/run and named audience/resolver policy; governed approval decisions
require board independently of an ordinary interaction.
Evidence: `source-only` — [implementation](../../server/src/routes/issues.ts#L16638) at
the reviewed commit above.
Verification: `not-run` — assert the documented agent denial with an owned test fixture;
verify any listed agent request/result path separately. A delegated operation needs its
own policy and access review.
Gaps: Scenario decide_approval does not establish a production agent approval path.
Preserve explicit approver authority.
## `tool-review`
Review: `baseline`.
API: `present` — representative operation IDs:
- `POST /api/tool-gateway/action-requests/{id}/approve`.
- `POST /api/tool-gateway/action-requests/{id}/decline`.
Agent access: `restricted` — Agent invokes assigned ask-policy tool; board approval
executes stored request.
Policy: Current task/run and named audience/resolver policy; governed approval decisions
require board independently of an ordinary interaction.
Evidence: `source-only` — [implementation](../../server/src/routes/issues.ts#L16638) at
the reviewed commit above.
Verification: `not-run` — assert the documented agent denial with an owned test fixture;
verify any listed agent request/result path separately. A delegated operation needs its
own policy and access review.
Gaps: The request/continuation path exists. Agent cannot grant itself once/always-allow
scope via generic API.
## `continuation`
Review: `baseline`.
API: `present` — representative operation IDs:
- `GET /api/issues/{id}/interactions`.
- `GET /api/heartbeat-runs/{runId}`.
Agent access: `available` — Server delivery and resumed assigned agent context.
Policy: Current task/run and named audience/resolver policy; governed approval decisions
require board independently of an ordinary interaction.
Evidence: `source-only` — [implementation](../../server/src/routes/issues.ts#L16638) 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: Continuation is server-owned; prove exactly one wake/no duplicate action after
resolution with existing integration fixtures.
+207
View File
@@ -0,0 +1,207 @@
# Recovery — agent access
Product map: [Recovery](../feature-map/recovery.md).
Review date: 2026-10-12. Source commit: `f981fa3cc10cb8663a87dec60345fbff46d54d0a`.
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.
## `diagnosis`
Review: `baseline`.
API: `present` — representative operation IDs:
- `GET /api/issues/{id}/diagnostics/blockers`.
- `GET /api/issues/{id}/recovery-actions`.
Agent access: `available` — REST / native call_api; CLI issue diagnostics.
Policy: Task/run visibility, run ownership and source/action policy; workspace export
retry and some operator controls require board.
Evidence: `source-only` — [implementation](../../server/src/routes/issues.ts#L9478) 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: Diagnostics expose recorded cause and boundaries; source-backed reading does not
prove successful recovery.
## `bounded-continuation`
Review: `baseline`.
API: `present` — representative operation IDs:
- `POST /api/issues/{id}/recovery-actions/resolve`.
Agent access: `partial` — Eligible agent REST / CLI; native generic mutation restricted.
Policy: Task/run visibility, run ownership and source/action policy; workspace export
retry and some operator controls require board.
Evidence: `source-only` — [implementation](../../server/src/routes/issues.ts#L9478) 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: Underlying route has agent checks; no corresponding default native recovery
mutation tool is advertised.
## `source-action`
Review: `baseline`.
API: `present` — representative operation IDs:
- `POST /api/issues/{id}/recovery-actions/resolve`.
Agent access: `partial` — Eligible agent REST / CLI; source-bound recovery state.
Policy: Task/run visibility, run ownership and source/action policy; workspace export
retry and some operator controls require board.
Evidence: `source-only` — [implementation](../../server/src/routes/issues.ts#L9478) 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: Need operation-level eligibility and a real native binding for permitted recovery
actions; do not route around lifecycle authority.
## `exhaustion`
Review: `baseline`.
API: `present` — representative operation IDs:
- `GET /api/issues/{id}/recovery-actions`.
- `GET /api/heartbeat-runs/{runId}`.
Agent access: `partial` — REST / native call_api reads; operator escalation flow.
Policy: Task/run visibility, run ownership and source/action policy; workspace export
retry and some operator controls require board.
Evidence: `source-only` — [implementation](../../server/src/routes/issues.ts#L9478) 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: Reading exhaustion is supported. Continuing past the recorded gate requires the
specified owner/action.
## `workspace`
Review: `baseline`.
API: `present` — representative operation IDs:
- `POST /api/issues/{id}/recovery-actions/retry-workspace-export`.
- `POST /api/execution-workspaces/{id}/reconcile-branch`.
Agent access: `restricted` — Board/runtime management APIs; agent reads diagnosis and
performs permitted workspace work.
Policy: Task/run visibility, run ownership and source/action policy; workspace export
retry and some operator controls require board.
Evidence: `source-only` — [implementation](../../server/src/routes/issues.ts#L9478) at
the reviewed commit above.
Verification: `not-run` — assert the documented agent denial with an owned test fixture;
verify any listed agent request/result path separately. A delegated operation needs its
own policy and access review.
Gaps: Export retry/reconciliation APIs exist but require board. Native generic
execution-control mutations are also blocked.
## `unknown-outcome`
Review: `baseline`.
API: `present` — representative operation IDs:
- `POST /api/chat-endpoints/{endpointId}/publications/{publicationId}/resolve`.
Agent access: `restricted` — Board provider-outcome resolution; agent may inspect
assigned provider tools.
Policy: Task/run visibility, run ownership and source/action policy; workspace export
retry and some operator controls require board.
Evidence: `source-only` — [implementation](../../server/src/routes/issues.ts#L9478) at
the reviewed commit above.
Verification: `not-run` — assert the documented agent denial with an owned test fixture;
verify any listed agent request/result path separately. A delegated operation needs its
own policy and access review.
Gaps: Uncertain-side-effect resolution is operator/source-specific; do not replay to
obtain apparent parity.
## `user-continuation`
Review: `baseline`.
API: `present` — representative operation IDs:
- `POST /api/issues/{id}/comments`.
Agent access: `partial` — User comment API and server-owned wake reconsideration; native
agent consumes bound wake.
Policy: Task/run visibility, run ownership and source/action policy; workspace export
retry and some operator controls require board.
Evidence: `source-only` — [implementation](../../server/src/routes/issues.ts#L9478) 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: Receiving the continuation is supported; impersonating a saved user message or
retry control is not.
## `reconnect`
Review: `baseline`.
API: `present` — representative operation IDs:
- `GET /api/companies/{companyId}/events/ws`.
- `GET /api/issues/{id}`.
Agent access: `partial` — Existing event protocol; REST refresh of persisted task state.
Policy: Task/run visibility, run ownership and source/action policy; workspace export
retry and some operator controls require board.
Evidence: `source-only` — [implementation](../../server/src/routes/issues.ts#L9478) 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: Streaming reconnect needs its protocol client. Polling/read APIs remain available;
replay is not proof of a fresh successful action.
+135
View File
@@ -0,0 +1,135 @@
# Routines, schedules, and triggers — agent access
Product map: [Routines, schedules, and triggers](../feature-map/routines.md).
Review date: 2026-10-12. Source commit: `f981fa3cc10cb8663a87dec60345fbff46d54d0a`.
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.
## `definition`
Review: `baseline`.
API: `present` — representative operation IDs:
- `POST /api/companies/{companyId}/routines`.
- `PATCH /api/routines/{id}`.
Agent access: `partial` — Agent REST / CLI routine create/update; optional installed MCP
generic request.
Policy: Agents may read company routines but only create/manage routines assigned to
themselves; trigger secrets need secure handling.
Evidence: `source-only` — [implementation](../../server/src/routes/routines.ts#L99) 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: Native call_api rejects routine mutation; manage_routine is scenario-only/unbound.
Agent REST is implemented.
## `triggers`
Review: `baseline`.
API: `present` — representative operation IDs:
- `POST /api/routines/{id}/triggers`.
- `PATCH /api/routine-triggers/{id}`.
Agent access: `partial` — Owned-routine agent REST / CLI routine trigger commands.
Policy: Agents may read company routines but only create/manage routines assigned to
themselves; trigger secrets need secure handling.
Evidence: `source-only` — [implementation](../../server/src/routes/routines.ts#L99) 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: No production default native trigger-management binding. Webhook creation/rotation
also returns credential material.
## `run-now`
Review: `baseline`.
API: `present` — representative operation IDs:
- `POST /api/routines/{id}/run`.
Agent access: `partial` — Owned-routine agent REST / CLI routine run.
Policy: Agents may read company routines but only create/manage routines assigned to
themselves; trigger secrets need secure handling.
Evidence: `source-only` — [implementation](../../server/src/routes/routines.ts#L99) 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: A scheduled/waiting native agent cannot use call_api for this eligible operation;
a real control binding is missing.
## `history`
Review: `baseline`.
API: `present` — representative operation IDs:
- `GET /api/routines/{id}/runs`.
- `GET /api/routines/{id}/revisions`.
Agent access: `available` — REST / native call_api / CLI routine.
Policy: Agents may read company routines but only create/manage routines assigned to
themselves; trigger secrets need secure handling.
Evidence: `source-only` — [implementation](../../server/src/routes/routines.ts#L99) 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: Runs are readable in company scope; configuration revision access checks routine
ownership for agents.
## `management`
Review: `baseline`.
API: `present` — representative operation IDs:
- `PATCH /api/routines/{id}`.
Agent access: `partial` — Owned-routine agent REST / CLI; normal native fallback can
manage separate folder metadata where permitted.
Policy: Agents may read company routines but only create/manage routines assigned to
themselves; trigger secrets need secure handling.
Evidence: `source-only` — [implementation](../../server/src/routes/routines.ts#L99) 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: Pause/archive routine mutation lacks a production native binding. Plugin-managed
routine rules remain separate.
+111
View File
@@ -0,0 +1,111 @@
# Runs, harnesses, and model accounts — agent access
Product map: [Runs, harnesses, and model accounts](../feature-map/runs-adapters.md).
Review date: 2026-10-12. Source commit: `f981fa3cc10cb8663a87dec60345fbff46d54d0a`.
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.
## `availability`
Review: `baseline`.
API: `present` — representative operation IDs:
- `GET /api/adapters`.
- `GET /api/companies/{companyId}/adapters/{type}/models`.
Agent access: `partial` — Agent company-model API and bound runtime context; board
adapter/account inventories.
Policy: Run/cost visibility and agent configuration policy; adapter installation/account
login/session control require board/admin.
Evidence: `source-only` — [implementation](../../server/src/routes/agents.ts#L6608) 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: Raw instance adapter listing requires board, while company model discovery exists
for eligible agents.
## `validation`
Review: `baseline`.
API: `present` — representative operation IDs:
- `POST /api/companies/{companyId}/adapters/{type}/test-environment`.
Agent access: `partial` — Permitted agent-creation validation path / REST / CLI;
operator account login.
Policy: Run/cost visibility and agent configuration policy; adapter installation/account
login/session control require board/admin.
Evidence: `source-only` — [implementation](../../server/src/routes/agents.ts#L6608) 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: Environment test path checks creation/configuration policy; missing provider auth
must use its owner setup flow.
## `runs`
Review: `baseline`.
API: `present` — representative operation IDs:
- `GET /api/heartbeat-runs/{runId}`.
- `GET /api/heartbeat-runs/{runId}/log`.
Agent access: `available` — REST / native call_api / CLI run.
Policy: Run/cost visibility and agent configuration policy; adapter installation/account
login/session control require board/admin.
Evidence: `source-only` — [implementation](../../server/src/routes/agents.ts#L6608) 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: Provider trace reveals/downloads require instance-admin and cannot be counted as
ordinary run output access.
## `session`
Review: `baseline`.
API: `present` — representative operation IDs:
- `POST /api/agents/{id}/runtime-state/reset-session`.
- `GET /api/agents/{id}/task-sessions`.
Agent access: `restricted` — Board session controls; native server-owned session
continuation.
Policy: Run/cost visibility and agent configuration policy; adapter installation/account
login/session control require board/admin.
Evidence: `source-only` — [implementation](../../server/src/routes/agents.ts#L6608) at
the reviewed commit above.
Verification: `not-run` — assert the documented agent denial with an owned test fixture;
verify any listed agent request/result path separately. A delegated operation needs its
own policy and access review.
Gaps: Execution context reset is not a permitted generic native API mutation or an
ordinary agent management path.
+138
View File
@@ -0,0 +1,138 @@
# Secrets, personal credentials, and proposals — agent access
Product map: [Secrets, personal credentials, and proposals](../feature-map/secrets.md).
Review date: 2026-10-12. Source commit: `f981fa3cc10cb8663a87dec60345fbff46d54d0a`.
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.
## `company-secrets`
Review: `baseline`.
API: `present` — representative operation IDs:
- `GET /api/companies/{companyId}/secrets/catalog`.
- `POST /api/companies/{companyId}/secrets`.
Agent access: `partial` — Agent metadata catalog; board secret administration; agent
secret proposal API.
Policy: Board secret administration, active-run/self/report proposal policy, and scoped
secret broker bindings; personal secret values belong to their user.
Evidence: `source-only` — [implementation](../../server/src/routes/secrets.ts#L194) 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: Metadata and requesting a change exist; generic native API blocks secret
management/value transport.
## `user-secrets`
Review: `baseline`.
API: `present` — representative operation IDs:
- `GET /api/companies/{companyId}/me/user-secrets`.
- `POST /api/companies/{companyId}/me/user-secrets`.
Agent access: `restricted` — Current board user's personal-secret API; agent receives
only authorized run binding.
Policy: Board secret administration, active-run/self/report proposal policy, and scoped
secret broker bindings; personal secret values belong to their user.
Evidence: `source-only` — [implementation](../../server/src/routes/secrets.ts#L194) at
the reviewed commit above.
Verification: `not-run` — assert the documented agent denial with an owned test fixture;
verify any listed agent request/result path separately. A delegated operation needs its
own policy and access review.
Gaps: Agent cannot edit a person's private credential value through their ordinary agent
key.
## `proposals`
Review: `baseline`.
API: `present` — representative operation IDs:
- `POST /api/agents/me/secret-proposals`.
- `GET /api/agents/me/secret-proposals`.
Agent access: `partial` — Active-run agent REST with redaction; board
approval/rejection.
Policy: Board secret administration, active-run/self/report proposal policy, and scoped
secret broker bindings; personal secret values belong to their user.
Evidence: `source-only` — [implementation](../../server/src/routes/secrets.ts#L194) 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: Native call_api blocks secret-proposals and no dedicated production proposal tool
is in its default authority set.
## `vault-import`
Review: `baseline`.
API: `present` — representative operation IDs:
- `POST /api/companies/{companyId}/secrets/remote-import/preview`.
- `POST /api/companies/{companyId}/secrets/remote-import`.
Agent access: `restricted` — Board authorized vault import API / CLI provider
operations.
Policy: Board secret administration, active-run/self/report proposal policy, and scoped
secret broker bindings; personal secret values belong to their user.
Evidence: `source-only` — [implementation](../../server/src/routes/secrets.ts#L194) at
the reviewed commit above.
Verification: `not-run` — assert the documented agent denial with an owned test fixture;
verify any listed agent request/result path separately. A delegated operation needs its
own policy and access review.
Gaps: Vault import is not implied by having a secret binding or the ability to propose a
secret.
## `runtime-delivery`
Review: `baseline`.
API: `present` — representative operation IDs:
- `GET /api/agents/me/secrets`.
- `POST /api/agents/me/secrets/{key}/value`.
Agent access: `partial` — Authorized environment/broker delivery; eligible legacy agent
REST access.
Policy: Board secret administration, active-run/self/report proposal policy, and scoped
secret broker bindings; personal secret values belong to their user.
Evidence: `source-only` — [implementation](../../server/src/routes/secrets.ts#L194) 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: Native metadata reads exist; value call is blocked and scenario read_secret_value
is unbound. Do not add raw secret-returning fallback tools.
+141
View File
@@ -0,0 +1,141 @@
# Skill discovery, authoring, and policy — agent access
Product map: [Skill discovery, authoring, and policy](../feature-map/skills.md).
Review date: 2026-10-12. Source commit: `f981fa3cc10cb8663a87dec60345fbff46d54d0a`.
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.
## `discovery`
Review: `baseline`.
API: `present` — representative operation IDs:
- `GET /api/companies/{companyId}/skills`.
- `POST /api/companies/{companyId}/skills/import`.
Agent access: `available` — REST / native call_api / CLI skills and sources.
Policy: Company skill policy by action/resource plus platform invariants; test execution
additionally requires task-assignment authority.
Evidence: `source-only` —
[implementation](../../server/src/routes/company-skills.ts#L208) 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: Installation/import is governed by company skill policy, not inferred from an
agent's role name.
## `authoring`
Review: `baseline`.
API: `present` — representative operation IDs:
- `POST /api/companies/{companyId}/skills`.
- `PATCH /api/companies/{companyId}/skills/{skillId}/files`.
Agent access: `available` — Native create_skill/update_skill for single-file operations;
REST for other files/metadata.
Policy: Company skill policy by action/resource plus platform invariants; test execution
additionally requires task-assignment authority.
Evidence: `source-only` —
[implementation](../../server/src/routes/company-skills.ts#L208) 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: Writable/fork policy and expected version apply. Native helpers intentionally
support a narrower shape than full API.
## `versions`
Review: `baseline`.
API: `present` — representative operation IDs:
- `GET /api/companies/{companyId}/skills/{skillId}/versions`.
Agent access: `available` — REST / native call_api / CLI skills.
Policy: Company skill policy by action/resource plus platform invariants; test execution
additionally requires task-assignment authority.
Evidence: `source-only` —
[implementation](../../server/src/routes/company-skills.ts#L208) 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: Revision metadata has an API; pinned execution skill versions and installed latest
are distinct.
## `policy`
Review: `baseline`.
API: `present` — representative operation IDs:
- `PUT /api/companies/{companyId}/skill-policy`.
- `POST /api/agents/{id}/skills/sync`.
Agent access: `partial` — REST / native call_api under users:manage_permissions or
target configuration policy.
Policy: Company skill policy by action/resource plus platform invariants; test execution
additionally requires task-assignment authority.
Evidence: `source-only` —
[implementation](../../server/src/routes/company-skills.ts#L208) 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: Policy administration has an explicit agent grant branch; assigning agent skills
also checks the target's config authority.
## `testing`
Review: `baseline`.
API: `present` — representative operation IDs:
- `POST /api/companies/{companyId}/skills/{skillId}/test-runs`.
Agent access: `partial` — Permitted agent REST; native read fallback for history; no
dedicated CLI test command found.
Policy: Company skill policy by action/resource plus platform invariants; test execution
additionally requires task-assignment authority.
Evidence: `source-only` —
[implementation](../../server/src/routes/company-skills.ts#L208) 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: Native call_api rejects test-run creation/control while the route can authorize
agents. No default native orchestration binding.
+110
View File
@@ -0,0 +1,110 @@
# Status cards and refreshed summaries — agent access
Product map: [Status cards and refreshed summaries](../feature-map/status-cards.md).
Review date: 2026-10-12. Source commit: `f981fa3cc10cb8663a87dec60345fbff46d54d0a`.
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.
## `authoring`
Review: `baseline`.
API: `present` — representative operation IDs:
- `POST /api/companies/{companyId}/status-cards`.
- `PATCH /api/status-cards/{id}`.
Agent access: `available` — REST / native call_api.
Policy: Feature gate, tasks:assign decision; agents manage only cards they authored;
compiler/summarizer has extra bound-task checks.
Evidence: `source-only` — [implementation](../../server/src/routes/status-cards.ts#L32)
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: Real agent create/update permission branch exists; not inherently a board-only
feature.
## `generation`
Review: `baseline`.
API: `present` — representative operation IDs:
- `POST /api/status-cards/{id}/recompile`.
- `POST /api/status-cards/{id}/refresh`.
Agent access: `available` — REST / native call_api for authorized own card.
Policy: Feature gate, tasks:assign decision; agents manage only cards they authored;
compiler/summarizer has extra bound-task checks.
Evidence: `source-only` — [implementation](../../server/src/routes/status-cards.ts#L32)
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: Execution result must be checked. Agent-authored prompt length and tasks:assign
limits apply.
## `inspection`
Review: `baseline`.
API: `present` — representative operation IDs:
- `GET /api/status-cards/{id}`.
- `GET /api/status-cards/{id}/summary-revisions`.
- `GET /api/status-cards/{id}/dry-run`.
Agent access: `available` — REST / native call_api.
Policy: Feature gate, tasks:assign decision; agents manage only cards they authored;
compiler/summarizer has extra bound-task checks.
Evidence: `source-only` — [implementation](../../server/src/routes/status-cards.ts#L32)
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: Read/history/debug APIs exist; a rendered compiling state is not evidence of
successful generation.
## `archive`
Review: `baseline`.
API: `present` — representative operation IDs:
- `PATCH /api/status-cards/{id}`.
Agent access: `available` — REST / native call_api under own-card management policy.
Policy: Feature gate, tasks:assign decision; agents manage only cards they authored;
compiler/summarizer has extra bound-task checks.
Evidence: `source-only` — [implementation](../../server/src/routes/status-cards.ts#L32)
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: Archive/restore is represented by card state, separate from delete; check exact
allowed status transition.
+180
View File
@@ -0,0 +1,180 @@
# Steering and queued messages — agent access
Product map: [Steering and queued messages](../feature-map/steering.md).
Review date: 2026-10-12. Source commit: `f981fa3cc10cb8663a87dec60345fbff46d54d0a`.
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.
## `queue`
Review: `baseline`.
API: `present` — representative operation IDs:
- `GET /api/issues/{id}/queued-comments`.
Agent access: `partial` — REST / native call_api for visible queue; server-owned queue
admission.
Policy: Queue inspection follows task visibility; queued user-message mutation and run
cancellation require a board actor/user.
Evidence: `source-only` — [implementation](../../server/src/routes/issues.ts#L16166) 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: Agents can read eligible queue state; sending/steering the person's queued
messages requires separate authority.
## `edit-order-discard`
Review: `baseline`.
API: `present` — representative operation IDs:
- `PATCH /api/issues/{id}/queued-comments/{commentId}`.
- `PUT /api/issues/{id}/queued-comments/order`.
- `DELETE /api/issues/{id}/queued-comments/{commentId}`.
Agent access: `restricted` — Board-user queue mutation API.
Policy: Queue inspection follows task visibility; queued user-message mutation and run
cancellation require a board actor/user.
Evidence: `source-only` — [implementation](../../server/src/routes/issues.ts#L16166) at
the reviewed commit above.
Verification: `not-run` — assert the documented agent denial with an owned test fixture;
verify any listed agent request/result path separately. A delegated operation needs its
own policy and access review.
Gaps: No agent user-message edit/reorder/discard path; explicit delegated-user policy
needed before granting one.
## `steer`
Review: `baseline`.
API: `present` — representative operation IDs:
- `POST /api/issues/{id}/queued-comments/{commentId}/steer`.
Agent access: `restricted` — Board-user execution control API; agent receives eligible
new run/wake.
Policy: Queue inspection follows task visibility; queued user-message mutation and run
cancellation require a board actor/user.
Evidence: `source-only` — [implementation](../../server/src/routes/issues.ts#L16166) at
the reviewed commit above.
Verification: `not-run` — assert the documented agent denial with an owned test fixture;
verify any listed agent request/result path separately. A delegated operation needs its
own policy and access review.
Gaps: Generic native API blocks this execution control; no authority to impersonate the
steering user.
## `interrupt`
Review: `baseline`.
API: `present` — representative operation IDs:
- `POST /api/issues/{id}/queued-comments/interrupt`.
- `POST /api/heartbeat-runs/{runId}/cancel`.
Agent access: `restricted` — Board-user interruption/cancel API.
Policy: Queue inspection follows task visibility; queued user-message mutation and run
cancellation require a board actor/user.
Evidence: `source-only` — [implementation](../../server/src/routes/issues.ts#L16166) at
the reviewed commit above.
Verification: `not-run` — assert the documented agent denial with an owned test fixture;
verify any listed agent request/result path separately. A delegated operation needs its
own policy and access review.
Gaps: Explicit operator action is distinct from an agent yielding/blocking its own turn.
## `stop-and-pause`
Review: `baseline`.
API: `present` — representative operation IDs:
- `POST /api/issues/{id}/tree-holds`.
- `POST /api/agents/{id}/pause`.
Agent access: `restricted` — Board control APIs; agent paperclip_finish/paperclip_block
for its own turn.
Policy: Queue inspection follows task visibility; queued user-message mutation and run
cancellation require a board actor/user.
Evidence: `source-only` — [implementation](../../server/src/routes/issues.ts#L16166) at
the reviewed commit above.
Verification: `not-run` — assert the documented agent denial with an owned test fixture;
verify any listed agent request/result path separately. A delegated operation needs its
own policy and access review.
Gaps: Task-tree/agent pause and confirmed stop need policy-preserving authority; no
generic agent management path.
## `drafts`
Review: `baseline`.
API: `not-applicable` — No shared server draft resource for this presentation state;
cross-client drafts would be a deliberate new capability.
Agent access: `not-applicable` — Browser-local task composer draft / submission state.
Policy: Queue inspection follows task visibility; queued user-message mutation and run
cancellation require a board actor/user.
Evidence: `source-only` — [implementation](../../server/src/routes/issues.ts#L16166) at
the reviewed commit above.
Verification: `not-run` — use the product recipe for the local/developer surface. Verify
listed shared-resource reads separately; local presentation alone is not agent API
evidence.
Gaps: No shared server draft resource for this presentation state; cross-client drafts
would be a deliberate new capability.
## `approval-queue`
Review: `baseline`.
API: `present` — representative operation IDs:
- `GET /api/issues/{id}/interactions`.
- `GET /api/issues/{id}/queued-comments`.
Agent access: `partial` — Agent can inspect authorized persisted interactions; server
continuation/queue delivery.
Policy: Queue inspection follows task visibility; queued user-message mutation and run
cancellation require a board actor/user.
Evidence: `source-only` — [implementation](../../server/src/routes/issues.ts#L16166) 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: Resolving as a human and controlling queued wakes is separate from seeing the
approval response.
+114
View File
@@ -0,0 +1,114 @@
# Delegation, dependencies, and signoff — agent access
Product map: [Delegation, dependencies, and
signoff](../feature-map/task-coordination.md).
Review date: 2026-10-12. Source commit: `f981fa3cc10cb8663a87dec60345fbff46d54d0a`.
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.
## `delegation`
Review: `baseline`.
API: `present` — representative operation IDs:
- `POST /api/companies/{companyId}/issues`.
Agent access: `available` — Native create_task/reassign_task; REST / CLI / MCP.
Policy: Task visibility/mutation, task-assignment and ownership policy; review audience
independent; tree controls board-only.
Evidence: `source-only` —
[implementation](../../server/src/routes/issue-tree-control.ts#L95) 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: Parent/child and provenance paths exist; same-company assignment does not remove
protected task/resource policy.
## `dependencies`
Review: `baseline`.
API: `present` — representative operation IDs:
- `PATCH /api/issues/{id}`.
Agent access: `available` — Native set_dependencies for current task; agent REST under
mutation/checkout policy.
Policy: Task visibility/mutation, task-assignment and ownership policy; review audience
independent; tree controls board-only.
Evidence: `source-only` —
[implementation](../../server/src/routes/issue-tree-control.ts#L95) 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: Generic native PATCH rejects blockedByIssueIds so use its real dedicated tool.
## `signoff`
Review: `baseline`.
API: `present` — representative operation IDs:
- `PATCH /api/issues/{id}`.
- `POST /api/issues/{id}/interactions`.
Agent access: `partial` — Native paperclip_finish/paperclip_block and assigned
resolve_review; legacy agent REST disposition.
Policy: Task visibility/mutation, task-assignment and ownership policy; review audience
independent; tree controls board-only.
Evidence: `source-only` —
[implementation](../../server/src/routes/issue-tree-control.ts#L95) 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: Review policy determines final completion; formal board approval is a different
boundary.
## `tree-control`
Review: `baseline`.
API: `present` — representative operation IDs:
- `POST /api/issues/{id}/tree-control/preview`.
- `POST /api/issues/{id}/tree-holds`.
- `POST /api/issues/{id}/tree-holds/{holdId}/release`.
Agent access: `restricted` — Board-only task-tree APIs.
Policy: Task visibility/mutation, task-assignment and ownership policy; review audience
independent; tree controls board-only.
Evidence: `source-only` —
[implementation](../../server/src/routes/issue-tree-control.ts#L95) at the reviewed
commit above.
Verification: `not-run` — assert the documented agent denial with an owned test fixture;
verify any listed agent request/result path separately. A delegated operation needs its
own policy and access review.
Gaps: Even reads/state/preview require board. There is no agent tree-control path just
from company/task permissions.
+136
View File
@@ -0,0 +1,136 @@
# Task creation and lifecycle — agent access
Product map: [Task creation and lifecycle](../feature-map/tasks.md).
Review date: 2026-10-12. Source commit: `f981fa3cc10cb8663a87dec60345fbff46d54d0a`.
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.
## `create`
Review: `baseline`.
API: `present` — representative operation IDs:
- `POST /api/companies/{companyId}/issues`.
Agent access: `available` — Native create_task; REST / CLI / MCP.
Policy: Company/task visibility, assignment/change policy, active-run checkout ownership
and lifecycle rules.
Evidence: `source-only` — [implementation](../../server/src/routes/issues.ts) 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: Creation is implemented; agent/user assignment and attachments may need
narrower/different APIs.
## `organize`
Review: `baseline`.
API: `present` — representative operation IDs:
- `GET /api/companies/{companyId}/issues`.
Agent access: `available` — Native search_tasks; REST / CLI; UI grouping/navigation
state separately.
Policy: Company/task visibility, assignment/change policy, active-run checkout ownership
and lifecycle rules.
Evidence: `source-only` — [implementation](../../server/src/routes/issues.ts) 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: Search/filter API exists; sorting/grouping/presentation defaults are not
necessarily shared server preferences.
## `properties`
Review: `baseline`.
API: `present` — representative operation IDs:
- `PATCH /api/issues/{id}`.
- `PUT /api/issues/{id}/title`.
Agent access: `partial` — Native set_task_title/reassign_task/set_dependencies; fallback
for permitted non-lifecycle fields; REST.
Policy: Company/task visibility, assignment/change policy, active-run checkout ownership
and lifecycle rules.
Evidence: `source-only` — [implementation](../../server/src/routes/issues.ts) 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: Native fallback blocks status/assignment/dependency policy fields. Dedicated tools
differ in scope and supported fields.
## `discussion`
Review: `baseline`.
API: `present` — representative operation IDs:
- `POST /api/issues/{id}/comments`.
- `POST /api/companies/{companyId}/issues/{issueId}/attachments`.
Agent access: `available` — Native report_progress/comment_on_task/register_deliverable;
REST / CLI / MCP.
Policy: Company/task visibility, assignment/change policy, active-run checkout ownership
and lifecycle rules.
Evidence: `source-only` — [implementation](../../server/src/routes/issues.ts) 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: Other-task comments and active-task progress have separate scopes; explicit
reopen/interrupt is not a generic comment capability.
## `completion`
Review: `baseline`.
API: `present` — representative operation IDs:
- `PATCH /api/issues/{id}`.
Agent access: `available` — Native paperclip_finish/paperclip_block through runner
protocol; legacy agent REST disposition.
Policy: Company/task visibility, assignment/change policy, active-run checkout ownership
and lifecycle rules.
Evidence: `source-only` — [implementation](../../server/src/routes/issues.ts) 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: Server governs whether a reported result becomes done/review/blocked. A generic
lifecycle PATCH is intentionally rejected for native runs.
+108
View File
@@ -0,0 +1,108 @@
# Team packages and catalog installation — agent access
Product map: [Team packages and catalog installation](../feature-map/teams.md).
Review date: 2026-10-12. Source commit: `f981fa3cc10cb8663a87dec60345fbff46d54d0a`.
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.
## `discovery`
Review: `baseline`.
API: `present` — representative operation IDs:
- `GET /api/teams/catalog`.
- `GET /api/teams/catalog/{catalogId}`.
Agent access: `available` — REST / native call_api / CLI teams.
Policy: Authenticated catalog browsing; same-company preview; agent install requires
agents:create grant or canCreateAgents.
Evidence: `source-only` — [implementation](../../server/src/routes/teams-catalog.ts#L36)
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: Team browsing exists even though there is no dedicated teams product screen.
## `preview`
Review: `baseline`.
API: `present` — representative operation IDs:
- `POST /api/companies/{companyId}/teams/catalog/{catalogId}/preview`.
Agent access: `available` — REST / native call_api / CLI teams preview.
Policy: Authenticated catalog browsing; same-company preview; agent install requires
agents:create grant or canCreateAgents.
Evidence: `source-only` — [implementation](../../server/src/routes/teams-catalog.ts#L36)
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: Preview does not install a team; its audit write should not be mistaken for agent
execution proof.
## `install`
Review: `baseline`.
API: `present` — representative operation IDs:
- `POST /api/companies/{companyId}/teams/catalog/{catalogId}/install`.
Agent access: `available` — Authorized agent REST / native call_api / CLI teams install.
Policy: Authenticated catalog browsing; same-company preview; agent install requires
agents:create grant or canCreateAgents.
Evidence: `source-only` — [implementation](../../server/src/routes/teams-catalog.ts#L36)
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: Actual agent permission branch exists. Resulting agents/accounts/workspaces may
still need operator setup.
## `configuration`
Review: `baseline`.
API: `present` — representative operation IDs:
- `POST /api/companies/{companyId}/teams/catalog/{catalogId}/preview`.
- `POST /api/companies/{companyId}/teams/catalog/{catalogId}/install`.
Agent access: `partial` — Team package variables/options via REST/CLI; resulting
resources use their own APIs.
Policy: Authenticated catalog browsing; same-company preview; agent install requires
agents:create grant or canCreateAgents.
Evidence: `source-only` — [implementation](../../server/src/routes/teams-catalog.ts#L36)
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: There is no independent generic team-edit resource; distinguish package options
from installed agent/project configuration.
+144
View File
@@ -0,0 +1,144 @@
# Execution workspaces, services, and files — agent access
Product map: [Execution workspaces, services, and files](../feature-map/workspaces.md).
Review date: 2026-10-12. Source commit: `f981fa3cc10cb8663a87dec60345fbff46d54d0a`.
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.
## `binding`
Review: `baseline`.
API: `present` — representative operation IDs:
- `GET /api/issues/{id}/heartbeat-context`.
- `GET /api/execution-workspaces/{id}`.
Agent access: `available` — Native get_task_context / REST / CLI / MCP workspace read.
Policy: Company/project/workspace visibility and runtime authority; active run, trust
preset and task ownership where required.
Evidence: `source-only` —
[implementation](../../server/src/routes/workspace-runtime-service-authz.ts#L76) 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: Run/task context identifies its actual realized workspace; record existence is not
a running service.
## `provisioning`
Review: `baseline`.
API: `present` — representative operation IDs:
- `GET /api/execution-workspaces/{id}`.
- `GET /api/execution-workspaces/{id}/workspace-operations`.
Agent access: `partial` — REST / native call_api reads; task/project assignment triggers
server provisioning.
Policy: Company/project/workspace visibility and runtime authority; active run, trust
preset and task ownership where required.
Evidence: `source-only` —
[implementation](../../server/src/routes/workspace-runtime-service-authz.ts#L76) 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: Observing readiness exists. Creating host commands or arbitrary provision targets
is a separate protected operation.
## `services`
Review: `baseline`.
API: `present` — representative operation IDs:
- `POST /api/execution-workspaces/{id}/runtime-services/{action}`.
Agent access: `partial` — Authorized agent REST / CLI workspace runtime-service /
existing stdio MCP controls.
Policy: Company/project/workspace visibility and runtime authority; active run, trust
preset and task ownership where required.
Evidence: `source-only` —
[implementation](../../server/src/routes/workspace-runtime-service-authz.ts#L76) 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: Native call_api blocks runtime-service mutation; control_workspace_service is not
in the production authority set. Optional MCP availability must be recorded.
## `files-git`
Review: `baseline`.
API: `present` — representative operation IDs:
- `GET /api/issues/{issueId}/file-resources/content`.
- `GET /api/issues/{issueId}/file-resources/list`.
Agent access: `partial` — Authorized workspace filesystem tools; Dot workspace bridge
when enabled; board file-resource HTTP UI.
Policy: Company/project/workspace visibility and runtime authority; active run, trust
preset and task ownership where required.
Evidence: `source-only` —
[implementation](../../server/src/routes/workspace-runtime-service-authz.ts#L76) 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: Files panel HTTP requires board. Agents can use their admitted workspace file
tools; remote/Dot scope and Git command availability differ.
## `closure`
Review: `baseline`.
API: `present` — representative operation IDs:
- `PATCH /api/execution-workspaces/{id}`.
- `GET /api/execution-workspaces/{id}/close-readiness`.
- `POST /api/execution-workspaces/{id}/reconcile-branch`.
Agent access: `partial` — REST / native fallback for permitted update; CLI workspace;
reconcile-branch requires board.
Policy: Company/project/workspace visibility and runtime authority; active run, trust
preset and task ownership where required.
Evidence: `source-only` —
[implementation](../../server/src/routes/workspace-runtime-service-authz.ts#L76) 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: Closure/readiness exists; not every workspace can be reopened, and branch
reconciliation has a board boundary.
@@ -3,13 +3,17 @@
Start here when reproducing a user-facing bug, verifying a change, or deciding
which surfaces a fix must cover. Each recipe describes what a person can do,
where they can do it, the expected result, and the evidence needed to verify it.
Product behavior is still governed by [the implementation spec](../doc/SPEC-implementation.md).
Product behavior is still governed by [the implementation spec](../../doc/SPEC-implementation.md).
The sibling [agent access map](../agent-access-map/README.md) records APIs,
agent entry points and permission boundaries for the same capability IDs.
Follow the [shared map contract](../README.md) when maintaining either map.
## Features
The map is organized by user capability, not by source file. It covers **35 feature
families** across the product, CLI, and operator workflows, checked against source
on 2026-10-05. Experimental and developer-only surfaces are labeled explicitly.
on 2026-10-12. Experimental and developer-only surfaces are labeled explicitly.
Each recipe includes sub-features, current entry points, automated evidence,
manual verification steps, and gotchas.
@@ -94,7 +98,7 @@ fixture integration. Record executed results separately from the map.
## Before driving a journey
1. Use this checkout's [isolated test drive](../doc/DEVELOPING.md#one-command-isolated-manual-test-drive)
1. Use this checkout's [isolated test drive](../../doc/DEVELOPING.md#one-command-isolated-manual-test-drive)
for manual product checks. It creates a temporary instance and prints its URL
and data directory. Do not guess that a server on port 3100 belongs to you.
2. Record the commit, URL, company, login role, relevant experimental settings,
@@ -113,9 +117,12 @@ fixture integration. Record executed results separately from the map.
persisted state or continuation. Use read-only API checks to corroborate UI
evidence; creating state through the API does not prove the creation UI.
For agent-driven acceptance work, the existing
[dev-workspace run/verify skill](../.agents/skills/paperclip-dev-workspace-run-verify-fix/SKILL.md)
and [evaluation skill](../.agents/skills/paperclip-evals/SKILL.md) describe runtime
For agent-driven acceptance work, start with the
[Paperclip verification skill](../../.agents/skills/verify-paperclip/SKILL.md) for an
isolated launch, ownership/readiness checks, browser driving, evidence, and cleanup.
It uses this directory as its feature map. The existing
[dev-workspace run/verify skill](../../.agents/skills/paperclip-dev-workspace-run-verify-fix/SKILL.md)
and [evaluation skill](../../.agents/skills/paperclip-evals/SKILL.md) describe runtime
ownership and evidence handling. Reuse them; this map introduces no environment
launcher, credentials, scheduled job, or second test framework.
@@ -131,7 +138,7 @@ A fix is verified across its affected surfaces only when each has evidence or
an explicit reason it does not apply. Shared code alone does not prove parity.
Keep product regressions visible; do not change the recipe to bless a failure.
For Paperclip-assigned work, attach evidence through the
[artifact workflow](../doc/AGENT-ARTIFACTS.md).
[artifact workflow](../../doc/AGENT-ARTIFACTS.md).
## Inventory and remaining depth
@@ -145,8 +152,8 @@ The page inventory is a source snapshot dated 2026-10-05. The map also
includes entry points hosted inside other modules (pipeline Review Queue and
Learnings, task documents, onboarding), CLI-only operations, and operator work.
The team recipe explicitly distinguishes the current CLI/API path from catalog
UI components without a current top-level route. Refer to [route registration](../ui/src/App.tsx)
and the [CLI registry](../cli/src/index.ts) when changing reachability.
UI components without a current top-level route. Refer to [route registration](../../ui/src/App.tsx)
and the [CLI registry](../../cli/src/index.ts) when changing reachability.
Remaining depth includes complete provider/auth/attachment matrices, every
harness/model/environment capability combination, third-party plugin features,
@@ -156,22 +163,29 @@ can include capabilities that do not add a page file.
## Maintaining the reference
The map is documentation only. It adds no CI checks, automatic journey execution,
or required inventory updates for future pull requests.
The map documents user journeys. It does not execute them automatically;
`coverage.json` records documentation scope rather than live test health.
When maintaining a recipe, compare its entry points and expected results with
the current source. Check that linked tests still exercise the stated behavior
and that local references still exist. Refresh the inventory snapshot when it
helps explain the current product. Maintenance is optional and review-based.
helps explain the current product. Keep the same-named agent access companion
and stable sub-feature IDs aligned when behavior or access changes. Source-only
access inventory remains distinct from live verification. Run
`node scripts/check-maps.mjs` after map edits for structural/reference checks;
follow the shared contract for the source and behavioral checks it cannot perform.
Each recipe starts with an H1 and a user-visible description, then exactly:
1. **Sub-features** — stable backticked IDs and observable behavior/states.
2. **How to get to it (user POV)** — one H3 backticked entry-point ID per surface.
3. **Driving it** — starts with `Preconditions:`; repeat each entry-point H3,
3. **Driving it with <harness>** — starts with `Preconditions:`; repeat each entry-point H3,
with `Automated:` and `Manual:` paragraphs. Name test scope and gaps honestly.
4. **Gotchas** — misleading look-alikes, feature gates, and invalid evidence.
The format is inspired by
New or updated entries follow
[Poteto's feature-map examples](../../.agents/skills/create-verification-skill/references/feature-map-example).
Existing entries with a `Driving it` heading can adopt the named harness when
their recipes are updated. The original format was inspired by
[Omnigent's feature map](https://github.com/omnigent-ai/omnigent/tree/91acfbbb59f6fc210ff95a9e9428aadd62e06582/feature-map).
Paperclip's recipes and checks follow its own task model and test infrastructure.
@@ -2,7 +2,9 @@
People and agents enter the correct instance and company with the permissions granted to their identity. Login, membership, resource access, and CLI authorization have separate controls.
Implementation: [auth page](../ui/src/pages/Auth.tsx), [company members](../ui/src/pages/CompanyAccess.tsx), [invitation](../ui/src/pages/InviteLanding.tsx).
Implementation: [auth page](../../ui/src/pages/Auth.tsx), [company members](../../ui/src/pages/CompanyAccess.tsx), [invitation](../../ui/src/pages/InviteLanding.tsx).
Agent access: [companion](../agent-access-map/access.md).
## Sub-features
@@ -21,33 +23,40 @@ Open `/auth`; first-owner bootstrap uses `/board-claim/:token` when configured.
### `invite-members`
Open `/invite/:token`; operators manage members in company settings and join requests at `/inbox/requests`.
Create/revoke human links at Members → Invites
(`/company/settings/members?tab=invites`). Human invitees receive the chosen
role after sign-in; agent invitations still use join-request approval.
### `cli-authorization`
Start the CLI auth/connect flow and approve its `/cli-auth/:id` browser page; instance access is under Settings when visible.
## Driving it
## Driving it with Playwright and the Paperclip CLI
Preconditions: follow the [baseline](./README.md#before-driving-a-journey). For login tests use authenticated mode and two test users; local-trusted mode does not prove session enforcement. Use two companies for isolation checks.
### `login`
Automated: [auth UI](../ui/src/pages/Auth.test.tsx) and [session routes](../server/src/__tests__/auth-session-route.test.ts) cover their respective layers.
Automated: [auth UI](../../ui/src/pages/Auth.test.tsx) and [session routes](../../server/src/__tests__/auth-session-route.test.ts) cover their respective layers.
Manual: Sign in, reload a company deep link, sign out, and revisit it. Confirm the browser requests authentication rather than showing cached company data. Test an invalid claim separately on disposable state.
### `invite-members`
Automated: [member UI](../ui/src/pages/CompanyAccess.test.tsx) and [invite replay](../server/src/__tests__/invite-accept-replay.test.ts) provide component and route evidence.
Automated: [member UI](../../ui/src/pages/CompanyAccess.test.tsx) and [invite replay](../../server/src/__tests__/invite-accept-replay.test.ts) provide component and route evidence.
Manual: Accept an invite as the intended user, inspect the resulting company and permissions, then reuse and expire disposable invites. Change a member permission, reload as that member, and verify a denied operation on another company remains denied.
### `cli-authorization`
Automated: [board auth client](../cli/src/__tests__/board-auth.test.ts) and [token commands](../cli/src/__tests__/token.test.ts) cover the client contracts.
Automated: [board auth client](../../cli/src/__tests__/board-auth.test.ts) and [token commands](../../cli/src/__tests__/token.test.ts) cover the client contracts.
Manual: Authorize the intended CLI context, make a read-only company request, then revoke its token and retry. Verify failure is explicit and does not silently fall back to another identity.
Use `auth login`, `auth whoami`, and `auth revoke-current` with explicit context.
Retry with the same bearer to prove revocation; deleting local credentials with
logout alone does not establish that server revocation succeeded.
## Gotchas
- Settings visibility is not authorization; direct requests still need permission checks.
@@ -2,7 +2,9 @@
People inspect company health, recent activity, run history, and routine activity, then follow evidence back to the task or agent responsible.
Implementation: [dashboard](../ui/src/pages/Dashboard.tsx), [live dashboard](../ui/src/pages/DashboardLive.tsx), [audit hub](../ui/src/pages/audit/AuditHub.tsx).
Implementation: [dashboard](../../ui/src/pages/Dashboard.tsx), [live dashboard](../../ui/src/pages/DashboardLive.tsx), [audit hub](../../ui/src/pages/audit/AuditHub.tsx).
Agent access: [companion](../agent-access-map/activity.md).
## Sub-features
@@ -22,22 +24,27 @@ Open `/dashboard` or `/dashboard/live`.
Open `/activity`, `/activity/runs`, or `/activity/timeline` in the streamlined shell; legacy routes may redirect.
## Driving it
## Driving it with Playwright and the Paperclip CLI
Preconditions: follow the [baseline](./README.md#before-driving-a-journey). Prepare known task mutations and completed/failed runs in a disposable company, recording their IDs and actors.
### `dashboard`
Automated: [dashboard service](../server/src/__tests__/dashboard-service.test.ts) covers server aggregation; [dashboard helpers](../ui/src/pages/Dashboard.test.ts) is narrower UI helper coverage.
Automated: [dashboard service](../../server/src/__tests__/dashboard-service.test.ts) covers server aggregation; [dashboard helpers](../../ui/src/pages/Dashboard.test.ts) is narrower UI helper coverage.
Manual: Compare the dashboard with the known fixture tasks and runs. Start and finish a small task, refresh/reload, and verify the summary changes and links reach the right records. Exercise empty data and a failed fetch.
### `activity-audit`
Automated: [activity service](../server/src/__tests__/activity-service.test.ts), [audit runs](../ui/src/pages/audit/AuditRuns.test.tsx), and [routine audit](../ui/src/pages/audit/RoutineAuditActivity.test.tsx) cover these separate data/host layers.
Automated: [activity service](../../server/src/__tests__/activity-service.test.ts), [audit runs](../../ui/src/pages/audit/AuditRuns.test.tsx), and [routine audit](../../ui/src/pages/audit/RoutineAuditActivity.test.tsx) cover these separate data/host layers.
Manual: Find a known mutation by actor/resource and a known run by status. Change filters, load more, and follow the source links. Reload the chosen view and verify no company leakage or duplicate events. Inspect a routine run from its audit entry.
Audit-event Load more and run listings differ: Runs currently loads at most 200
entries without pagination. The tested RoutineAuditActivity component has no
registered activity-route host; inspect execution links actually offered by
the routine rather than treating that component test as a reachable journey.
## Gotchas
- Audit/activity events, run-log rows, first-party Telemetry, and operator OpenTelemetry traces are separate data paths.
@@ -2,7 +2,9 @@
A person can hold a persistent conversation with an agent, return to its history, and hand useful work into a project or task. The gated conference-room chat is a separate conversation surface.
Implementation: [agent chat](../ui/src/pages/AgentChat.tsx), [chat landing](../ui/src/pages/AgentChats.tsx), [conference room](../ui/src/pages/BoardChat.tsx).
Implementation: [agent chat](../../ui/src/pages/AgentChat.tsx), [chat landing](../../ui/src/pages/AgentChats.tsx), [conference room](../../ui/src/pages/BoardChat.tsx).
Agent access: [companion](../agent-access-map/agent-chat.md).
## Sub-features
@@ -25,25 +27,32 @@ Ask for project work in Agent Chat and follow its created project/task links.
Open `/board-chat` only when its conference-room gate is enabled.
## Driving it
## Driving it with Playwright and the Paperclip CLI
Preconditions: follow the [baseline](./README.md#before-driving-a-journey). Enable the applicable chat feature, use a configured test agent, and distinguish model replies from a mocked conversation fixture.
### `agent-conversation`
Automated: [chat landing](../ui/src/pages/AgentChats.test.tsx) checks recent-chat routing; [conversation service](../server/src/__tests__/agent-conversations.test.ts) covers persisted conversation behavior.
Automated: [chat landing](../../ui/src/pages/AgentChats.test.tsx) checks recent-chat routing; [conversation service](../../server/src/__tests__/agent-conversations.test.ts) covers persisted conversation behavior.
Manual: Start a conversation, send a recognizable request, and inspect its reply. Navigate away and reopen the same history. Test a new conversation, unavailable historical agent, and an inaccessible saved conversation; verify no cross-user or cross-company history appears.
Manual: Start a conversation, send a recognizable request, and inspect its reply.
Navigate away and reopen the same history. Use `/new` for a fresh session within
the same standing conversation. Test an unavailable historical agent and an
inaccessible saved conversation; verify no cross-user or cross-company history appears.
### `project-handoff`
Automated: [chat project tools](../server/src/__tests__/chat-project-tools.test.ts) checks tool contracts; live model choice and UI handoff require a manual run.
Automated: [chat project tools](../../server/src/__tests__/chat-project-tools.test.ts) checks tool contracts; live model choice and UI handoff require a manual run.
Manual: Ask the configured agent to create bounded project work, inspect the proposed/created target, and open the resulting task. Verify the request context and intended project survived and the task produces a useful output.
### `conference-room`
Automated: [board chat gate](../server/src/__tests__/board-chat-route-feature-flag.test.ts) proves route gating, not a live conversation.
Automated: [board chat gate](../../server/src/__tests__/board-chat-route-feature-flag.test.ts) proves route gating, not a live conversation.
Preconditions for this entry point: `local_trusted` mode and an installed,
authenticated `claude` CLI, in addition to the Conference Room flag. These are
separate from Agent Chat's configured-agent prerequisites.
Manual: Check disabled access first, enable in the disposable instance, then send and reload a conversation. Inspect the actual responding agent and persisted history; report this result separately from Agent Chat.
@@ -2,11 +2,14 @@
Operators hire agents, configure their identity and instructions, assign reporting relationships, and manage their lifecycle. Built-in agents have their own setup and lifecycle constraints.
Implementation: [hiring](../ui/src/pages/NewAgent.tsx), [configuration](../ui/src/components/AgentConfigForm.tsx), [organization](../ui/src/pages/OrgChart.tsx).
Implementation: [hiring](../../ui/src/pages/NewAgent.tsx), [configuration](../../ui/src/components/AgentConfigForm.tsx), [organization](../../ui/src/pages/OrgChart.tsx).
Agent access: [companion](../agent-access-map/agents.md).
## Sub-features
- `hire`: choose role, manager, adapter, model, and required account settings.
- `hire`: choose identity, adapter, model, and required account settings; edit
reporting relationships through the agent configuration afterward.
- `instructions`: edit agent configuration and instruction files with durable revisions.
- `organization`: inspect and change reporting relationships through supported controls.
- `lifecycle`: pause/resume or retire an agent while preserving history.
@@ -26,25 +29,30 @@ Open `/agents/:agentId` and the configuration/instruction surfaces it exposes.
Use the roster’s organization view; `/org` redirects to the roster in the streamlined shell.
## Driving it
## Driving it with Playwright and the Paperclip CLI
Preconditions: follow the [baseline](./README.md#before-driving-a-journey). Use a disposable company and supported adapter; hiring may require a formal approval.
### `hire-agent`
Automated: [new agent page](../ui/src/pages/NewAgent.test.tsx) and [configuration form](../ui/src/components/AgentConfigForm.render.test.tsx) cover mocked UI behavior.
Automated: [new agent page](../../ui/src/pages/NewAgent.test.tsx) and [configuration form](../../ui/src/components/AgentConfigForm.render.test.tsx) cover mocked UI behavior.
Manual: Hire an agent with a distinct name and role. Complete any required approval, reload the roster, and open its configuration. Confirm manager, adapter, and model persisted; run a small task to prove execution readiness.
The current hiring wizard assigns the first hire CEO and subsequent hires
General reporting to the CEO. Change manager/role afterward through supported
configuration. Process/HTTP agents can be created through API/CLI but are excluded
from the hiring picker; API fixture creation does not prove this UI journey.
### `agent-configuration`
Automated: [instruction service](../server/src/__tests__/agent-instructions-service.test.ts) and [instruction revisions](../server/src/__tests__/agent-instruction-revisions.test.ts) cover file/revision contracts.
Automated: [instruction service](../../server/src/__tests__/agent-instructions-service.test.ts) and [instruction revisions](../../server/src/__tests__/agent-instruction-revisions.test.ts) cover file/revision contracts.
Manual: Save a harmless instruction edit, reload, and verify its revision and effect in the next eligible run. Pause and resume the disposable agent; confirm pause prevents new work and does not erase previous runs.
### `organization`
Automated: [org chart](../ui/src/pages/OrgChart.test.tsx) is component evidence. Built-in setup also has [configuration modal tests](../ui/src/components/ConfigureBuiltInAgentModal.test.tsx).
Automated: [org chart](../../ui/src/pages/OrgChart.test.tsx) is component evidence. Built-in setup also has [configuration modal tests](../../ui/src/components/ConfigureBuiltInAgentModal.test.tsx).
Manual: Inspect a manager and report, change the relationship through the offered controls, and reload both views. Exercise a rejected invalid relationship. Configure a built-in agent and verify it retains its required identity and restrictions.
@@ -2,7 +2,9 @@
After connecting an app, an operator decides which agents may use it and whether each action is off, requires approval, or is allowed. Activity and action tests help verify the resulting access.
Implementation: [app detail](../ui/src/pages/apps/AppDetail.tsx), [permissions](../ui/src/pages/apps/app-detail/PermissionsPanel.tsx), [activity](../ui/src/pages/apps/app-detail/ActivityPanel.tsx).
Implementation: [app detail](../../ui/src/pages/apps/AppDetail.tsx), [permissions](../../ui/src/pages/apps/app-detail/PermissionsPanel.tsx), [activity](../../ui/src/pages/apps/app-detail/ActivityPanel.tsx).
Agent access: [companion](../agent-access-map/app-permissions.md).
## Sub-features
@@ -28,13 +30,13 @@ Preconditions: follow the [baseline](./README.md#before-driving-a-journey). Prep
### `permissions`
Automated: [app detail](../ui/src/pages/apps/AppDetail.test.tsx) covers agent/action controls, quarantined actions, and navigation using mocked requests.
Automated: [app detail](../../ui/src/pages/apps/AppDetail.test.tsx) covers agent/action controls, quarantined actions, and navigation using mocked requests.
Manual: Grant one agent access, leave another excluded, and exercise off, ask, and allowed states for a harmless action. Reload between changes. Verify actual denied calls stay denied and ask-first creates a decision rather than executing early.
### `test-and-maintain`
Automated: [app detail tests](../ui/src/pages/apps/AppDetail.test.tsx) cover test-dialog/UI contracts. Real provider execution and revocation require the selected provider’s live check.
Automated: [app detail tests](../../ui/src/pages/apps/AppDetail.test.tsx) cover test-dialog/UI contracts. Real provider execution and revocation require the selected provider’s live check.
Manual: Run a read-only action with explicit inputs and inspect returned data and activity. Refresh discovery and review new actions. Revoke or disconnect only the disposable credential, then verify subsequent use fails with an actionable reconnect state.
@@ -2,7 +2,9 @@
Operators inspect recorded spend and configure budget controls for the company, projects, and agents. Hard stops pause or prevent eligible work until the governing incident is resolved.
Implementation: [costs and budget host](../ui/src/pages/Costs.tsx), [audit hub](../ui/src/pages/audit/AuditHub.tsx).
Implementation: [costs and budget host](../../ui/src/pages/Costs.tsx), [audit hub](../../ui/src/pages/audit/AuditHub.tsx).
Agent access: [companion](../agent-access-map/budgets-costs.md).
## Sub-features
@@ -21,19 +23,22 @@ Use Activity → Costs/Budgets in the streamlined shell, `/costs` in the product
Open the governing budget configuration and any resulting budget incident card.
## Driving it
## Driving it with Playwright and the Paperclip CLI
Preconditions: follow the [baseline](./README.md#before-driving-a-journey). Use synthetic low-cost events and small disposable budgets. Do not buy model usage merely to hit a threshold.
### `cost-overview`
Automated: [costs service](../server/src/__tests__/costs-service.test.ts) covers cost contracts; [embedded costs UI](../ui/src/pages/Costs.test.tsx) has narrow Audit-host coverage.
Automated: [costs service](../../server/src/__tests__/costs-service.test.ts) covers cost contracts; [embedded costs UI](../../ui/src/pages/Costs.test.tsx) has narrow Audit-host coverage.
Manual: Inspect a known fixture run and reconcile its recorded spend with the selected report period and resource. Switch company/project filters and reload. Check empty and unavailable cost data without treating missing data as zero spend.
Manual: Inspect a known fixture run and reconcile recorded spend with the chosen
period and resource. Switch the report period/company and inspect the **By
project** breakdown; it is not a project-selector filter. Reload and check empty
or unavailable cost data without treating missing data as zero spend.
### `budget-enforcement`
Automated: [budget service](../server/src/__tests__/budgets-service.test.ts) exercises soft incidents, hard stops, scope, and valid budget raises.
Automated: [budget service](../../server/src/__tests__/budgets-service.test.ts) exercises soft incidents, hard stops, scope, and valid budget raises.
Manual: Create a small fixture budget, cross its threshold with synthetic recorded spend, and verify the warning or hard-stop state. Attempt new work and confirm it is gated. Raise the correct budget through an authorized action and verify eligible continuation without clearing unrelated manual pauses.
@@ -2,7 +2,9 @@
The cases experiment exposes structured records with types, fields, parent/child relationships, activity, revisions, and related task work.
Implementation: [case list](../ui/src/pages/Cases.tsx), [case detail](../ui/src/pages/CaseDetail.tsx).
Implementation: [case list](../../ui/src/pages/Cases.tsx), [case detail](../../ui/src/pages/CaseDetail.tsx).
Agent access: [companion](../agent-access-map/cases.md).
## Sub-features
@@ -21,23 +23,29 @@ Open `/cases` and switch between available grouped/tree views.
Open `/cases/:caseIdentifier` or a task’s linked case.
## Driving it
## Driving it with Playwright and the Paperclip CLI
Preconditions: follow the [baseline](./README.md#before-driving-a-journey). Enable cases and prepare related records with different types/statuses plus an associated task.
### `case-list`
Automated: [case list](../ui/src/pages/Cases.test.tsx) covers filters, persisted view state, and keyboard/tree behavior with mocked data.
Automated: [case list](../../ui/src/pages/Cases.test.tsx) covers filters, persisted view state, and keyboard/tree behavior with mocked data.
Manual: Search for a child, verify its parent context remains understandable, change filters/grouping/columns, and reload. Open the record by keyboard and direct link. Include empty results and terminal records.
### `case-record`
Automated: [case routes](../server/src/__tests__/cases-routes.test.ts) covers API behavior; [case fields](../ui/src/components/CaseFieldsPanel.test.tsx) covers field UI separately.
Automated: [case routes](../../server/src/__tests__/cases-routes.test.ts) covers API behavior; [case fields](../../ui/src/components/CaseFieldsPanel.test.tsx) covers field UI separately.
Manual: Edit an offered field, reload, inspect its revision/activity, and follow child and task links. Verify cross-company and invalid field changes fail clearly. Distinguish a pipeline-owned item from a stand-alone case.
Manual: Change status or labels, reload, inspect activity, and follow child/task
links. Edit a case document and inspect its document revisions separately.
Arbitrary JSON fields are currently displayed without a general field editor.
Verify cross-company and invalid changes fail clearly. Distinguish a
pipeline-owned item from a stand-alone case.
## Gotchas
- A case is not a task execution; inspect linked tasks to prove work occurred.
- Feature gating and case-type schema determine which actions are available.
- Feature gating and offered controls determine available actions. The API
accepts a string case type and arbitrary JSON fields; do not infer typed
case-field validation or a field-editing UI from those values.
@@ -2,7 +2,9 @@
People can talk to an assigned agent through configured external channels, bind their identity, exchange files, and inspect delivery state. Each provider has a different identity, threading, and attachment contract.
Implementation: [endpoint setup](../ui/src/pages/apps/chat/ChatEndpointSetup.tsx), [endpoint detail](../ui/src/pages/apps/chat/ChatEndpointDetail.tsx), [email setup](../ui/src/pages/apps/chat/EmailEndpointSetup.tsx).
Implementation: [endpoint setup](../../ui/src/pages/apps/chat/ChatEndpointSetup.tsx), [endpoint detail](../../ui/src/pages/apps/chat/ChatEndpointDetail.tsx), [email setup](../../ui/src/pages/apps/chat/EmailEndpointSetup.tsx).
Agent access: [companion](../agent-access-map/chat-channels.md).
## Sub-features
@@ -22,24 +24,31 @@ Message the configured bot/address from its external provider and follow the cor
Open `/apps/chat/:endpointId/settings` and the endpoint’s other available tabs; identity confirmation uses `/chat-identity/confirm`.
## Driving it
## Driving it with Playwright and provider clients
Preconditions: follow the [baseline](./README.md#before-driving-a-journey). Enable chat connectors and use a test provider account/channel with permission to send messages. Setup is covered in [connection setup](./connection-setup.md).
Preconditions: follow the [baseline](./README.md#before-driving-a-journey). Use a
test provider account/channel with permission to send messages. Gates differ:
AgentMail bypasses the chat-connectors UI gate, GitHub uses
`enableGitHubReviewBots`, and other chat providers use `enableChatConnectors`.
Setup is covered in [connection setup](./connection-setup.md).
### `external-thread`
Automated: [channel integration](../server/src/__tests__/chat-channels.integration.test.ts) uses provider fixtures; it does not prove a live Slack, Discord, Teams, Telegram, GitHub, email, or Photon delivery.
Automated: [channel integration](../../server/src/__tests__/chat-channels.integration.test.ts) uses provider fixtures; it does not prove a live Slack, Discord, Teams, Telegram, GitHub, email, or Photon delivery.
Manual: For each supported provider being changed, send a unique message, verify the intended agent/company receives it, and inspect the actual external reply in the original thread. Repeat with an unlinked/unauthorized sender, duplicate inbound delivery, and one supported attachment. Record provider-specific results separately.
### `endpoint-management`
Automated: [channel integration](../server/src/__tests__/chat-channels.integration.test.ts) covers shared endpoint/delivery behavior; live credential repair and provider ownership remain manual checks.
Automated: [channel integration](../../server/src/__tests__/chat-channels.integration.test.ts) covers shared endpoint/delivery behavior; live credential repair and provider ownership remain manual checks.
Manual: Inspect the bound agent and identity, recent activity, and delivery failure details. Repair a disposable credential, retry a safe message when offered, and verify exactly one external reply. Disable the endpoint and confirm new traffic is not silently processed.
## Gotchas
- Visibility flags do not pause existing delivery. Disable the disposable
endpoint itself to test stopped traffic.
- One provider’s passing fixture does not qualify another provider or live delivery.
- An accepted send request does not prove the recipient received the message or file.
- Use [steering](./steering.md) and [questions](./questions-and-approvals.md) for their channel-specific interaction checks.
@@ -2,7 +2,9 @@
Operators and agents can work through explicit CLI/API context, manage domain resources, inspect runs, and create isolated local worktree instances for development.
Implementation: [command registry](../cli/src/index.ts), [client context](../cli/src/commands/client/context.ts), [worktree commands](../cli/src/commands/worktree.ts).
Implementation: [command registry](../../cli/src/index.ts), [client context](../../cli/src/commands/client/context.ts), [worktree commands](../../cli/src/commands/worktree.ts).
Agent access: [companion](../agent-access-map/cli-operations.md).
## Sub-features
@@ -25,26 +27,31 @@ Use issue subresource, asset/skill, and run/heartbeat commands exposed by the CL
### `worktree-instance`
Use the documented worktree/test-drive commands in an owned checkout; inspect `paperclipai worktree --help` first.
Inspect root help too: `worktree:make/list/merge-history/cleanup` are top-level
commands rather than subcommands of `worktree`.
## Driving it
## Driving it with the Paperclip CLI
Preconditions: follow the [baseline](./README.md#before-driving-a-journey). Use `--help` from the checked-out CLI to discover exact arguments. Select a disposable company and isolated context; do not inherit an unknown API target.
Pass the server origin to `--api-base` (without appending `/api`); the commands
already include the API path. `issue create` requires explicit `--company-id`
even when a profile stores a company. A persona label is not authentication proof.
### `client-context`
Automated: [context](../cli/src/__tests__/context.test.ts), [HTTP client](../cli/src/__tests__/http.test.ts), and [operations parity](../cli/src/__tests__/operations-parity.test.ts) cover client contracts, not every live endpoint.
Automated: [context](../../cli/src/__tests__/context.test.ts), [HTTP client](../../cli/src/__tests__/http.test.ts), and [operations parity](../../cli/src/__tests__/operations-parity.test.ts) cover client contracts, not every live endpoint.
Manual: Inspect the selected context and identity, list the disposable company’s resources, create a harmless task through the supported command, and verify it in the browser. Exercise an invalid token and wrong-company resource. Inspect JSON output and nonzero errors rather than only printed success text.
### `subresources-and-runs`
Automated: [issue subresources](../cli/src/__tests__/issue-subresources.test.ts) and [asset/skill parity](../cli/src/__tests__/admin-asset-skill-parity.test.ts) cover command/API contracts.
Automated: [issue subresources](../../cli/src/__tests__/issue-subresources.test.ts) and [asset/skill parity](../../cli/src/__tests__/admin-asset-skill-parity.test.ts) cover command/API contracts.
Manual: Write a small task document or attach a fixture using the supported command, open it in the UI, and compare contents. Invoke eligible test work, inspect the resulting run ID/status/output, and verify denial when the actor lacks permission.
### `worktree-instance`
Automated: [worktree commands](../cli/src/__tests__/worktree.test.ts) and [test drive](../cli/src/__tests__/test-drive.test.ts) cover isolation/setup contracts.
Automated: [worktree commands](../../cli/src/__tests__/worktree.test.ts) and [test drive](../../cli/src/__tests__/test-drive.test.ts) cover isolation/setup contracts.
Manual: Initialize an owned disposable worktree instance, inspect its printed paths and ports, verify health and login, and confirm any seed data belongs to the intended source. Stop and clean up only that instance; inspect preserved work before deleting any checkout.
@@ -2,7 +2,9 @@
An operator can switch between companies, change their identity and settings, archive them, and preview an import or export. Each company remains a separate scope for work and agents.
Implementation: [companies](../ui/src/pages/Companies.tsx), [settings](../ui/src/pages/CompanySettings.tsx), [import](../ui/src/pages/CompanyImport.tsx), [export](../ui/src/pages/CompanyExport.tsx).
Implementation: [companies](../../ui/src/pages/Companies.tsx), [settings](../../ui/src/pages/CompanySettings.tsx), [import](../../ui/src/pages/CompanyImport.tsx), [export](../../ui/src/pages/CompanyExport.tsx).
Agent access: [companion](../agent-access-map/companies.md).
## Sub-features
@@ -21,24 +23,28 @@ Use the company switcher or `/companies`, then enter company Settings.
Use `/company/export` and `/company/import` where enabled, or the corresponding CLI company commands.
## Driving it
## Driving it with Playwright and the Paperclip CLI
Preconditions: follow the [baseline](./README.md#before-driving-a-journey). Use two disposable companies and a small package fixture. Record cloud-managed restrictions and visible settings gates.
### `company-switcher`
Automated: [company list](../ui/src/pages/Companies.test.tsx) and [archive UI](../ui/src/pages/CompanySettingsArchive.test.tsx) cover UI behavior with mocks.
Automated: [company list](../../ui/src/pages/Companies.test.tsx) and [archive UI](../../ui/src/pages/CompanySettingsArchive.test.tsx) cover UI behavior with mocks.
Manual: Create or select a company, rename it, and reload. Switch to the second company and back; verify tasks, agents, and settings follow the selection. Archive the disposable company and verify its visibility and offered restoration path.
### `package-transfer`
Automated: [portability routes](../server/src/__tests__/company-portability-routes.test.ts) and [CLI import/export](../cli/src/__tests__/company-import-export-e2e.test.ts) cover package and command behavior, not every external Git host.
Automated: [portability routes](../../server/src/__tests__/company-portability-routes.test.ts) and [CLI import/export](../../cli/src/__tests__/company-import-export-e2e.test.ts) cover package and command behavior, not every external Git host.
Manual: Export a small company, inspect the package preview, and import into a disposable target. Verify counts, references, conflict choices, and agent configuration. Run one imported task after supplying its required local credentials. Confirm source company data is unchanged.
## Gotchas
- Restore an archived company through `/companies` → its menu → **Unarchive**.
Archiving pauses eligible agents and cancels active runs; restoration handles
agents paused specifically for company archival.
- Package presence does not prove a runnable imported company; credentials and environment bindings need separate verification.
- Company deletion is a distinct gated operation; do not use it as the archive test.
- Settings hidden in a managed deployment should be recorded as unavailable, not bypassed.
@@ -5,6 +5,8 @@ setup from either Apps or a task that needs access. A saved draft, a completed
provider login, a usable connection, and a resumed task are separate checkpoints.
Chat channels additionally require an endpoint and linked sender identity.
Agent access: [companion](../agent-access-map/connection-setup.md).
## Sub-features
- `catalog`: find a provider, inspect its available methods, and open setup;
@@ -57,22 +59,22 @@ or open `/apps/chat/connect`. Complete that provider's endpoint setup, then
open its settings (`/apps/chat/:endpointId/settings`). Follow identity linking
as the intended sender before messaging the agent externally.
## Driving it
## Driving it with Playwright and the Paperclip CLI
Preconditions: follow the [baseline](./README.md#before-driving-a-journey).
Choose a disposable provider account/resource and record its auth method,
deployment mode, account ownership, and access selection. For live setup, use
the provider's documented prerequisites in the
[connector playbook](../doc/connections/CONNECTOR-PLAYBOOK.md). Automated fixtures
[connector playbook](../../doc/connections/CONNECTOR-PLAYBOOK.md). Automated fixtures
do not establish OAuth registration, public callbacks, or production provider access.
### `apps-catalog`
Automated: [Browse](../ui/src/pages/apps/Browse.test.tsx),
[unconnected app](../ui/src/pages/apps/AppNotConnected.test.tsx), and
[AppsConnect](../ui/src/pages/apps/AppsConnect.test.tsx) cover catalog entry,
Automated: [Browse](../../ui/src/pages/apps/Browse.test.tsx),
[unconnected app](../../ui/src/pages/apps/AppNotConnected.test.tsx), and
[AppsConnect](../../ui/src/pages/apps/AppsConnect.test.tsx) cover catalog entry,
access selection, provider-specific method choices, and setup failures with
mocked APIs. [Connection intents](../tests/e2e/connection-intents.spec.ts)
mocked APIs. [Connection intents](../../tests/e2e/connection-intents.spec.ts)
drives store and task setup against one fake provider through a useful continuation:
```sh
@@ -99,7 +101,7 @@ Test no-auth and authenticated endpoints separately; never infer one from the ot
### `task-request`
Automated: [interaction card](../ui/src/components/IssueThreadInteractionCard.test.tsx)
Automated: [interaction card](../../ui/src/components/IssueThreadInteractionCard.test.tsx)
checks addressed-user controls. AppsConnect tests cover page/dialog parity,
task-bound OAuth, popup handoff, and verifying a saved connection before closing.
The connection-intents browser suite above exercises fixture-backed continuation.
@@ -114,7 +116,7 @@ task does not grant the right to resolve the request.
Automated: AppsConnect tests cover exact-draft resume, declined OAuth, reconnect
lookup failure/retry, response-lost creation, archived connection revival, and
saved account reuse. [App detail](../ui/src/pages/apps/AppDetail.test.tsx) covers
saved account reuse. [App detail](../../ui/src/pages/apps/AppDetail.test.tsx) covers
the connection host. These tests do not complete a real provider login.
Manual: leave setup through its footer, reload Apps, choose Finish setup, and
@@ -124,10 +126,10 @@ action afterwards. Count connections before/after to catch accidental duplicates
### `chat-channel`
Automated: [setup routing](../ui/src/pages/apps/chat/ChatEndpointSetup.routing.test.tsx),
[saved setup state](../ui/src/pages/apps/chat/ChatEndpointSetup.state.test.ts),
[email setup](../ui/src/pages/apps/chat/EmailEndpointSetup.test.tsx), and
[identity confirmation](../ui/src/pages/apps/chat/ChatIdentityConfirm.test.tsx)
Automated: [setup routing](../../ui/src/pages/apps/chat/ChatEndpointSetup.routing.test.tsx),
[saved setup state](../../ui/src/pages/apps/chat/ChatEndpointSetup.state.test.ts),
[email setup](../../ui/src/pages/apps/chat/EmailEndpointSetup.test.tsx), and
[identity confirmation](../../ui/src/pages/apps/chat/ChatIdentityConfirm.test.tsx)
cover shared UI logic with fixtures. Provider-specific live setup is not implied.
Manual: complete setup for one named provider, reload endpoint settings, link
@@ -138,6 +140,10 @@ Slack setup does not qualify Discord, Telegram, GitHub, email, or iMessage.
## Gotchas
- Private endpoint rejection depends on deployment: owned loopback MCP servers
are supported in local-trusted/private instances. Public authenticated
deployments apply the private-network restriction.
- A successful OAuth callback is not proof of saved connection access or task
continuation. Verify all three checkpoints.
- Personal identity, shared account access, and per-agent access are distinct.
File renamed without changes.
@@ -2,7 +2,9 @@
Contributors can inspect design examples, interaction labs, and performance fixtures. These are development surfaces and do not count as production feature verification.
Implementation: [route registration](../ui/src/App.tsx), [design guide](../ui/src/pages/DesignGuide.tsx), [long-thread fixture](../ui/src/pages/IssueChatLongThreadPerf.tsx).
Implementation: [route registration](../../ui/src/App.tsx), [design guide](../../ui/src/pages/DesignGuide.tsx), [long-thread fixture](../../ui/src/pages/IssueChatLongThreadPerf.tsx).
Agent access: [companion](../agent-access-map/developer-labs.md).
## Sub-features
@@ -21,23 +23,28 @@ Use `/design-guide`, registered `/ux-lab/...` routes, or Storybook; consult `ui/
Open `/tests/perf/long-thread` only in an appropriate development environment.
## Driving it
## Driving it with Playwright
Preconditions: follow the [baseline](./README.md#before-driving-a-journey). Use a development/test environment. Confirm the route is registered for the current build before claiming the page is available.
### `preview-lab`
Automated: [onboarding variant](../ui/src/components/OnboardingWizardVariant.test.tsx) is an example component contract. There is no claim of full automated acceptance coverage for every lab page.
Automated: [onboarding variant](../../ui/src/components/OnboardingWizardVariant.test.tsx) is an example component contract. There is no claim of full automated acceptance coverage for every lab page.
Manual: Open the specific fixture state, inspect controls and layout, then repeat the affected interaction in the actual product host. Report fixture results separately from persisted task/company results.
### `performance-fixture`
Automated: [task thread component](../ui/src/components/IssueChatThread.test.tsx) does not establish a performance budget. Timing/scroll measurements need a dedicated browser run.
Automated: [task thread component](../../ui/src/components/IssueChatThread.test.tsx) does not establish a performance budget. Timing/scroll measurements need a dedicated browser run.
Manual: Record browser/build/data size, exercise scrolling and composing in the fixture, and retain timing or trace evidence. Confirm a representative real task does not regress before extrapolating fixture measurements.
Manual: Record browser/build/data size, exercise scrolling and rendering in the
long-thread fixture, and retain timing or trace evidence. Its composer is
disabled; test composing separately in a real task. Confirm representative
real-task behavior before extrapolating fixture measurements.
## Gotchas
- An unmounted or obsolete lab file remains in the conservative page inventory but is not a shipped entry point.
- Intended developer use is not a universal runtime gate: Design Guide and
global lab/performance routes are also registered in production builds.
- Screenshots of a lab do not prove live provider behavior, persistence, or authorization.
+66
View File
@@ -0,0 +1,66 @@
# Documents, attachments, and work products
People read and revise task documents, annotate specific content, open attached files, and inspect the outputs an agent hands back. The artifact library provides another route to the same work.
Implementation: [task documents](../../ui/src/components/IssueDocumentsSection.tsx), [artifact library](../../ui/src/pages/Artifacts.tsx), [document panel](../../ui/src/components/task-side-panel/TaskDocumentPanel.tsx).
Agent access: [companion](../agent-access-map/documents-artifacts.md).
## Sub-features
- `documents`: edit versioned task documents and inspect or restore revisions.
- `annotations`: attach feedback to document content and inspect resolution state.
- `attachments`: upload, preview, and download allowed files with company access checks.
- `work-products`: link deliverables to their source task, resource, and review context.
- `library`: search, filter, group, and open artifact stacks.
## How to get to it (user POV)
### `task-document`
Open a document from the task thread or document side panel.
### `task-output`
Open an attachment, output card, or file link from a task.
For direct uploads, use the task side panel's **Open a new tab → Artifacts →
Upload files** or drop files anywhere in that panel. On mobile, open
**More actions → Properties** first. Agent conversations do not expose this upload path.
### `artifact-library`
Open `/artifacts` and its grouping, search, and media controls.
## Driving it with Playwright and the Paperclip CLI
Preconditions: follow the [baseline](./README.md#before-driving-a-journey). Use a task with a text document, a small attachment, and a generated work product. Use nonsensitive fixture files.
### `task-document`
Automated: [documents service](../../server/src/__tests__/documents-service.test.ts), [annotations](../../server/src/__tests__/document-annotations-service.test.ts), and [revision restore](../../server/src/__tests__/issue-document-restore-routes.test.ts) cover server contracts.
Manual: Edit a paragraph, save, reload, and compare revisions. Add an annotation to a specific selection and inspect it after another edit. Resolve it through the supported action. Restore a disposable revision and confirm the new current document and history agree.
### `task-output`
Automated: [attachment routes](../../server/src/__tests__/issue-attachment-routes.test.ts) and [work products](../../server/src/__tests__/work-products.test.ts) cover data/access behavior; [artifact arrival browser suite](../../tests/e2e/artifact-tab-arrival.spec.ts) targets arrival. [Artifact uploads](../../tests/e2e/artifact-uploads.spec.ts) drives file selection/drop, filename collisions, retry, and preservation of paused/unassigned tasks.
Manual: Upload a small Markdown file and CSV through Artifacts. Markdown becomes
a versioned task document; other files become attachments. Read the document,
download the CSV and compare bytes, then reload. Upload the same Markdown filename
again and verify a separate suffixed document without overwriting the original.
On a paused unassigned task, confirm upload does not start work or add comments.
Verify agent-produced work products separately using an eligible test run.
Test an inaccessible user/company and explicit missing workspace-only resources.
### `artifact-library`
Automated: [artifact page](../../ui/src/pages/Artifacts.test.tsx) covers grouping, search requests, and pagination using mocks.
Manual: Find the task’s output through search and grouping, open its stack, page through results, and reload a direct stack link. Confirm the same file/content appears as from the task.
## Gotchas
- A local path is not automatically an uploaded artifact accessible to another user.
- A preview screenshot is not proof that download bytes or revision references are correct.
- Version conflicts and stale annotations must stay visible rather than silently targeting different content.
@@ -2,7 +2,9 @@
Operators configure where agents execute, probe readiness, select an environment for work, and inspect remote provisioning or custom-image state when the installed provider supports it.
Implementation: [environment settings](../ui/src/pages/CompanyEnvironments.tsx), [environment runtime](../server/src/services/environment-runtime.ts).
Implementation: [environment settings](../../ui/src/pages/CompanyEnvironments.tsx), [environment runtime](../../server/src/services/environment-runtime.ts).
Agent access: [companion](../agent-access-map/execution-environments.md).
## Sub-features
@@ -17,24 +19,32 @@ Implementation: [environment settings](../ui/src/pages/CompanyEnvironments.tsx),
### `environment-settings`
Open Settings → Environments, then create/edit a supported target.
The canonical URL is `/company/settings/instance/environments`. Enable
`enableEnvironments` first; keep `enableManagedSandboxOnly` off to inspect local
targets. The catalog is instance-scoped and mutation requires a local operator
or instance administrator.
### `remote-execution`
Choose the environment in agent/project/workspace configuration, then inspect the resulting task/run and workspace.
## Driving it
## Driving it with Playwright and the Paperclip CLI
Preconditions: follow the [baseline](./README.md#before-driving-a-journey). Use an owned disposable target and a supported provider plugin. Record provider, target identity, account, and spending constraints before a live remote run.
### `environment-settings`
Automated: [environment UI](../ui/src/pages/CompanyEnvironments.test.tsx), [driver configuration UI](../ui/src/pages/CompanySettings.test.tsx), and [environment service](../server/src/__tests__/environment-service.test.ts) cover configuration behavior.
Automated: [environment UI](../../ui/src/pages/CompanyEnvironments.test.tsx), [driver configuration UI](../../ui/src/pages/CompanySettings.test.tsx), and [environment service](../../server/src/__tests__/environment-service.test.ts) cover configuration behavior.
Manual: Save a disposable target, reload it, and run its available probe. Verify both success and missing-credential/reachability errors identify the target. Confirm unavailable providers are not offered as working run targets.
The local row has no UI Test button. Its API/CLI probe reports host/cwd
availability only; it does not validate an adapter binary, workspace, or task
execution. Remote-driver probes and a real bounded run need their own evidence.
### `remote-execution`
Automated: [execution target](../server/src/__tests__/environment-execution-target.test.ts) and [custom images](../server/src/__tests__/environment-custom-images-service.test.ts) cover contracts; [SSH live test](../server/src/__tests__/environment-live-ssh.test.ts) requires its own external setup.
Automated: [execution target](../../server/src/__tests__/environment-execution-target.test.ts) and [custom images](../../server/src/__tests__/environment-custom-images-service.test.ts) cover contracts; [SSH live test](../../server/src/__tests__/environment-live-ssh.test.ts) requires its own external setup.
Manual: Run a bounded command in the intended target, inspect its output and workspace, and verify execution did not silently fall back to the server host. For custom-image changes, build/probe the disposable image before assigning it. Inspect cleanup and shutdown after the run.
@@ -2,11 +2,13 @@
Administrators expose selected tools through gateways and reusable access profiles, connect clients, manage tokens, and inspect gateway activity.
Implementation: [gateways](../ui/src/pages/apps/gateways/GatewaysList.tsx), [gateway detail](../ui/src/pages/apps/gateways/GatewayDetail.tsx), [profiles](../ui/src/pages/tools/profiles/ProfileWizard.tsx).
Implementation: [gateways](../../ui/src/pages/apps/gateways/GatewaysList.tsx), [gateway detail](../../ui/src/pages/apps/gateways/GatewayDetail.tsx), [profiles](../../ui/src/pages/tools/profiles/ProfileWizard.tsx).
Agent access: [companion](../agent-access-map/gateways-profiles.md).
## Sub-features
- `gateway`: create/edit an endpoint and select its exposed apps/tools.
- `gateway`: create/edit an endpoint backed by a tool access profile.
- `profiles`: define reusable tool access configuration and inspect draft/detail state.
- `client-connect`: copy the intended endpoint/configuration to an authorized test client.
- `tokens`: create/revoke client credentials and verify their scope.
@@ -22,19 +24,24 @@ Open `/apps/gateways`, then a gateway’s Overview, Apps/Tools, Tokens, and Acti
Open `/apps/advanced/profiles`, create a profile, or follow its detail/edit route.
## Driving it
## Driving it with Playwright and an MCP client
Preconditions: follow the [baseline](./README.md#before-driving-a-journey). Use a fixture tool connection and test client. Record gateway/profile, token owner, transport, and selected company.
Gateway creation selects a profile. Maintain that profile's app/action selection
through the Apps/Tools links; the gateway form is not a separate tool picker.
Use an active organization member for human-scoped access, and check the actual
endpoint authorization independently of whether the admin UI is visible.
### `gateway-client`
Automated: [gateway service](../server/src/__tests__/tool-gateway-service.test.ts), [connect client dialog](../ui/src/pages/apps/gateways/ConnectClientDialog.test.tsx), and [token panel](../ui/src/pages/apps/gateways/panels/TokensPanel.test.tsx) cover service/UI contracts.
Automated: [gateway service](../../server/src/__tests__/tool-gateway-service.test.ts), [connect client dialog](../../ui/src/pages/apps/gateways/ConnectClientDialog.test.tsx), and [token panel](../../ui/src/pages/apps/gateways/panels/TokensPanel.test.tsx) cover service/UI contracts.
Manual: Create a disposable gateway with one harmless tool, connect a client using its provided configuration, discover/call that tool, and inspect activity. Revoke the client token and confirm the same call fails. Test a tool outside the allowed set.
### `access-profile`
Automated: [profile wizard](../ui/src/pages/tools/profiles/ProfileWizard.test.tsx) and [profile detail](../ui/src/pages/tools/profiles/ProfileDetail.test.tsx) cover component behavior with mocks.
Automated: [profile wizard](../../ui/src/pages/tools/profiles/ProfileWizard.test.tsx) and [profile detail](../../ui/src/pages/tools/profiles/ProfileDetail.test.tsx) cover component behavior with mocks.
Manual: Create a bounded profile, choose its offered tools and options, save or resume its draft, and reload the detail. Apply/connect it through the offered flow and inspect the actual client-visible tool set. Verify cancellation and invalid selections retain an understandable draft.
@@ -2,7 +2,9 @@
People define company and lower-level goals and connect projects and tasks to the outcome they serve.
Implementation: [goals](../ui/src/pages/Goals.tsx), [goal detail](../ui/src/pages/GoalDetail.tsx).
Implementation: [goals](../../ui/src/pages/Goals.tsx), [goal detail](../../ui/src/pages/GoalDetail.tsx).
Agent access: [companion](../agent-access-map/goals.md).
## Sub-features
@@ -20,19 +22,24 @@ Open `/goals`, create a goal, and enter `/goals/:goalId`.
Inspect the goal context from a project or task and compare explicit versus inherited context.
## Driving it
## Driving it with Playwright and the Paperclip CLI
Preconditions: follow the [baseline](./README.md#before-driving-a-journey). Prepare two goals and a disposable project/task in the selected company.
### `goal-detail`
Automated: [project-goal validation](../server/src/__tests__/project-goal-validation.test.ts) covers relationship validation; [goal detail control](../ui/src/pages/GoalDetail.test.tsx) only tests the properties toggle, not the whole creation journey.
Automated: [project-goal validation](../../server/src/__tests__/project-goal-validation.test.ts) covers relationship validation; [goal detail control](../../ui/src/pages/GoalDetail.test.tsx) only tests the properties toggle, not the whole creation journey.
Manual: Create a parent and child goal, save owner/status changes, and reload. Link a project and task through the offered controls, follow their goal context, and verify a cross-company or invalid relationship is rejected.
Manual: Choose **Add Goal/New Goal**, enter **Goal title**, select the level, and
create a parent. Open it and choose **Sub Goal** to create a child with the
parent preselected. Change status in Properties and reload; follow the Parent
Goal link and inspect Sub-Goals. Owner is currently display-only in this UI.
Link a project and task through the offered controls, follow their goal context,
and verify a cross-company or invalid relationship is rejected.
### `task-goal-context`
Automated: [task goal routes](../server/src/__tests__/issues-goal-context-routes.test.ts) and [goal fallback](../server/src/__tests__/issue-goal-fallback.test.ts) cover the server rules.
Automated: [task goal routes](../../server/src/__tests__/issues-goal-context-routes.test.ts) and [goal fallback](../../server/src/__tests__/issue-goal-fallback.test.ts) cover the server rules.
Manual: Compare a task with an explicit goal to one relying on project context. Change the allowed association, reload, and verify the displayed/injected context follows the documented server rule rather than retaining an unrelated goal.
@@ -2,7 +2,9 @@
People find work that needs their attention, distinguish unread activity from required decisions, archive handled items, and search across the company.
Implementation: [inbox](../ui/src/pages/Inbox.tsx), [decisions](../ui/src/pages/WhatNeedsMe.tsx), [search](../ui/src/pages/Search.tsx).
Implementation: [inbox](../../ui/src/pages/Inbox.tsx), [decisions](../../ui/src/pages/WhatNeedsMe.tsx), [search](../../ui/src/pages/Search.tsx).
Agent access: [companion](../agent-access-map/inbox-search.md).
## Sub-features
@@ -25,30 +27,34 @@ Open `/decisions`, then a queue at `/decisions/queues/:key` and its source item.
Open `/search` or the navigation search entry.
## Driving it
## Driving it with Playwright and the Paperclip CLI
Preconditions: follow the [baseline](./README.md#before-driving-a-journey). Seed assigned, unread, blocked, and resolved tasks plus a pending decision. Record the combined Inbox/Tasks experimental setting.
### `inbox`
Automated: [archive routes](../server/src/__tests__/inbox-archive-routes.test.ts) cover server mutations. [Task-list helpers](../ui/src/pages/Issues.test.tsx) cover search URLs, pagination, and presentation constants; they do not render the combined Inbox/Tasks page. Reading, archiving, and navigating that page remain manual checks.
Automated: [archive routes](../../server/src/__tests__/inbox-archive-routes.test.ts) cover server mutations. [Task-list helpers](../../ui/src/pages/Issues.test.tsx) cover search URLs, pagination, and presentation constants; they do not render the combined Inbox/Tasks page. Reading, archiving, and navigating that page remain manual checks.
Manual: Read an unread task, return to Unread, archive a handled item, and reload. Verify personal triage state changes while task status stays correct. Switch users and companies to check isolation.
### `decisions`
Automated: [decision queues](../server/src/__tests__/decision-queues-routes.test.ts) covers route behavior. End-to-end queue-to-source navigation is manual.
Automated: [decision queues](../../server/src/__tests__/decision-queues-routes.test.ts) covers route behavior. End-to-end queue-to-source navigation is manual.
Manual: Open a pending decision, follow its source, resolve it through the supported control, and reload the queue. Confirm it retires only after the decision persisted and unrelated pending items remain.
### `search`
Automated: [search page](../ui/src/pages/Search.test.tsx) and [company search service](../server/src/__tests__/company-search-service.test.ts) cover UI and server search separately.
Automated: [search page](../../ui/src/pages/Search.test.tsx) and [company search service](../../server/src/__tests__/company-search-service.test.ts) cover UI and server search separately.
Manual: Search a unique task title and content phrase, open the result, and compare the actual record. Test filters, no results, and a second company. Verify stale results do not expose inaccessible data.
## Gotchas
- Combined Inbox/Tasks requires both `enableCombinedInboxTasks` and
`enableStreamlinedUi`. [Standalone Inbox tests](../../ui/src/pages/Inbox.test.tsx)
render archive/read controls and toolbars; this is not live multi-user evidence.
- Personal archival is not task cancellation or completion.
- Legacy Inbox routes can redirect to the combined task view; record which host actually rendered.
- Search service tests do not establish the relevance quality of every query.
@@ -2,7 +2,9 @@
An operator can install and run Paperclip, diagnose the instance, configure supported deployment settings, manage its service, and produce a recoverable database backup.
Implementation: [CLI entry point](../cli/src/index.ts), [instance settings](../ui/src/pages/InstanceExperimentalSettings.tsx), [backup command](../cli/src/commands/db-backup.ts).
Implementation: [CLI entry point](../../cli/src/index.ts), [instance settings](../../ui/src/pages/InstanceExperimentalSettings.tsx), [backup command](../../cli/src/commands/db-backup.ts).
Agent access: [companion](../agent-access-map/instance-operations.md).
## Sub-features
@@ -22,24 +24,29 @@ Use `paperclipai install`, `run`, `service`, `doctor`, `configure`, `channels`,
Use currently visible instance settings for experiments/access and `paperclipai db:backup --help` for one-off backup. Some legacy general-settings URLs redirect.
## Driving it
## Driving it with Playwright and the Paperclip CLI
Preconditions: follow the [baseline](./README.md#before-driving-a-journey). Use a disposable data directory/service identity. Do not update, restart, or restore over an unrelated live instance as a documentation test.
### `operator-cli`
Automated: [doctor](../cli/src/__tests__/doctor.test.ts), [update command](../cli/src/__tests__/update-command.test.ts), and [service manager](../cli/src/__tests__/service-manager.test.ts) cover command contracts.
Automated: [doctor](../../cli/src/__tests__/doctor.test.ts), [update command](../../cli/src/__tests__/update-command.test.ts), and [service manager](../../cli/src/__tests__/service-manager.test.ts) cover command contracts.
Manual: Inspect the selected installation/channel and configuration, start the isolated instance, confirm health and browser access, then stop that instance. For update changes, use the dry-run/check path first and verify installed version and rollback state on an owned disposable installation.
### `settings-backup`
Automated: [experimental settings](../ui/src/pages/InstanceExperimentalSettings.test.tsx) and [database backup routes](../server/src/__tests__/instance-database-backups-routes.test.ts) cover their UI/API contracts.
Automated: [experimental settings](../../ui/src/pages/InstanceExperimentalSettings.test.tsx) and [database backup routes](../../server/src/__tests__/instance-database-backups-routes.test.ts) cover their UI/API contracts.
Manual: Change a harmless experimental setting, reload, and confirm the affected route honors it. Back up a disposable instance, inspect the reported file and metadata, and restore using the documented procedure into a second isolated target. Verify a known record after restoration.
## Gotchas
- Source-checkout update/check commands report manual update guidance; they do
not qualify a managed installation. Rollback restores retained CLI payloads,
not database migrations. Service status applies to its selected service
identity, not automatically to an owned foreground dev server.
- A successful backup write does not prove restoration works.
- Settings visibility and mutability differ for cloud-managed and self-hosted instances.
- Keep the three data paths distinct: first-party Telemetry, operator-configured OpenTelemetry, and local run logs.
@@ -2,7 +2,9 @@
People organize their sidebar, move between company resources, maintain their profile, and dismiss product announcements with the correct persistence and identity scope.
Implementation: [sidebar](../ui/src/components/Sidebar.tsx), [profile](../ui/src/pages/ProfileSettings.tsx), [announcements](../ui/src/components/AnnouncementWell.tsx).
Implementation: [sidebar](../../ui/src/components/Sidebar.tsx), [profile](../../ui/src/pages/ProfileSettings.tsx), [announcements](../../ui/src/components/AnnouncementWell.tsx).
Agent access: [companion](../agent-access-map/navigation-preferences.md).
## Sub-features
@@ -22,19 +24,24 @@ Use starred/recent/sidebar links and direct company-prefixed URLs.
Use Settings → Profile, `/u/:userSlug`, and the announcement well when a publication is available.
## Driving it
## Driving it with Playwright and the Paperclip CLI
Preconditions: follow the [baseline](./README.md#before-driving-a-journey). Use two test users and companies; record the selected UI shell and any client-local preference storage.
### `sidebar-deep-links`
Automated: [sidebar](../ui/src/components/Sidebar.test.tsx) and [sidebar preference routes](../server/src/__tests__/sidebar-preferences-routes.test.ts) cover UI/server behavior.
Automated: [sidebar](../../ui/src/components/Sidebar.test.tsx) and [sidebar preference routes](../../server/src/__tests__/sidebar-preferences-routes.test.ts) cover UI/server behavior.
Manual: Star and reorder supported resources, collapse a section, navigate and reload. Switch company/user and inspect the intended preference scope. Open an unavailable resource and a legacy route; verify clear fallback or correct redirect without leaking another company’s state.
Record persistence separately: section collapse is in-memory and reopens after
reload; global sidebar collapse is disabled. Streamlined starred projects sort
alphabetically. Recents are browser-local by user/company; stars and supported
ordering are saved server-side. Local-trusted mode does not prove two-user isolation.
### `profile-announcements`
Automated: [profile page](../ui/src/pages/ProfileSettings.test.tsx), [announcement hook](../ui/src/hooks/useAnnouncement.test.tsx), and [announcement routes](../server/src/__tests__/announcements-routes.test.ts) cover separate UI/persistence layers.
Automated: [profile page](../../ui/src/pages/ProfileSettings.test.tsx), [announcement hook](../../ui/src/hooks/useAnnouncement.test.tsx), and [announcement routes](../../server/src/__tests__/announcements-routes.test.ts) cover separate UI/persistence layers.
Manual: Change a disposable user’s display details, reload, and inspect an attributed profile link. Dismiss a fixture announcement, switch companies, and verify it remains dismissed for that user; check another user still has their own dismissal state.
+63
View File
@@ -0,0 +1,63 @@
# Onboarding and first work
An operator can start an instance, create a company, configure its first agent, and reach a real first task. Instance setup and company onboarding are separate steps.
Implementation: [web wizard](../../ui/src/components/OnboardingWizard.tsx), [CLI setup](../../cli/src/commands/onboard.ts).
Agent access: [companion](../agent-access-map/onboarding.md).
## Sub-features
- `instance`: choose local instance configuration and start the server.
- `company`: create a company with its identity and initial agent.
- `adapter`: choose an available harness, model, account, and execution environment.
- `first-task`: leave setup with a task whose execution or missing prerequisite is visible.
- `resume`: return to an incomplete wizard without losing saved state.
## How to get to it (user POV)
### `web-wizard`
Open `/onboarding` or the onboarding launcher in an empty company context.
Use `/<company-prefix>/onboarding` to resume an existing company's agent setup;
the unprefixed route starts at organization naming on self-hosted instances.
Cloud-managed instances reuse their existing company for agent setup.
### `cli-setup`
Use `paperclipai onboard --help` or `paperclipai run --help` to select an isolated data directory before setup.
## Driving it with Playwright and the Paperclip CLI
Preconditions: follow the [baseline](./README.md#before-driving-a-journey). Use a new isolated data directory and record deployment mode. A configured adapter may still need account authentication.
### `web-wizard`
Automated: [wizard tests](../../ui/src/components/OnboardingWizard.test.tsx) cover mocked wizard behavior; [onboarding browser suite](../../tests/e2e/onboarding.spec.ts) supplies its own test environment. Live model execution is a separate check.
- **Create company and resume.** Start a fresh empty instance and run doctor using
the [verification skill](../../.agents/skills/verify-paperclip/SKILL.md). Run
`node .agents/skills/verify-paperclip/scripts/onboarding-smoke.mjs --evidence-dir "$VERIFY_EVIDENCE_DIR"`.
The helper opens `/onboarding` in a fresh self-hosted instance, enters a unique
name in `e.g. Northwind Labs`, and chooses `Continue`. The agent-name field must
appear and the saved company must have no invented goal. Reopen the
company-prefixed onboarding route and reload; the agent step must appear
without creating another company. Screenshots and a trace capture the real UI action and result.
This proves company creation/resumption, not hiring or a first model run.
Manual: Create a disposable company and first agent. Leave midway, reopen the
company's onboarding route, and finish; drafts save automatically. Follow the
created first task, verify the selected agent and company, and inspect its output
or explicit authentication gate. Reload both company and task.
### `cli-setup`
Automated: [CLI onboarding](../../cli/src/__tests__/onboard.test.ts) and [isolated test drive](../../cli/src/__tests__/test-drive.test.ts) cover their setup contracts; they do not establish that every model account is usable.
Manual: Run setup in the disposable directory, open the URL it prints, and confirm the instance identity and company. Restart using that same configuration and verify saved state. Exercise an unavailable adapter and confirm an actionable error.
## Gotchas
- An empty company, an empty instance, and an unauthenticated browser are different states.
- Creating an agent does not prove its provider login or first execution succeeded.
- See [access](./access.md) for authenticated deployments and [agents](./agents.md) for later hiring.
@@ -2,7 +2,9 @@
With the pipeline experiment enabled, people move structured work through configured stages, inspect stage automation, review outputs, and retain learning records.
Implementation: [pipeline board and item hosts](../ui/src/pages/Pipelines.tsx), [pipeline configuration](../ui/src/pages/PipelineSettings.tsx).
Implementation: [pipeline board and item hosts](../../ui/src/pages/Pipelines.tsx), [pipeline configuration](../../ui/src/pages/PipelineSettings.tsx).
Agent access: [companion](../agent-access-map/pipelines.md).
## Sub-features
@@ -21,24 +23,28 @@ Open `/pipelines`, `/pipelines/:pipelineId`, and its Settings route.
Open `/pipelines/:pipelineId/items/:caseId`, `/review-queue`, or `/learnings`.
## Driving it
## Driving it with Playwright and the Paperclip CLI
Preconditions: follow the [baseline](./README.md#before-driving-a-journey). Enable pipelines and prepare a disposable pipeline with at least two stages and a fixture agent. Record any associated case type.
### `pipeline-board`
Automated: [pipeline UI helpers](../ui/src/pages/Pipelines.test.tsx) cover grouping and presentation helpers; [pipeline service](../server/src/__tests__/pipelines-service.test.ts) covers service behavior.
Automated: [pipeline UI helpers](../../ui/src/pages/Pipelines.test.tsx) cover grouping and presentation helpers; [pipeline service](../../server/src/__tests__/pipelines-service.test.ts) covers service behavior.
Manual: Configure stages and a harmless automation, add an item, and inspect its stage. Follow its task/work references and observe the resulting transition. Reload grouping and settings; verify rejected or failed transitions leave the item in an intelligible state.
### `item-review-learning`
Automated: [pipeline tutorial browser suite](../tests/e2e/pipelines-tutorial-flow.spec.ts) targets a fixture journey; it does not qualify arbitrary stage automation or learning quality.
Automated: [pipeline tutorial browser suite](../../tests/e2e/pipelines-tutorial-flow.spec.ts) targets a fixture journey; it does not qualify arbitrary stage automation or learning quality.
Manual: Open a pending review, inspect its source output and revision, accept or reject, and verify the persisted stage outcome. Follow a learning record to its source context and confirm it belongs to the intended pipeline/company.
## Gotchas
- Learnings is filtered case-event history, such as review decisions and forced
moves, not a separate authored learning-record system. The UI visibility flag
is separate from API authorization.
- These routes are experimental and may redirect or deny access when disabled.
- ReviewQueue and Learnings are hosted from the pipeline module; a page-file inventory alone misses them.
- Pipeline items and free-standing [cases](./cases.md) share records but have different navigation contexts.
@@ -2,7 +2,9 @@
Operators install and configure plugins, inspect their status and errors, and use their contributed pages, tools, and managed resources within the plugin’s granted capabilities.
Implementation: [plugin manager](../ui/src/pages/PluginManager.tsx), [plugin settings](../ui/src/pages/PluginSettings.tsx), [plugin page](../ui/src/pages/PluginPage.tsx).
Implementation: [plugin manager](../../ui/src/pages/PluginManager.tsx), [plugin settings](../../ui/src/pages/PluginSettings.tsx), [plugin page](../../ui/src/pages/PluginPage.tsx).
Agent access: [companion](../agent-access-map/plugins.md).
## Sub-features
@@ -21,24 +23,29 @@ Open Settings → Plugins where permitted, or the CLI plugin commands.
Open `/plugins/:pluginId`, a registered plugin route, or its contributed company/project settings surface.
## Driving it
## Driving it with Playwright and the Paperclip CLI
Preconditions: follow the [baseline](./README.md#before-driving-a-journey). Use a known local fixture plugin with bounded capabilities. Record installed version and any declared external dependencies.
### `plugin-administration`
Automated: [install authorization](../server/src/__tests__/plugin-install-route-security.test.ts) and [plugin settings](../ui/src/pages/PluginSettings.test.tsx) cover route/UI contracts.
Automated: [install authorization](../../server/src/__tests__/plugin-install-route-security.test.ts) and [plugin settings](../../ui/src/pages/PluginSettings.test.tsx) cover route/UI contracts.
Manual: Install the fixture, supply its configuration, activate it, and inspect status. Save an invalid configuration and verify a useful error. Disable/remove the disposable plugin and check its tools and managed resources no longer behave as active.
### `plugin-contribution`
Automated: [static plugin UI](../server/src/__tests__/plugin-ui-static.test.ts) and [company settings contribution](../ui/src/pages/CompanySettingsPluginPage.test.tsx) cover serving/host behavior.
Automated: [static plugin UI](../../server/src/__tests__/plugin-ui-static.test.ts) and [company settings contribution](../../ui/src/pages/CompanySettingsPluginPage.test.tsx) cover serving/host behavior.
Manual: Open the contributed page by navigation and cold deep link, perform a harmless plugin action, and inspect its real outcome. Switch company and test an actor without the capability. Reload with the plugin unavailable and verify the host reports that state.
## Gotchas
- Installation/lifecycle is instance-level; configuration can be company-scoped.
Settings lives at `/company/settings/instance/plugins`. npm installation and
bundled-local installation are different controls. Developer file-watcher
reload is not a lifecycle action in the plugin manager.
- Installing a plugin does not authorize every host capability or external action.
- Plugin-provided routes are dynamic; this map covers the host lifecycle, not every third-party feature.
- Environment-driver plugins also need the [environment](./execution-environments.md) checks.
@@ -2,7 +2,9 @@
People group tasks into projects, attach goals and repositories, and configure the context and defaults used by project work.
Implementation: [project list](../ui/src/pages/Projects.tsx), [project detail](../ui/src/pages/ProjectDetail.tsx).
Implementation: [project list](../../ui/src/pages/Projects.tsx), [project detail](../../ui/src/pages/ProjectDetail.tsx).
Agent access: [companion](../agent-access-map/projects.md).
## Sub-features
@@ -21,24 +23,31 @@ Open `/projects`, create a project, and enter its overview or Issues view.
Open `/projects/:projectId/configuration` and its repository/workspace settings.
## Driving it
## Driving it with Playwright and the Paperclip CLI
Preconditions: follow the [baseline](./README.md#before-driving-a-journey). Use a disposable project and a small repository you can access; record checkout and credential ownership.
### `project-list`
Automated: [projects UI](../ui/src/pages/Projects.test.tsx) and [project detail](../ui/src/pages/ProjectDetail.test.tsx) are component tests.
Automated: [projects UI](../../ui/src/pages/Projects.test.tsx) and [project detail](../../ui/src/pages/ProjectDetail.test.tsx) are component tests.
Manual: Create a project, add a task from its view, and reload. Verify the task belongs to that project, list counts are plausible, and links preserve company scope. Archive only the disposable project and inspect list/task behavior.
### `repository-settings`
Automated: [repository persistence](../server/src/__tests__/project-repositories-persistence.test.ts) and [repository browser suite](../tests/e2e/project-repositories.spec.ts) cover configured repository workflows.
Automated: [repository persistence](../../server/src/__tests__/project-repositories-persistence.test.ts) and [repository browser suite](../../tests/e2e/project-repositories.spec.ts) cover configured repository workflows.
Manual: Attach a small repository, save, and create a project task. Inspect the actual checkout/revision used by its run. Test an invalid repository and missing credentials without treating a saved URL as a working workspace.
## Gotchas
- `/overview` now selects Configuration, not a distinct overview page. Personal
join/leave and star controls have their own persistence and should be checked
when affected; **Star/Unstar {project name}** is the visible star action.
- Project name slugs change on rename and have no historical alias lookup.
Reopen a renamed project through its stable UUID route, wait for the current
Configuration form, and record the newly normalized URL before reloading.
- Project repository configuration and a provisioned execution workspace are different records.
- See [workspaces](./workspaces.md), [goals](./goals.md), and [budgets](./budgets-costs.md) for those features.
- Do not assume a deleted or archived project should erase its historical task evidence.
@@ -5,6 +5,8 @@ history. A question, plan confirmation, governance approval, and app-tool review
can look similar but have different authority and continuation rules. Each
decision must stay attached to its original request and survive reload.
Agent access: [companion](../agent-access-map/questions-and-approvals.md).
## Sub-features
- `questions`: single-choice, multiple-choice, custom, and free-text answers;
@@ -78,11 +80,11 @@ a component fixture alone cannot prove live response delivery.
### `task-thread`
Automated: [interaction cards](../ui/src/components/IssueThreadInteractionCard.test.tsx),
[paged task cards](../ui/src/components/task-chat/TaskChatInteractionCard.test.tsx),
and [task thread](../ui/src/components/TaskChatThread.test.tsx) cover form,
receipt, and dismissal behavior. [Resolution routes](../server/src/__tests__/issue-thread-interaction-routes.test.ts)
and [response delivery](../server/src/__tests__/question-response-delivery.test.ts)
Automated: [interaction cards](../../ui/src/components/IssueThreadInteractionCard.test.tsx),
[paged task cards](../../ui/src/components/task-chat/TaskChatInteractionCard.test.tsx),
and [task thread](../../ui/src/components/TaskChatThread.test.tsx) cover form,
receipt, and dismissal behavior. [Resolution routes](../../server/src/__tests__/issue-thread-interaction-routes.test.ts)
and [response delivery](../../server/src/__tests__/question-response-delivery.test.ts)
cover authority and durable continuation. Run a targeted set with:
```sh
@@ -99,7 +101,7 @@ before trying the old approval, then review the current revision.
### `agent-chat`
Automated: the [task thread suite](../ui/src/components/TaskChatThread.test.tsx)
Automated: the [task thread suite](../../ui/src/components/TaskChatThread.test.tsx)
parameterizes unanswered-question history for conversation mode on and off.
This proves component parity, not a model's plan handoff.
@@ -109,7 +111,7 @@ history remains and the conversation does not close as a completed task.
### `attention`
Automated: [attention resolver](../ui/src/components/AttentionInteractionResolver.test.tsx)
Automated: [attention resolver](../../ui/src/components/AttentionInteractionResolver.test.tsx)
covers preparing-request refresh without accepting it. The resolution-route
tests above cover the API, not every Decisions or Inbox navigation path.
@@ -121,8 +123,8 @@ manual coverage gap.
### `board-approval`
Automated: [approval service](../server/src/__tests__/approvals-service.test.ts)
and [idempotency routes](../server/src/__tests__/approval-routes-idempotency.test.ts)
Automated: [approval service](../../server/src/__tests__/approvals-service.test.ts)
and [idempotency routes](../../server/src/__tests__/approval-routes-idempotency.test.ts)
cover persistence and duplicate decisions. They do not drive the approval pages.
Manual: create disposable formal approval requests; approve one from the list,
@@ -132,7 +134,7 @@ the recorded decision and its governed effect, not just a success toast.
### `app-review`
Automated: [connection reviews](../tests/e2e/connection-reviews.spec.ts) drives
Automated: [connection reviews](../../tests/e2e/connection-reviews.spec.ts) drives
task/queue synchronization, approve, decline, remembered permission, provider
failure, and restart with a scripted process agent and local MCP provider:
@@ -144,11 +146,11 @@ Manual: dismiss and reopen a review, decide it from each entry point using fresh
requests, and inspect the continuation's useful result. Always allow must show
its scope; a future action with changed arguments should obey the saved rule.
Provider failure must remain an approved decision with a failed execution.
Real provider and model checks follow [Task reviews](../doc/connections/TASK-REVIEWS.md#verification-workflows).
Real provider and model checks follow [Task reviews](../../doc/connections/TASK-REVIEWS.md#verification-workflows).
### `skill-test`
Automated: [read-only interaction contract](../server/src/__tests__/issue-thread-interaction-routes.test.ts)
Automated: [read-only interaction contract](../../server/src/__tests__/issue-thread-interaction-routes.test.ts)
checks that fetching interactions does not mutate them. Shared card suites cover
rendering. Neither proves the complete Skill Studio host or its permission matrix.
@@ -159,9 +161,9 @@ referenced unit tests.
### `external-channel`
Automated: [chat question forms](../server/src/services/chat-question-forms.test.ts),
[Discord forms](../server/src/services/chat-discord-question-forms.test.ts),
and [interaction publications](../server/src/__tests__/chat-interaction-publications.test.ts)
Automated: [chat question forms](../../server/src/services/chat-question-forms.test.ts),
[Discord forms](../../server/src/services/chat-discord-question-forms.test.ts),
and [interaction publications](../../server/src/__tests__/chat-interaction-publications.test.ts)
cover serialization and delivery logic with fixtures.
Manual: use a disposable provider conversation, answer as the linked sender,
@@ -5,6 +5,8 @@ continuation is available. Recovery retains task context and ownership, honors
pause and budget gates, and distinguishes confirmed failure from an uncertain
external outcome. A retry acknowledgement alone is not proof that work resumed.
Agent access: [companion](../agent-access-map/recovery.md).
## Sub-features
- `diagnosis`: a task/run exposes the recorded cause, evidence, owner, attempt
@@ -68,12 +70,12 @@ to get a failure screen. Use the existing deterministic recovery suite first.
### `source-task`
Automated: [recovery actions](../server/src/__tests__/issue-recovery-actions.test.ts)
Automated: [recovery actions](../../server/src/__tests__/issue-recovery-actions.test.ts)
covers source scoping, bounded attempts, operator stops, quota monitoring,
ownership, stale action retirement, and continuation deduplication.
[Recovery cards](../ui/src/components/IssueRecoveryActionCard.test.tsx) cover
[Recovery cards](../../ui/src/components/IssueRecoveryActionCard.test.tsx) cover
diagnosis, retry progress, exhaustion, and action availability. The fixture-backed
[execution-recovery journeys](../tests/e2e/execution-recovery/recovery.spec.ts)
[execution-recovery journeys](../../tests/e2e/execution-recovery/recovery.spec.ts)
start their own test-drive instances and exercise safe, uncertain, restart,
manager-lineage, and legacy-unknown paths:
@@ -90,7 +92,7 @@ history remains. A fixture pass does not qualify every live harness/provider.
### `run-detail`
Automated: [run workspace recovery](../ui/src/components/RunWorkspaceRecoverySurface.test.tsx)
Automated: [run workspace recovery](../../ui/src/components/RunWorkspaceRecoverySurface.test.tsx)
tests this host; it is component coverage, not an end-to-end repair.
Manual: prepare a failed run with error code `workspace_validation_failed`, a
@@ -105,10 +107,10 @@ gap.
### `operator-retry`
Automated: [disposition notices](../ui/src/components/DispositionRecoveryNotice.test.tsx)
Automated: [disposition notices](../../ui/src/components/DispositionRecoveryNotice.test.tsx)
tests pending/error/gated states and waiting for the real retry acknowledgement.
The recovery-card suite covers workspace divergence, reissue, reconcile, and
confirmation. [Workspace export](../ui/src/components/WorkspaceExportRecovery.test.tsx)
confirmation. [Workspace export](../../ui/src/components/WorkspaceExportRecovery.test.tsx)
covers its separate repair surface.
Manual: reproduce an exhausted disposable action. Click once, verify pending
@@ -120,10 +122,10 @@ action paths. A changed card label is insufficient proof of workspace integrity.
### `post-stop-message`
Automated: [legacy continuation](../server/src/services/recovery/legacy-continuation.test.ts),
[queue routes](../server/src/__tests__/issue-queued-comments-routes.test.ts), and
[native restart recovery](../server/src/services/native-runtime/native-restart-recovery.test.ts)
cover their respective recovery paths. [Legacy failure continuation](../tests/e2e/legacy-failure-continuation.spec.ts)
Automated: [legacy continuation](../../server/src/services/recovery/legacy-continuation.test.ts),
[queue routes](../../server/src/__tests__/issue-queued-comments-routes.test.ts), and
[native restart recovery](../../server/src/services/native-runtime/native-restart-recovery.test.ts)
cover their respective recovery paths. [Legacy failure continuation](../../tests/e2e/legacy-failure-continuation.spec.ts)
adds a browser journey; it is not native runtime proof.
Manual: stop a disposable run, submit a distinguishable follow-up, and observe
@@ -134,7 +136,7 @@ outcomes, inspect the provider before authorizing another operation.
### `browser-reconnect`
Automated: [live-update recovery](../ui/src/context/LiveUpdatesProvider.recovery.test.tsx)
Automated: [live-update recovery](../../ui/src/context/LiveUpdatesProvider.recovery.test.tsx)
covers client transport recovery with mocks. It does not prove runner restart.
Manual: go offline during a disposable run, let the server reach a new state,
@@ -155,5 +157,5 @@ only. Separately inspect the underlying execution if it is still stuck.
silently trigger recovery that fights the user's instruction.
- Source inspection and mocked component tests do not qualify real server
restart continuity. Use the appropriate runtime suite for that claim.
- See [execution semantics](../doc/execution-semantics.md) for the governing
- See [execution semantics](../../doc/execution-semantics.md) for the governing
recovery contract and [steering](./steering.md) for saved follow-ups.
@@ -2,7 +2,9 @@
Operators define repeatable work, configure its inputs and triggers, run it on demand or automatically, and inspect the execution history and resulting tasks.
Implementation: [routine list](../ui/src/pages/Routines.tsx), [routine detail](../ui/src/pages/RoutineDetail.tsx), [trigger editor](../ui/src/components/routine-triggers/TriggerWizard.tsx).
Implementation: [routine list](../../ui/src/pages/Routines.tsx), [routine detail](../../ui/src/pages/RoutineDetail.tsx), [trigger editor](../../ui/src/components/routine-triggers/TriggerWizard.tsx).
Agent access: [companion](../agent-access-map/routines.md).
## Sub-features
@@ -20,21 +22,27 @@ Open `/routines`, create one, and inspect `/routines/:routineId` and its edit se
### `trigger-history`
Use the routine’s trigger controls and History/Audit links; lists also offer Run now.
Use the routine's trigger controls and Runs/Recent Runs/Audit links; lists also
offer Run now. **History** records configuration versions, not executions.
## Driving it
## Driving it with Playwright and the Paperclip CLI
Preconditions: follow the [baseline](./README.md#before-driving-a-journey). Use a disposable routine, deterministic test agent, and harmless target. Record schedule timezone and enabled state.
### `routine-editor`
Automated: [routine detail helper](../ui/src/pages/RoutineDetail.test.tsx) tests project-selector options, not the rendered editor. [Routine service](../server/src/__tests__/routines-service.test.ts) covers server contracts. Saving and running through the editor remain manual checks.
Automated: [routine detail helper](../../ui/src/pages/RoutineDetail.test.tsx) tests project-selector options, not the rendered editor. [Routine service](../../server/src/__tests__/routines-service.test.ts) covers server contracts. Saving and running through the editor remain manual checks.
Manual: Save an agent, request, project, and a required variable. Reload and inspect the saved definition. Run now with a distinguishable input, follow the resulting task, and verify its output and history entry. Check a missing required input.
Variables are detected from `{{name}}` placeholders; mark a detected variable
Required and verify missing input prevents Run routine. Configuration can be
checked without model credentials. A successful subprocess run alone does not
complete the generated task or establish a useful task output.
### `trigger-history`
Automated: [trigger wizard](../ui/src/components/routine-triggers/TriggerWizard.test.tsx) is component coverage; [routine integration](../server/src/__tests__/routines-e2e.test.ts) is server integration rather than a provider-wide browser proof.
Automated: [trigger wizard](../../ui/src/components/routine-triggers/TriggerWizard.test.tsx) is component coverage; [routine integration](../../server/src/__tests__/routines-e2e.test.ts) is server integration rather than a provider-wide browser proof.
Manual: Set a near-term disposable schedule or authorized test webhook, verify one eligible execution and its source trigger, then disable it and confirm further invocations stop. Inspect a failed execution without losing its history. Remove the temporary trigger after testing.
@@ -2,7 +2,9 @@
Operators choose an agent harness and model account, inspect execution history and transcripts, and distinguish a working configuration from a successful task result.
Implementation: [adapter manager](../ui/src/pages/AdapterManager.tsx), [run host](../ui/src/pages/AgentDetail.tsx), [configuration](../ui/src/components/AgentConfigForm.tsx).
Implementation: [adapter manager](../../ui/src/pages/AdapterManager.tsx), [run host](../../ui/src/pages/AgentDetail.tsx), [configuration](../../ui/src/components/AgentConfigForm.tsx).
Agent access: [companion](../agent-access-map/runs-adapters.md).
## Sub-features
@@ -21,24 +23,28 @@ Open an agent’s model/adapter configuration or the instance adapter settings p
Open an agent run at `/agents/:agentId/runs/:runId` from the agent or task activity.
## Driving it
## Driving it with Playwright and the Paperclip CLI
Preconditions: follow the [baseline](./README.md#before-driving-a-journey). Record adapter, model, account, native/legacy runtime, and environment. Capabilities vary; one harness result is not a matrix-wide qualification.
### `adapter-setup`
Automated: [adapter validation routes](../server/src/__tests__/agent-adapter-validation-routes.test.ts) and [model refresh](../server/src/__tests__/adapter-model-refresh-routes.test.ts) cover server behavior.
Automated: [adapter validation routes](../../server/src/__tests__/agent-adapter-validation-routes.test.ts) and [model refresh](../../server/src/__tests__/adapter-model-refresh-routes.test.ts) cover server behavior.
Manual: Select the intended adapter and account, refresh model choices, and run its environment test. Save, reload, then execute a small task. Repeat with a deliberately unavailable account and verify the failure remains visible.
### `run-history`
Automated: [live run routes](../server/src/__tests__/agent-live-run-routes.test.ts) and [run event sequencing](../server/src/__tests__/heartbeat-run-event-sequencing.test.ts) cover run data contracts.
Automated: [live run routes](../../server/src/__tests__/agent-live-run-routes.test.ts) and [run event sequencing](../../server/src/__tests__/heartbeat-run-event-sequencing.test.ts) cover run data contracts.
Manual: Start a disposable task, open its running transcript, and follow it to a terminal outcome. Reload and compare task/run IDs, status, output, and cost. Verify a failed run remains distinguishable from a completed run with useful output.
## Gotchas
- Model accounts are managed in Apps and inline agent account controls.
`/company/settings/connections` configures decision/fast-response models,
not the general model-account library.
- The run log is instance database data; it is not the opt-out first-party Telemetry system or operator-configured OpenTelemetry tracing.
- Authentication/model discovery does not establish tool, image, steering, or resumption capability parity.
- Use [recovery](./recovery.md) for interrupted runs and [execution environments](./execution-environments.md) for local/SSH/sandbox differences.
@@ -2,7 +2,9 @@
Operators manage company secret references, users supply their own credentials where required, and reviewers decide proposed secret changes without exposing secret values in ordinary UI evidence.
Implementation: [secrets page](../ui/src/pages/Secrets.tsx), [personal secrets](../ui/src/pages/secrets/MyUserSecretsTab.tsx), [proposals](../ui/src/pages/secrets/ProposalsTab.tsx).
Implementation: [secrets page](../../ui/src/pages/Secrets.tsx), [personal secrets](../../ui/src/pages/secrets/MyUserSecretsTab.tsx), [proposals](../../ui/src/pages/secrets/ProposalsTab.tsx).
Agent access: [companion](../agent-access-map/secrets.md).
## Sub-features
@@ -22,24 +24,28 @@ Open company Settings → Secrets and the company/personal secret views.
Use the Proposals tab or Import from vault where available.
## Driving it
## Driving it with Playwright and the Paperclip CLI
Preconditions: follow the [baseline](./README.md#before-driving-a-journey). Use dummy credentials in an isolated company, two user identities, and a test agent. Never print actual secret values in evidence.
### `secret-management`
Automated: [secrets service](../server/src/__tests__/secrets-service.test.ts) and [user ownership](../server/src/__tests__/secrets-service-user-secret-owner-scoped.test.ts) cover storage/access contracts.
Automated: [secrets service](../../server/src/__tests__/secrets-service.test.ts) and [user ownership](../../server/src/__tests__/secrets-service-user-secret-owner-scoped.test.ts) cover storage/access contracts.
Manual: Create a dummy secret reference, bind it through a supported field, and verify its use in a harmless run without logging the value. Update it and reload. Switch users and confirm personal values remain owner-scoped and missing credentials produce an actionable state.
### `proposal-import`
Automated: [proposal routes](../server/src/__tests__/secret-proposals-routes.test.ts) and [vault import dialog](../ui/src/pages/secrets/ImportFromVaultDialog.test.tsx) cover route/UI layers; a real vault integration needs live validation.
Automated: [proposal routes](../../server/src/__tests__/secret-proposals-routes.test.ts) and [vault import dialog](../../ui/src/pages/secrets/ImportFromVaultDialog.test.tsx) cover route/UI layers; a real vault integration needs live validation.
Manual: Review a dummy proposal, reject one and accept another, then inspect the resulting reference state and history. Preview a vault import, select only disposable entries, and verify imported references and denied-access errors after reload.
## Gotchas
- Vault import currently targets eligible AWS Secrets Manager providers.
Organization-secret checks in local-trusted mode do not establish two-user
personal-secret ownership or actual external-vault import.
- A displayed reference name is not proof that the actor can resolve its value at runtime.
- Company secrets and user-specific values have different ownership.
- Redaction needs verification in errors, activity, and run logs as well as the form.
@@ -2,7 +2,9 @@
Operators discover or import skills, author and test them in Skill Studio, manage source versions, and decide which agents may use them.
Implementation: [skill library](../ui/src/pages/CompanySkills.tsx), [studio](../ui/src/pages/SkillStudio.tsx), [sources](../ui/src/pages/SkillSources.tsx), [agent skills](../ui/src/pages/agent-skills/AgentSkillsTab.tsx).
Implementation: [skill library](../../ui/src/pages/CompanySkills.tsx), [studio](../../ui/src/pages/SkillStudio.tsx), [sources](../../ui/src/pages/SkillSources.tsx), [agent skills](../../ui/src/pages/agent-skills/AgentSkillsTab.tsx).
Agent access: [companion](../agent-access-map/skills.md).
## Sub-features
@@ -21,35 +23,41 @@ Open `/skills`, Discover, or `/skills/sources`; project import is available thro
### `studio`
Use New skill or `/skills/studio/:skillId`; writable copies and source-backed originals differ.
Direct authoring starts at `/skills/studio/new`: fill **Name** and **Slug**, then
**Create skill**. Authoring/save/reload requires no model credential; running a
Studio test is separate.
### `agent-enablement`
Use skill policy/agent selection in the library or an agent’s Skills tab.
## Driving it
## Driving it with Playwright and the Paperclip CLI
Preconditions: follow the [baseline](./README.md#before-driving-a-journey). Use a harmless skill fixture and test agent with skill support. Record whether the source is local, bundled, project, or remote.
### `library-sources`
Automated: [library UI](../ui/src/pages/CompanySkills.test.tsx) and [source service](../server/src/__tests__/skill-sources.test.ts) cover their respective layers.
Automated: [library UI](../../ui/src/pages/CompanySkills.test.tsx) and [source service](../../server/src/__tests__/skill-sources.test.ts) cover their respective layers.
Manual: Install a fixture, locate it in Installed, inspect its source and files, and reload. Import a source update and compare versions before accepting it. Check a source requiring unavailable repository access and verify the failure is explicit.
### `studio`
Automated: [Studio](../ui/src/pages/SkillStudio.test.tsx) covers UI behavior; model-driven skill testing remains a separate manual result.
Automated: [Studio](../../ui/src/pages/SkillStudio.test.tsx) covers UI behavior; model-driven skill testing remains a separate manual result.
Manual: Create or fork a disposable skill, edit instructions, save, and reload. Run a bounded test, respond to any question, and inspect the output. Verify the saved version matches what was tested and failed saves retain the draft.
### `agent-enablement`
Automated: [policy service](../server/src/__tests__/company-skill-policy-service.test.ts) and [agent skills state](../ui/src/pages/agent-skills/AgentSkillsTab.test.ts) cover policy/state contracts.
Automated: [policy service](../../server/src/__tests__/company-skill-policy-service.test.ts) and [agent skills state](../../ui/src/pages/agent-skills/AgentSkillsTab.test.ts) cover policy/state contracts.
Manual: Enable the skill for one test agent and leave another without access. Run a small task on each, inspect the available skill context, then change the release/policy and verify the next eligible run uses the intended version.
## Gotchas
- The release picker requires `enableBetaSkills`. Do not invent an Instructions
accessibility label for the Studio body editor; inspect its current handles.
- Installed does not mean enabled for every agent.
- Read-only GitHub/bundled skills may require a writable copy rather than an in-place edit.
- Studio interaction coverage is in [questions and approvals](./questions-and-approvals.md); a passing mock is not a live harness test.
@@ -2,7 +2,9 @@
The status-card experiment turns a saved prompt/query into an inspectable summary of watched work, with refresh history, configuration, and archive/restore controls.
Implementation: [status page](../ui/src/pages/StatusCards/index.tsx), [card detail](../ui/src/pages/StatusCards/StatusCardDetailDrawer.tsx).
Implementation: [status page](../../ui/src/pages/StatusCards/index.tsx), [card detail](../../ui/src/pages/StatusCards/StatusCardDetailDrawer.tsx).
Agent access: [companion](../agent-access-map/status-cards.md).
## Sub-features
@@ -27,13 +29,13 @@ Preconditions: follow the [baseline](./README.md#before-driving-a-journey). Enab
### `status-board`
Automated: [status-card service/routes](../server/src/__tests__/status-cards.test.ts) covers gated lifecycle and generation contracts; [tile UI](../ui/src/pages/StatusCards/StatusCardTile.test.tsx) covers rendering.
Automated: [status-card service/routes](../../server/src/__tests__/status-cards.test.ts) covers gated lifecycle and generation contracts; [tile UI](../../ui/src/pages/StatusCards/StatusCardTile.test.tsx) covers rendering.
Manual: Create a bounded card, inspect its generation task, and wait for a saved summary. Change a watched task, refresh, and verify both the summary and update history reflect the source change. Exercise a failed generation and confirm it is not presented as fresh.
### `card-settings`
Automated: [settings form](../ui/src/pages/StatusCards/StatusCardSettingsForm.test.tsx) and [update engine](../server/src/__tests__/status-card-update-engine.test.ts) cover separate UI/engine layers.
Automated: [settings form](../../ui/src/pages/StatusCards/StatusCardSettingsForm.test.tsx) and [update engine](../../server/src/__tests__/status-card-update-engine.test.ts) cover separate UI/engine layers.
Manual: Change a disposable card’s prompt or summarizer, run the offered rebuild/refresh, and inspect the resulting query and summary. Archive and restore it, reload its direct link, and check the actual new generation outcome.
@@ -5,6 +5,8 @@ not been consumed, and choose when to steer or interrupt. Stopping a run and
pausing a task are separate controls. The UI must preserve the message, explain
why it is waiting, and only claim delivery after an authoritative acknowledgement.
Agent access: [companion](../agent-access-map/steering.md).
## Sub-features
- `queue`: a busy task saves follow-ups and shows their order and wait reason.
@@ -57,11 +59,11 @@ unsupported steering without treating an absent capability as a product failure.
### `task-composer`
Automated: [queued-message UI](../ui/src/components/task-chat/TaskChatQueuedMessages.test.tsx)
Automated: [queued-message UI](../../ui/src/components/task-chat/TaskChatQueuedMessages.test.tsx)
covers order, failure restoration, unavailable steering, stale revisions, and
discard acknowledgements. [Queue routes](../server/src/__tests__/issue-queued-comments-routes.test.ts)
discard acknowledgements. [Queue routes](../../server/src/__tests__/issue-queued-comments-routes.test.ts)
cover durable ordering, authorization, steering acknowledgements, interrupt
recovery, and concurrent dispatch. [Composer](../ui/src/components/task-chat/TaskChatComposer.test.tsx)
recovery, and concurrent dispatch. [Composer](../../ui/src/components/task-chat/TaskChatComposer.test.tsx)
covers drafts and uncertain saves.
```sh
@@ -69,9 +71,9 @@ pnpm exec vitest run ui/src/components/task-chat/TaskChatQueuedMessages.test.tsx
```
Automated stop coverage is separate:
[composer stop](../tests/e2e/composer-stop.spec.ts) with
[its configuration](../tests/e2e/playwright-composer-stop.config.ts) and
[ACP stop/continuation](../tests/e2e/acp-stop-continuation.spec.ts). Inspect their
[composer stop](../../tests/e2e/composer-stop.spec.ts) with
[its configuration](../../tests/e2e/playwright-composer-stop.config.ts) and
[ACP stop/continuation](../../tests/e2e/acp-stop-continuation.spec.ts). Inspect their
fixture and opt-in prerequisites; skipped native cases are not native proof.
Manual: queue three distinguishable messages. Edit one, reorder them, reload,
@@ -86,7 +88,7 @@ when available; the named component tests do not prove every host integration.
### `agent-chat`
Automated: [agent chat sessions](../tests/e2e/agent-chat-sessions.spec.ts) covers
Automated: [agent chat sessions](../../tests/e2e/agent-chat-sessions.spec.ts) covers
persistent conversation/session behavior with deterministic harness fixtures;
shared composer tests cover the controls. These do not qualify live steering
for every harness.
@@ -100,7 +102,7 @@ when the change touches delivery.
### `request-response`
Automated: [response delivery](../server/src/__tests__/question-response-delivery.test.ts)
Automated: [response delivery](../../server/src/__tests__/question-response-delivery.test.ts)
proves queueing/coalescing and retry-safe receipts. The queue-route suite tests
separate comment and approval queues, explicit steering, and fresh-session
restrictions on plan approvals.
@@ -113,7 +115,7 @@ approval outcome through an ordinary queued-message editor.
### `external-channel`
Automated: [chat interaction arbitration](../server/src/services/chat-interaction-arbitration.test.ts)
Automated: [chat interaction arbitration](../../server/src/services/chat-interaction-arbitration.test.ts)
covers backend arbitration with simulated requests. It is not a provider UI test.
Manual: send two distinguishable messages through one disposable linked
@@ -2,7 +2,9 @@
A larger task can coordinate child work, dependencies, reviewers, and execution controls while preserving a clear owner and a traceable completion decision.
Implementation: [task thread](../ui/src/pages/IssueDetail.tsx), [execution policy](../server/src/services/issues.ts).
Implementation: [task thread](../../ui/src/pages/IssueDetail.tsx), [execution policy](../../server/src/services/issues.ts).
Agent access: [companion](../agent-access-map/task-coordination.md).
## Sub-features
@@ -21,19 +23,23 @@ Open the task’s parent/child and dependency links in task detail.
Inspect the task’s execution policy and available review, pause, resume, or stop controls.
## Driving it
## Driving it with Playwright and the Paperclip API
Preconditions: follow the [baseline](./README.md#before-driving-a-journey). Prepare a parent, child, and dependent task plus implementer/reviewer agents. Record execution policy and use a disposable tree.
Parent/dependency navigation and inherited tree holds can be checked on unassigned
tasks. Agents are required for the continuation and signoff portion. A tree pause
creates a hold; it does not change task statuses to a paused status.
### `task-relationships`
Automated: [dependency wakeups](../server/src/__tests__/issue-dependency-wakeups-routes.test.ts) checks server behavior; visual relationship navigation remains a manual check.
Automated: [dependency wakeups](../../server/src/__tests__/issue-dependency-wakeups-routes.test.ts) checks server behavior; visual relationship navigation remains a manual check.
Manual: Block one task on another, finish the prerequisite, and observe the dependent task’s eligible continuation. Follow parent/child links back to the source request. Verify no duplicate run or false parent completion occurs.
### `review-and-controls`
Automated: [execution policy](../server/src/__tests__/issue-execution-policy.test.ts), [tree control](../server/src/__tests__/issue-tree-control-service.test.ts), and [signoff browser suite](../tests/e2e/signoff-policy.spec.ts) target these layers. A linked suite is not a claim that its current run is green.
Automated: [execution policy](../../server/src/__tests__/issue-execution-policy.test.ts), [tree control](../../server/src/__tests__/issue-tree-control-service.test.ts), and [signoff browser suite](../../tests/e2e/signoff-policy.spec.ts) target these layers. A linked suite is not a claim that its current run is green.
Manual: Complete implementation under a review-required policy and confirm it waits for the required review outcome. Exercise rejection and later approval. Pause the parent while child work is pending, then verify resumption respects budget and ownership gates.
@@ -2,7 +2,9 @@
People create, assign, organize, discuss, and finish tasks. A task retains its owner, project, priority, history, and outputs as it moves through the work lifecycle.
Implementation: [new task](../ui/src/components/NewIssueDialog.tsx), [task list](../ui/src/pages/Issues.tsx), [task detail](../ui/src/pages/IssueDetail.tsx).
Implementation: [new task](../../ui/src/components/NewIssueDialog.tsx), [task list](../../ui/src/pages/Issues.tsx), [task detail](../../ui/src/pages/IssueDetail.tsx).
Agent access: [companion](../agent-access-map/tasks.md).
## Sub-features
@@ -26,30 +28,39 @@ Open `/issues` or a project’s Issues view; legacy `/tasks` links redirect.
Open `/issues/:issueId` from a row, mention, or direct link.
## Driving it
## Driving it with Playwright and the Paperclip CLI
Preconditions: follow the [baseline](./README.md#before-driving-a-journey). Use an invokable test agent and a project; record whether a real or simulated harness handles the request.
Preconditions: follow the [baseline](./README.md#before-driving-a-journey). Use a
disposable project. Persistence checks can assign work to Me or leave it
unassigned; execution checks additionally need an invokable test agent. Record
whether a real or simulated harness handles execution.
### `new-task`
Automated: [creation dialog](../ui/src/components/NewIssueDialog.test.tsx) is component coverage with mocked requests.
Automated: [creation dialog](../../ui/src/components/NewIssueDialog.test.tsx) is component coverage with mocked requests.
Manual: Create a uniquely named task with an agent and project. Open its resulting link and reload. Confirm text, attachment, assignment, and project persisted, and verify execution started only when the task and agent are eligible.
Creation is request-first: enter **Describe a task…**, choose the assignee and
project, and submit **Create task**. A standalone title field is not always shown.
Use a human/unassigned task to verify persistence without invoking a model.
### `task-list`
Automated: [task-list helpers](../ui/src/pages/Issues.test.tsx) cover search URLs, pagination, deduplication, and presentation constants. The suite does not render the page or exercise filtering, grouping, opening a task, and returning; those interactions still need a running-browser check.
Automated: [task-list helpers](../../ui/src/pages/Issues.test.tsx) cover search URLs, pagination, deduplication, and presentation constants. The suite does not render the page or exercise filtering, grouping, opening a task, and returning; those interactions still need a running-browser check.
Manual: Filter by status and assignee, change grouping/sort, open a task, and return. Verify the correct records and selected view survive navigation and reload. Include an empty result and a failed request.
### `task-detail`
Automated: [task detail](../ui/src/pages/IssueDetail.test.tsx) covers component behavior, while [issue service](../server/src/__tests__/issues-service.test.ts) covers server contracts.
Automated: [task detail](../../ui/src/pages/IssueDetail.test.tsx) covers component behavior, while [issue service](../../server/src/__tests__/issues-service.test.ts) covers server contracts.
Manual: Add a comment and edit authorized properties. Reload and verify history, actor, and values. Complete a disposable task and inspect its deliverable; reopen through an available action and confirm the next execution follows current policy.
## Gotchas
- Priority remains an API field, but ordinary priority UI editing is hidden.
- A status label alone does not prove that the requested work exists.
- Single-assignee and atomic checkout rules still apply when tasks are created from different hosts.
- Use [coordination](./task-coordination.md), [steering](./steering.md), and [documents](./documents-artifacts.md) for their distinct workflows.
@@ -2,7 +2,9 @@
Operators can preview and install a team package with its agents and related resources. Catalog/package installation is available through the CLI/API; the repository also contains catalog UI components that are not a current top-level route.
Implementation: [CLI teams](../cli/src/commands/client/teams.ts), [catalog components](../ui/src/pages/TeamCatalog.tsx).
Implementation: [CLI teams](../../cli/src/commands/client/teams.ts), [catalog components](../../ui/src/pages/TeamCatalog.tsx).
Agent access: [companion](../agent-access-map/teams.md).
## Sub-features
@@ -21,24 +23,28 @@ Use the CLI teams catalog/preview/install operations in the selected context.
The catalog components and install wizard are available in developer tests/design surfaces. No top-level `/teams` route is registered; use the CLI/API for the current installation workflow.
## Driving it
## Driving it with the Paperclip CLI
Preconditions: follow the [baseline](./README.md#before-driving-a-journey). Use a disposable company, a small catalog entry, and explicit company context. Check `paperclipai teams --help` for current subcommands.
### `catalog-cli`
Automated: [team commands](../cli/src/__tests__/teams.test.ts) and [catalog service](../server/src/__tests__/teams-catalog-service.test.ts) cover command and service contracts.
Automated: [team commands](../../cli/src/__tests__/teams.test.ts) and [catalog service](../../server/src/__tests__/teams-catalog-service.test.ts) cover command and service contracts.
Manual: List an entry, preview its proposed agents and resources, install it into the disposable company, and inspect each created resource. Run a small task after configuring accounts. Retry preview/install as supported and inspect duplicate/conflict behavior.
### `catalog-components`
Automated: [catalog component](../ui/src/pages/TeamCatalog.test.tsx) and [install hook](../ui/src/pages/useInstallTeamCatalogEntry.test.tsx) cover preview and install UI logic with mocks.
Automated: [catalog component](../../ui/src/pages/TeamCatalog.test.tsx) and [install hook](../../ui/src/pages/useInstallTeamCatalogEntry.test.tsx) cover preview and install UI logic with mocks.
Manual: When changing or mounting these components, exercise preview, manager/source options, cancellation, failed install, and success. Follow created agents in the actual company. Record whether this was a component harness or a real product entry point.
## Gotchas
- Catalog preview records an audit event but installs no agents/projects. Use
`teams browse/inspect/preview` with explicit company and origin API context;
the current product has no `/teams` route.
- Source files do not prove that a screen is reachable in the current app.
- Installed team configuration may still need credentials or environment setup.
- Company package import is a separate [portability](./companies.md) workflow.
@@ -2,7 +2,9 @@
A project or task can use a managed workspace with inspectable files, Git state, services, and runtime controls. Operators can follow its lifecycle through provisioning, use, and closure.
Implementation: [workspace list](../ui/src/pages/Workspaces.tsx), [execution workspace](../ui/src/pages/ExecutionWorkspaceDetail.tsx), [project workspace](../ui/src/pages/ProjectWorkspaceDetail.tsx).
Implementation: [workspace list](../../ui/src/pages/Workspaces.tsx), [execution workspace](../../ui/src/pages/ExecutionWorkspaceDetail.tsx), [project workspace](../../ui/src/pages/ProjectWorkspaceDetail.tsx).
Agent access: [companion](../agent-access-map/workspaces.md).
## Sub-features
@@ -22,24 +24,29 @@ Use the task’s workspace card or Files panel and follow its workspace link.
Open `/workspaces`, a project workspace, or `/execution-workspaces/:workspaceId` and its Services/Configuration/Runtime logs views.
## Driving it
## Driving it with Playwright and the Paperclip CLI
Preconditions: follow the [baseline](./README.md#before-driving-a-journey). Enable isolated-workspace UI where needed. Use an owned disposable repository and environment; record workspace ID and branch.
### `task-workspace`
Automated: [workspace card](../ui/src/components/IssueWorkspaceCard.test.tsx) and [task binding](../server/src/__tests__/issue-runtime-workspace-binding.test.ts) cover host/binding contracts.
Automated: [workspace card](../../ui/src/components/IssueWorkspaceCard.test.tsx) and [task binding](../../server/src/__tests__/issue-runtime-workspace-binding.test.ts) cover host/binding contracts.
Manual: Run a task that writes a small file, follow the bound workspace, and inspect the file and revision. Reload and verify links still refer to the same workspace, not another checkout or a stale run.
### `workspace-management`
Automated: [workspace detail](../ui/src/pages/ExecutionWorkspaceDetail.test.tsx) and [runtime service](../server/src/__tests__/workspace-runtime.test.ts) cover UI and runtime contracts separately.
Automated: [workspace detail](../../ui/src/pages/ExecutionWorkspaceDetail.test.tsx) and [runtime service](../../server/src/__tests__/workspace-runtime.test.ts) cover UI and runtime contracts separately.
Manual: Provision a disposable workspace, wait for readiness, start an available service, open its endpoint, and inspect a real response and logs. Stop it and verify it actually stops. Exercise close/reopen only after inspecting pending changes and active runs.
## Gotchas
- UI visibility, default isolation policy, the local environment row, a workspace
record, and a running service are distinct prerequisites. A fresh instance
still needs an owned cwd/repository and runtime commands; `/workspaces` lists
existing work. Reopening depends on lifecycle, not a generic detail action.
- A link or running badge does not prove the service is reachable from the user’s browser.
- Workspace IDs, runtime leases, and repository paths are not interchangeable.
- Use [recovery](./recovery.md) for divergence/export repair and [CLI operations](./cli-operations.md) for local worktree tooling.
@@ -26,6 +26,13 @@ export const ACPX_HANDSHAKE_TRANSPORT_POLL_MS = 250;
// much smaller than the whole-adapter execution timeout.
export const ACPX_DUPLEX_LOSS_CANCEL_DEADLINE_MS = 30_000;
// The closed ACP `ToolKind` enum. Run diagnostics may report these labels for
// pending tool calls; tool titles, names, and inputs never leave the run.
// Any other reported kind is collapsed to "unknown".
export const ACP_TOOL_KINDS = [
"read", "edit", "delete", "move", "search", "execute", "think", "fetch", "switch_mode", "other",
] as const;
export const ACPX_ADAPTER_AGENT_IDS = {
claude_local: "claude",
codex_local: "codex",
@@ -33,6 +33,7 @@ import {
parseGeminiVersionParts,
referencedSourceContentSignature,
rewriteGeminiAcpFlagForVersion,
summarizeAcpStopActivity,
summarizeAcpxTurnUsage,
type AcpxEngineExecutorOptions,
} from "./execute.js";
@@ -3400,6 +3401,118 @@ describe("ACP activity diagnostics", () => {
expect(currentNow).toBeGreaterThan(10_000);
},
);
it("snapshots a silent turn's activity when the wall-clock timeout fires, before cancel events", async () => {
const root = await makeTempRoot();
const cwd = path.join(root, "worktree");
await fs.mkdir(cwd, { recursive: true });
let currentNow = 1000;
let releaseTurn: (() => void) | null = null;
const turnCancelled = new Promise<void>((resolve) => { releaseTurn = resolve; });
const execute = createAcpxEngineExecutor({
now: () => currentNow,
createRuntime: () => ({
...buildRuntime(),
startTurn: () => ({
events: (async function* () {
yield { type: "tool_call", toolCallId: "private-id", title: "private command", kind: "execute", status: "in_progress" };
// The agent goes silent with the tool still pending.
currentNow = 9000;
await turnCancelled;
// The cancel makes the agent emit a closing event, so the
// finalize-time age alone would make this turn look active.
currentNow = 9500;
yield { type: "status", text: "private closing status" };
})(),
result: turnCancelled.then(() => ({ status: "cancelled", stopReason: "cancelled" })),
cancel: async () => { releaseTurn?.(); },
}),
}) as never,
});
const result = await execute({
runId: "silent-timeout", agent: { id: "agent-1", companyId: "company-1" }, runtime: {},
config: { agent: "custom", agentCommand: "node ./fake-acp.js", stateDir: path.join(root, "state"), cwd, timeoutSec: 1 },
context: {}, onMeta: async () => {}, onLog: async () => {},
} as never);
expect(result.timedOut).toBe(true);
expect(result.resultJson).toMatchObject({
acpObservedEventCount: 2,
acpLastEventAgeMs: 0,
acpPendingToolCount: 1,
acpLastEventAgeAtStopMs: 8000,
acpOldestPendingToolAgeAtStopMs: 8000,
acpPendingToolKinds: "execute",
});
const diagnostics = Object.fromEntries(Object.entries(result.resultJson ?? {}).filter(([key]) => key.startsWith("acp")));
expect(JSON.stringify(diagnostics)).not.toContain("private");
}, 15_000);
it("keeps the stalled tool's stop-time age when the cancel closes that tool", async () => {
const root = await makeTempRoot();
const cwd = path.join(root, "worktree");
await fs.mkdir(cwd, { recursive: true });
let currentNow = 1000;
let releaseTurn: (() => void) | null = null;
const turnCancelled = new Promise<void>((resolve) => { releaseTurn = resolve; });
const execute = createAcpxEngineExecutor({
now: () => currentNow,
createRuntime: () => ({
...buildRuntime(),
startTurn: () => ({
events: (async function* () {
yield { type: "tool_call", toolCallId: "private-id", title: "private command", kind: "execute", status: "in_progress" };
currentNow = 9000;
await turnCancelled;
// The cancel closes the stalled tool before finalization runs.
currentNow = 9500;
yield { type: "tool_call", tag: "tool_call_update", toolCallId: "private-id", status: "cancelled" };
})(),
result: turnCancelled.then(() => ({ status: "cancelled", stopReason: "cancelled" })),
cancel: async () => { releaseTurn?.(); },
}),
}) as never,
});
const result = await execute({
runId: "cancel-closes-tool", agent: { id: "agent-1", companyId: "company-1" }, runtime: {},
config: { agent: "custom", agentCommand: "node ./fake-acp.js", stateDir: path.join(root, "state"), cwd, timeoutSec: 1 },
context: {}, onMeta: async () => {}, onLog: async () => {},
} as never);
expect(result.timedOut).toBe(true);
expect(result.resultJson).toMatchObject({
acpPendingToolCount: 0,
acpLastEventAgeAtStopMs: 8000,
acpOldestPendingToolAgeAtStopMs: 8000,
acpPendingToolKinds: "execute",
});
const diagnostics = Object.fromEntries(Object.entries(result.resultJson ?? {}).filter(([key]) => key.startsWith("acp")));
expect(JSON.stringify(diagnostics)).not.toContain("private");
}, 15_000);
});
describe("summarizeAcpStopActivity", () => {
it("reports nothing for an unstopped turn with no pending tools", () => {
expect(summarizeAcpStopActivity(null, 1000, [])).toEqual({});
});
it("reports pending kinds without a stop, and collapses unknown kinds", () => {
expect(summarizeAcpStopActivity(null, 1000, [
{ kind: "fetch", firstSeenAt: 10 }, { kind: "private_tool_name" }, {}, { kind: "fetch" },
])).toEqual({ acpPendingToolKinds: "fetch,unknown" });
});
it("measures ages from the stop and ignores tools first seen after it", () => {
expect(summarizeAcpStopActivity(10_000, 4000, [
{ kind: "execute", firstSeenAt: 3000 }, { kind: "read", firstSeenAt: 12_000 },
])).toEqual({
acpLastEventAgeAtStopMs: 6000,
acpOldestPendingToolAgeAtStopMs: 7000,
acpPendingToolKinds: "execute,read",
});
});
it("omits the event age when no event preceded the stop", () => {
expect(summarizeAcpStopActivity(10_000, null, [])).toEqual({});
});
});
describe("summarizeAcpxTurnUsage", () => {
@@ -105,6 +105,7 @@ import {
type AcpRuntimeUsageCost,
} from "acpx/runtime";
import {
ACP_TOOL_KINDS,
ACPX_DUPLEX_LOSS_CANCEL_DEADLINE_MS,
ACPX_HANDSHAKE_TIMEOUT_MS,
ACPX_HANDSHAKE_TRANSPORT_POLL_MS,
@@ -3249,6 +3250,46 @@ async function emitRuntimeEvent(
}
}
function isPendingAcpTool(tool: { status?: string }): boolean {
return tool.status !== "completed" && tool.status !== "failed" && tool.status !== "cancelled";
}
/**
* Activity as of the moment the turn's stop fired, for a stopped turn only.
* Separates a turn that went silent long before its deadline from one that
* was still working. Reports only ages and closed ACP tool-kind labels.
*/
export function summarizeAcpStopActivity(
stopRequestedAt: number | null,
lastEventBeforeStopAt: number | null,
pendingTools: ReadonlyArray<{ kind?: string; firstSeenAt?: number }>,
): { acpLastEventAgeAtStopMs?: number; acpOldestPendingToolAgeAtStopMs?: number; acpPendingToolKinds?: string } {
const summary: ReturnType<typeof summarizeAcpStopActivity> = {};
if (pendingTools.length > 0) {
const knownKinds: readonly string[] = ACP_TOOL_KINDS;
summary.acpPendingToolKinds = uniqueSorted(
pendingTools.map((tool) => (tool.kind && knownKinds.includes(tool.kind) ? tool.kind : "unknown")),
).join(",");
}
if (stopRequestedAt === null) return summary;
const age = (since: number) => {
const value = stopRequestedAt - since;
return Number.isSafeInteger(value) && value >= 0 ? value : undefined;
};
if (lastEventBeforeStopAt !== null) {
const value = age(lastEventBeforeStopAt);
if (value !== undefined) summary.acpLastEventAgeAtStopMs = value;
}
const pendingSince = pendingTools
.map((tool) => tool.firstSeenAt)
.filter((at): at is number => typeof at === "number" && at <= stopRequestedAt);
if (pendingSince.length > 0) {
const value = age(Math.min(...pendingSince));
if (value !== undefined) summary.acpOldestPendingToolAgeAtStopMs = value;
}
return summary;
}
function resultErrorMessage(result: AcpRuntimeTurnResult): string | null {
if (result.status !== "failed") return null;
return result.error.message;
@@ -4046,7 +4087,7 @@ export function createAcpxEngineExecutor(deps: AcpxEngineExecutorOptions = {}) {
let runtimeStopConfirmed = false;
let safeInterruptedSession = false;
let preserveInterruptedSession = false;
const interruptionTools = new Map<string, { kind?: string; status?: string }>();
const interruptionTools = new Map<string, { kind?: string; status?: string; firstSeenAt?: number }>();
let incompleteToolInventory = false;
try {
await ctx.onCancellationReady?.();
@@ -4759,6 +4800,14 @@ export function createAcpxEngineExecutor(deps: AcpxEngineExecutorOptions = {}) {
let observedUsage: Pick<AdapterExecutionResult, "usage" | "usageBasis" | "costUsd" | "usageComplete"> = { usageComplete: false };
let lastRuntimeEventAt: number | null = null;
let observedRuntimeEvents = 0;
// Activity as of the moment the turn's stop (wall-clock timeout or
// operator stop) fired. The cancel can make the agent emit closing
// events (including updates that close the stalled tool), so the
// finalize-time age and pending set alone cannot tell a silent stall
// from live work.
let turnStopRequestedAt: number | null = null;
let lastRuntimeEventBeforeStopAt: number | null = null;
let pendingToolsAtStop: Array<{ kind?: string; firstSeenAt?: number }> | null = null;
let turnDispatchAttempted = false;
// The turn-local state the sequence steps share. `promptBuild` sets the
// prompt, `preTurnUsage` sets the pre-turn status, `turnStart` sets the
@@ -4846,6 +4895,11 @@ export function createAcpxEngineExecutor(deps: AcpxEngineExecutorOptions = {}) {
};
const stepTurnStart = (signal: AbortSignal, startTimeoutMs: number | undefined): StartedTurn => {
ctx.signal?.throwIfAborted();
signal.addEventListener("abort", () => {
if (turnStopRequestedAt !== null) return;
turnStopRequestedAt = now();
pendingToolsAtStop = [...interruptionTools.values()].filter(isPendingAcpTool);
}, { once: true });
// After entering startTurn, a thrown error cannot prove the provider
// received no work. Only failures before this boundary are free to settle.
turnDispatchAttempted = true;
@@ -4939,6 +4993,7 @@ export function createAcpxEngineExecutor(deps: AcpxEngineExecutorOptions = {}) {
const drainEvents = (async (): Promise<void> => {
for await (const event of turn.events) {
lastRuntimeEventAt = now();
if (turnStopRequestedAt === null) lastRuntimeEventBeforeStopAt = lastRuntimeEventAt;
observedRuntimeEvents += 1;
// ACPX currently flattens client-side filesystem/terminal receipts
// into status text. They cannot establish complete action outcomes.
@@ -4950,6 +5005,7 @@ export function createAcpxEngineExecutor(deps: AcpxEngineExecutorOptions = {}) {
interruptionTools.set(event.toolCallId, {
kind: event.kind ?? previous?.kind,
status: event.status ?? previous?.status,
firstSeenAt: previous?.firstSeenAt ?? lastRuntimeEventAt,
});
}
}
@@ -5004,14 +5060,14 @@ export function createAcpxEngineExecutor(deps: AcpxEngineExecutorOptions = {}) {
// Capture runtime activity before usage reads, error logs, or cleanup
// make an otherwise silent turn look active at its execution deadline.
const lastEventAgeMs = lastRuntimeEventAt === null ? undefined : now() - lastRuntimeEventAt;
const pendingTools = [...interruptionTools.values()].filter(isPendingAcpTool);
const activityDiagnostics = {
acpObservedEventCount: observedRuntimeEvents,
...(lastEventAgeMs !== undefined && Number.isSafeInteger(lastEventAgeMs) && lastEventAgeMs >= 0
? { acpLastEventAgeMs: lastEventAgeMs } : {}),
acpPendingToolCount: [...interruptionTools.values()].filter(
(tool) => tool.status !== "completed" && tool.status !== "failed" && tool.status !== "cancelled",
).length,
acpPendingToolCount: pendingTools.length,
acpToolInventoryComplete: !incompleteToolInventory,
...summarizeAcpStopActivity(turnStopRequestedAt, lastRuntimeEventBeforeStopAt, pendingToolsAtStop ?? pendingTools),
};
if (input.kind === "terminal") {
const terminal = input.terminal;
@@ -0,0 +1,71 @@
import { mkdtemp, rm } from "node:fs/promises";
import os from "node:os";
import path from "node:path";
import { afterEach, describe, expect, it, vi } from "vitest";
vi.mock("node:child_process", async (importOriginal) => {
const actual = await importOriginal<typeof import("node:child_process")>();
// Execute the authored remote command locally, through both subprocess paths.
return {
...actual,
execFile: vi.fn((file: string, args: string[], options: object, callback: Parameters<typeof actual.execFile>[3]) => {
if (file !== "ssh") throw new Error(`Unexpected subprocess ${file}`);
return actual.execFile("sh", ["-c", args.at(-1)!], options, callback);
}),
spawn: vi.fn((file: string, args: string[], options: Parameters<typeof actual.spawn>[2]) => {
if (file !== "ssh") throw new Error(`Unexpected subprocess ${file}`);
return actual.spawn("sh", ["-c", args.at(-1)!], options);
}),
};
});
import { createSshCommandManagedRuntimeRunner } from "./ssh.js";
const roots: string[] = [];
afterEach(async () => {
for (const root of roots.splice(0)) await rm(root, { recursive: true, force: true });
});
async function runner() {
const cwd = await mkdtemp(path.join(os.tmpdir(), "ssh-managed-argv-"));
roots.push(cwd);
return createSshCommandManagedRuntimeRunner({
spec: {
host: "fixture.invalid", username: "fixture", port: 22,
remoteCwd: cwd, remoteWorkspacePath: cwd,
privateKey: null, knownHosts: null, strictHostKeyChecking: true,
},
});
}
describe("SSH command-managed argv", () => {
it("rejects environment keys that could be interpreted as env options", async () => {
await expect((await runner()).execute({ command: "true", env: { "-u": "PATH" } }))
.rejects.toThrow("Invalid SSH environment variable key");
});
it.each([[false, false], [true, false], [false, true], [true, true]])(
"preserves shell positional arguments with environment=%s and stdin=%s",
async (withEnvironment, withStdin) => {
const value = "literal 'quote' $(printf unsafe) `printf unsafe`";
const result = await (await runner()).execute({
command: "sh",
args: ["-c", 'set -eu; printf "%s\\n" "$0" "$1" "$2" "${SENTINEL_TEXT-unset}"', "named-probe", "two words", value],
...(withEnvironment ? { env: { SENTINEL_TEXT: value } } : {}),
...(withStdin ? { stdin: "" } : {}),
timeoutMs: 5000,
});
expect(result.exitCode).toBe(0);
expect(result.stdout).toBe(["named-probe", "two words", value, withEnvironment ? value : "unset"].join("\n") + "\n");
},
);
it("applies environment to a non-shell command", async () => {
const result = await (await runner()).execute({
command: "printenv", args: ["SENTINEL_TEXT"],
env: { SENTINEL_TEXT: "two words" }, timeoutMs: 5000,
});
expect(result.exitCode).toBe(0);
expect(result.stdout).toBe("two words\n");
});
});
Loaded 100 of 120 files, more files were not shown because too many files have changed in this diff. Show more