Reconcile Claude platform packages with merged Codex defaults

Co-Authored-By: Paperclip <noreply@paperclip.ing>

* codex/claude-runner-default: (85 commits)
  feat: default new Codex agents to Paperclip Runner on Linux and macOS (#15683)
  docs(skills): add slow-query diagnosis and fix skill (#16303)
  feat(sentry): add opt-in run failure reporting with saved run references (#16300)
  refactor(server): isolate provider message admission and runtime policies (#16289)
  refactor(server): isolate provider webhook lifecycle decisions (#16283)
  fix(workspaces): keep cleanup Git scans fresh and dedupe page reads (#16302)
  fix(sentry): keep provider-rejected Grok wakes out of run failure reports (#16297)
  fix(runner): report Runner disconnect age when a Dot bridge exits (#16296)
  refactor(server): isolate chat conversation and control policies (#16276)
  perf(recovery): use indexed execution identity lookups (#16291)
  perf(runs): bound history and reduce repeated context reads (#16286)
  fix(native-runtime): report which close barrier failed (#16298)
  feat(skills): select and validate tracked GitHub branches (#16288)
  fix(observability): sample native runs independently of triggers (#16285)
  fix(github): retry and recover review publication (#16284)
  perf(workspaces): wake terminal cleanup from committed changes (#16282)
  fix(mcp): deduplicate discovered tool descriptors (#16281)
  perf: remove history scans from task and chat queries (#16278)
  docs(skills): add maintenance bot setup workflow (#16279)
  fix(observability): time execution configuration steps (#16236)
  ...

# Conflicts:
#	scripts/verify-grok-npm-install.mjs
This commit is contained in:
Dotta committed 2026-10-14 12:12:58 -05:00
commit b030683ca2
1176 files changed
+129461 -261897

No files matched your search

@@ -0,0 +1,152 @@
---
name: create-external-bot-integration
description: >-
Build and qualify external bots such as Dot in Paperclip. Use for two-way work,
invitation, identity, wakeup, Runner lifecycle, native tools, recovery, and
Cloud delivery. CLI adapters and app-only connectors use their existing skills.
---
# Create an External Bot Integration
Make an existing external agent a useful Paperclip participant: Paperclip can
assign work to it, and it can initiate governed work from its own conversation.
It uses its relevant native capabilities, returns inspectable results to
Paperclip, and participates in normal admission, authority, and finalization.
This workflow incorporates the September 30–October 9, 2026 Dot integration.
Provider facts and code paths in the references are dated evidence, not a claim
that every future bot supports the same APIs. Verify the current implementation
and official provider documentation before choosing a transport or changing code.
## 1. Establish the release contract before narrowing the implementation
Read [release-contract.md](references/release-contract.md). Infer already-stated
requirements and authorization from the conversation. Ask only about consequential
unknowns; do not ask the user to repeat “two way,” Cloud, or use of Runner.
Record the target environment, acting identity, capabilities, allowed human setup
steps, delivery/stop expectations, and checkable finish line. Keep one compact
matrix in the existing plan or task. Follow repository conventions if creating a
plan file. “Works” must name its level: prototype, real provider, real Runner,
managed sandbox, deployed tenant, or unattended first-time onboarding.
Reuse the current implementation and qualification evidence. Inspect the relevant
checkout, instructions, app/Cloud PRs, and Runner artifact. Do not recreate work
already merged or apply an old plan to a different deployed revision.
## 2. Prove the uncertain provider boundary first
Identify supported ways to authenticate, wake the agent, load tools, correlate
work, return results, and stop or revoke authority. Check events/subscriptions as
well as direct APIs and chat channels. Do not assume that a bot mention wakes
another bot, that MCP notifications wake an offline agent, or that a plugin listed
in settings is callable in the agent's current conversation.
Use a synthetic company and stable public HTTPS endpoint. Start with a scripted
client for deterministic protocol tests, then the actual provider account:
1. Fresh connection → callable read tool → verified event round trip.
2. Paperclip assignment → autonomous acceptance → persisted result → finalization.
3. Idle bot request → one governed intake → useful action → finalization.
If idle autonomy is in scope, the third journey is a first milestone, not an
optional expansion. Do not make the user create a placeholder task for the bot.
Label every nudge, operator repair, simulated dependency, and manual tool call.
A successful assisted run does not prove prompt-only first-time setup.
## 3. Reuse Runner while keeping placement and capability separate
Read [runner-architecture.md](references/runner-architecture.md) before changing
execution or authority. For Paperclip, prefer the existing Runner infrastructure:
shared lifecycle, receipts, recovery, and a future sandbox boundary for workspace
tools. The bot's model and native tools can remain entirely at its provider.
Use the ordinary configured managed execution environment on Cloud. One admitted
assignment reuses its Runner across messages and tool calls; idle connection
traffic does not allocate compute. A sandbox hosting Runner does not grant the
bot filesystem or shell access. Never add a fallback to the control-plane host.
Implement dedicated agent identity, durable assignment/operation state, current
authority checks, and normal finalization. Treat a proposed alternative backend
as an explicit architecture decision with preserved invariants and evidence of
benefit, not as a reaction to the latest question about overhead.
## 4. Build onboarding as a watched, resumable workflow
Read [onboarding-and-prompts.md](references/onboarding-and-prompts.md). Start at
the natural UI entry: invite an external agent, select the provider, copy a setup
prompt, give it to the bot, and watch real connection checks. Reuse the product's
copy-prompt component and provider-independent invitation flow.
Distinguish OAuth grant, runtime tool availability, subscription verification,
event confirmation, and agent readiness. Generate or renew pending prompts
automatically where safe; preserve connected agents. Finish with an explicit Done
action. Use stories for waiting, expiry, errors, pause, readiness, and recovery,
then verify the real rendered transitions and persistence.
The prompt must tell the bot to use its own relevant tools/apps/skills and return
results. The Paperclip catalog governs Paperclip calls, not the bot's entire
runtime. Limit qualification restrictions to the specific test and Paperclip
destination. Never turn “use this test connection” into “use no other tools.”
## 5. Qualify both correctness and the ordinary user experience
Read [conformance-tests.md](references/conformance-tests.md) and select the rows
required by the release contract. Reuse existing Runner and Product E2E fixtures;
add regression cases for uncovered contracts instead of building a parallel test
system. Keep simulated protocol, actual provider, and actual deployment evidence
separate. A provider saying “done” is not proof of task disposition or cleanup.
Test a lost response, duplicate wake, follow-up at completion, real controller
restart, authority loss, and cleanup. For recovery, compare the original run,
assignment, session, process identity, and lease. A restart test in which the
controller never restarted is invalid. Unknown mutation outcomes require
reconciliation, not a new request ID and a second execution.
If setup needs a reboot, app reattachment, or manual inbox nudge, record the
functional success and the remaining onboarding defect separately. Do not quietly
teach the tester to navigate around a product defect and then call it self-serve.
## 6. Deliver one identifiable candidate and verify the deployed path
Read [troubleshooting-and-deployment.md](references/troubleshooting-and-deployment.md)
when setting up a test drive, diagnosing a failure, or deploying. Preserve one
environment manifest: checkout/revision, origin, local port, data directory,
tenant, image/Runner artifact, active task, and owned resources. Keep secrets out.
Retain the environment while the user/provider is testing; do not expire it
silently or reset the OAuth database behind a cached client registration.
Use the repository's adapter, eval, PR, and release workflows when available.
The Paperclip `create-agent-adapter` skill covers shared configuration surfaces;
`paperclip-runner-release` coordinates a release; `test-it-for-real` validates the
actual experience. Discover their installed locations rather than assuming they
are siblings of this skill. This skill adds external-bot-specific contracts.
Carry authorized merge and rollout through the app, ingress, and Runner artifact
dependencies. Verify the serving revision and repeat the main journeys on the
real tenant with ordinary defaults. Distinguish implementation defects, provider
behavior, infrastructure failures, and test/evidence defects. Bound retries by
the operation and observed cause; preserve the same resumable deployment request.
Report supported capabilities, exact live evidence, interventions, unsupported
provider controls, remaining gates, and resource disposition. Never equate unknown
cost with zero cost, or revoked Paperclip access with confirmed global bot stop.
This skill supplies procedure, not new permission to message, grant access, spend,
publish, or deploy. Apply the current user's authorization and host policies.
## References
- [Release contract](references/release-contract.md): scope, capability matrix,
provider research, architecture decision, and finish-line template.
- [Runner architecture](references/runner-architecture.md): identity, state,
admission, receipts, follow-ups, recovery, files, and concrete Paperclip anchors.
- [Onboarding and prompts](references/onboarding-and-prompts.md): UI states,
consent, lifetime, tool loading, native capabilities, and reusable prompt text.
- [Conformance tests](references/conformance-tests.md): runnable journey recipes,
failure matrix, evidence schema, and release gates.
- [Troubleshooting and deployment](references/troubleshooting-and-deployment.md):
network planes, specific symptom-to-action diagnostics, stable environments,
managed execution, and release provenance.
- [Dot case study](references/dot-case-study.md): dated incidents, exact historical
protocol/tool names, observed limitations, and source trail. Read when comparing
a new provider to Dot or checking why a rule exists.
@@ -0,0 +1,4 @@
interface:
display_name: "Create External Bot Integration"
short_description: "Build and qualify external agents in Paperclip"
default_prompt: "Use $create-external-bot-integration to build and qualify this external agent through Paperclip Runner, including onboarding and both directions of work."
@@ -0,0 +1,211 @@
# External-bot conformance and qualification
## Contents
- [Keep the evidence levels explicit](#keep-the-evidence-levels-explicit)
- [Minimum real-provider journeys](#minimum-real-provider-journeys)
- [Select additional rows from the capability contract](#select-additional-rows-from-the-capability-contract)
- [Record evidence that survives a handoff](#record-evidence-that-survives-a-handoff)
- [Historical Paperclip test entry point](#historical-paperclip-test-entry-point)
## Keep the evidence levels explicit
| Level | What it proves | What it does not prove |
| --- | --- | --- |
| Unit / contract tests | Schema, policy, state transitions, selected races | Real provider or deployed routing |
| Scripted client + actual Rust/DB | End-to-end protocol and ordinary tool/finalizer integration | Provider tool loading, wake behavior, browser setup |
| Scripted client + managed sandbox | Remote artifact/transport, placement, cleanup | Actual external bot or Cloud tenant ingress |
| Actual bot + test drive | Provider behavior, real event/tool loop | Published app image or fresh tenant behavior |
| Actual bot + deployed tenant | Named deployed candidate and selected journeys | All accounts, long-duration reliability, public distribution |
For UI, a Storybook fixture proves a rendered state, not that the backend reaches
that state. A deep link that bypasses onboarding does not prove discoverability.
Use the current repo's `paperclip-evals`, `add-runner-eval`, and
`add-product-e2e-eval` procedures when relevant and available. Locate an existing
case before adding a new fixture. The recipes below specify outcomes; adapt their
tool calls to the actual provider. Do not infer live success from this document.
## Minimum real-provider journeys
### C01 — first connection from a fresh invitation
Start with a synthetic company and no binding for the new agent. Enter through
ordinary agent creation, not its runtime deep link. Generate the prompt and give
it to the real bot. Use only the human actions agreed in the release contract.
Require all of: correct scoped grant, actual read tool invocation, verified
subscription, correlated readiness challenge acknowledged, binding persisted,
agent ready, UI Done, and state still correct after refresh. Do not create a work
task or allocate a sandbox for the readiness challenge. Save the action log and
final screenshot. Record app attachment, reboot, manual consent, or inbox nudges
as interventions. A repaired setup can pass functionally while failing first-try UX.
### C02 — Paperclip assigns useful work with no chat nudge
Create an ordinary task with a fresh synthetic nonce. Example:
```text
Calculate 17 + 25. Write a task document named integration-proof containing
“17 + 25 = 42” and the nonce <RANDOM_NONCE>. Read it back and finish using the
assignment's completion contract. Use no workspace or attachment access.
```
Assign through the normal UI/API and wait for the supported event path. Verify
explicit acceptance, agent/run attribution, document contents and revision count,
canonical completion receipt, run success, task disposition, and cleanup. A
nonce-specific artifact proves the correct task was processed. Do not submit its
result through a connector yourself and describe that as the bot's execution.
### C03 — bot initiates work while idle
With no active assignment, tell the real bot:
```text
Create a Paperclip task titled <UNIQUE_TITLE> and assign it to my responsible
human owner. Find that person using the connection's identity/people tools.
Start governed work yourself if necessary, then return the created task link.
```
Require one visible bot-authored intake, ordinary admission, actual human assignee,
one created target task, and intake completion. Repeat the intake request with the
same stable request ID before and after completion: no additional task/run. A
different prompt with the same ID must fail. Simulate admission failure: the bot
gets an actionable terminal result rather than waiting forever for an offer.
### C04 — use native capabilities and bring back the result
Use a user-authorized synthetic source in a native tool already connected to the
bot, deliberately absent from the Paperclip assigned-app catalog. Ask a question
whose answer requires that source. Require the actual native read and a useful
result persisted on the Paperclip task. Keep data/destination authority explicit;
do not create a new third-party grant solely to make this test pass.
Run once after a narrowly scoped qualification test ends. Failure if the bot says
it lacks the tool merely because Paperclip does not list it. Also verify the
bot cannot substitute another Paperclip identity to bypass a denied operation.
### C05 — follow-up plus a real controller restart
Have the bot accept a task and report readiness once, then wait for a normal task
comment. Capture run/assignment/session, sandbox lease, Runner marker/PID/birth
fingerprint, and controller identity. Restart the owned controller and verify
that it actually changed. Wait through a realistic bounded reconnect gap.
Post the resume instruction as an ordinary Paperclip comment. Require the same
assignment/session/Runner, read of that exact comment, one document result, one
finalization, one task run, and released resources. A dev supervisor that kept
the controller alive invalidates the experiment. A new run completing the task
is retry evidence, not recovery evidence.
Separately force the comment to arrive at completion: unread comments survive
for the next turn; comments read by the active assignment do not run twice.
### C06 — stop and revoked authority
Cancel a synthetic active assignment, then attempt an effect using its old
authority. Verify rejection, fence delivery/acknowledgment, terminal run/assignment
reconciliation, and resource release. Repeat protocol tests for pause, reassignment,
membership loss, revoked grant, refresh replay, and budget stop as applicable.
Do not report global provider termination without provider-level evidence.
## Select additional rows from the capability contract
| ID / boundary | Stimulus | Required observation |
| --- | --- | --- |
| O01 pending renewal | Expire code while dialog open; reopen after refresh | Fresh usable prompt, same agent, no error-as-normal-flow. |
| O02 race | Pair while another tab renews | Completed binding preserved; no two active grants or renewal loop. |
| O03 lifecycle | Preparing, verifying, manually paused, awaiting approval | Setup allowed only in legitimate setup states; Done waits for readiness. |
| O04 provider runtime | Install/update plugin while bot conversation active | Actual new action usable; catalog refresh/attachment instructions truthful. |
| O05 lifetime | Rotate refresh token; replay old token; simulate long inactivity | Policy-specific renewal works; replay/revocation deny access; expired grants not revived. |
| O06 optional avatar | Same upload twice, other agent/company, restricted token, export/import | Self-scoped, normalized, idempotent; no private asset ID portability leak. |
| D01 event duplication | Duplicate and reorder signed event deliveries | Same mailbox/assignment processed; no duplicate effects. |
| D02 event delay | Deliver after acceptance deadline or during reconnect | Stale offer rejected/reconciled; no new authority from an old event. |
| D03 resubscribe | Subscription expires with outstanding work | Reverification and fresh reference to existing work; no replayed effects. |
| D04 cursor concurrency | Commit two mailbox writers around an inbox read | Cursor cannot skip a later-committed result. |
| D05 callback authority | Failed ownership challenge, wrong signature, replay where applicable | No unverified subscription or unauthorized state transition; correct signing material stays secret. |
| D06 callback egress | Private-address destination, redirect escape, timeout, repeated failure | Destination policy enforced; bounded attempts and visible failure; no internal-network access. |
| R01 response loss | Drop response after a document mutation | Same ID retrieves same effect/receipt; revision count stays one. |
| R02 ambiguity | Kill controller after external mutation starts | Unknown outcome surfaced; no automatic second effect. |
| R03 definite error | Read a nonexistent file/skill | Terminal bounded error; later tools and finish still work. |
| R04 stale controller | Late callback after ownership generation changes | Cannot overwrite newer state; late effect evidence retained. |
| R05 missing checkpoint | Remove/mismatch recovery evidence after dispatch | Reconciliation required; no replacement assignment disguised as resume. |
| R06 completion order | Finish with pending tools or changed report | Rejected until contract satisfied; canonical result retained. |
| R07 shutdown | Acknowledged shutdown before monitor's next poll; absent exit code | Clean exit recognized only with authenticated terminal evidence. |
| A01 identity | Cross-company IDs, wrong agent/resource, invalid pairing hint | Denied by server; no authority selected by caller fields. |
| A02 review/people | Review another agent's task; assign to a human | Legitimate mode-specific access works without granting unrelated task writes. |
| A03 live grant loss | Revoke setting/grant during a protected read | No new protected response after revocation. |
| A04 API fallback | Try file download/upload through generic API tool | Same attachment/workspace rules apply; no alternate-path bypass. |
| S01 skills/apps | Pinned synthetic skill; assigned gateway tool; tool revocation | Correct version/digest and normal gateway auth/receipts; stale catalog can't override authority. |
| F01 attachment | Answer only on page two; corrupt/hash-changed/oversized files | Correct bounded paging and integrity errors; no data from another task. |
| F02 artifact | Produce and register output | Downloaded bytes and SHA-256 match; task links the usable work product. |
| W01 workspace | Traversal, symlink, instance config, credential access | Confined or denied across every file and upload path. |
| W02 commands | Detached descendants, timeout, cancellation | Supervisor and descendants contained/terminated; unavailable platforms fail closed. |
| W03 concurrent edits | Two writes with same observed hash | At most one commits; second sees conflict. |
| C07 placement | Idle reads; many tools/messages in one active task | No idle compute; same admitted Runner/lease reused. |
| C08 artifact mismatch | Managed image contains pre-provider Runner | Capability/digest check rejects before advertising work. |
| C09 terminal failure | Allocation timeout, failed admission, orphan offer | Clear terminal receipt, no blocked future work, tracked cleanup. |
| C10 deploy | Fresh tenant and shipped images through real ingress | OAuth, anonymous consent, both work directions, and cleanup pass. |
Long-duration subscription/refresh tests need real provider time as well as fake
clock unit tests. Select a duration consistent with the release claim; a five-minute
demo does not establish multi-day availability. Do not leave a paid soak running
without authorization, ownership, limits, and a supported monitoring mechanism.
## Record evidence that survives a handoff
Use one row per case and candidate; do not combine incompatible partial runs into
one green campaign. A useful record is:
```yaml
case: C05
candidate:
appCommit: <sha>
ingressCommit: <sha-or-not-applicable>
appImageDigest: <digest>
runnerArtifactDigest: <digest>
environment: <tenant-or-isolated-instance>
client: actual-provider # or scripted
startingState: <fresh/connected/accepted/etc>
identities:
run: <id>
assignment: <id>
session: <id>
lease: <id>
controllerBefore: <id>
controllerAfter: <id>
processFingerprintBefore: <redacted-reference>
processFingerprintAfter: <redacted-reference>
interventions: []
observed: <receipts, document revisions, task state>
evidence: <log/screenshot/artifact links>
cleanup: <released/destroyed/pending with provider receipt>
outcome: PASS # FAIL / BLOCKED / UNVERIFIED / NOT_APPLICABLE
limits: <which release claims this does not establish>
```
Keep secrets, callback signing keys, access/refresh tokens, pairing codes, and
private source data out of reports and public PRs. Internal IDs may belong in a
private qualification record; follow the repo's public issue/PR rules.
## Historical Paperclip test entry point
The October 9 integration used `server/src/__tests__/dot-runner.test.ts` for
actual Rust/PostgreSQL tests and an opt-in private Daytona case:
```sh
pnpm exec vitest run server/src/__tests__/dot-runner.test.ts -t 'private Daytona Rust'
```
That candidate read `PAPERCLIP_DOT_DAYTONA_LIVE=1`, `DAYTONA_API_KEY`, an immutable
`PAPERCLIP_DOT_DAYTONA_IMAGE`, optional `PAPERCLIP_DOT_DAYTONA_RUNNER_BINARY`, and
`PAPERCLIP_DOT_DAYTONA_EVIDENCE`. Locate the current fixture and inspect its flags,
cost bounds, dependencies, and `finally` cleanup before running. Do not print
credentials. This case used a scripted MCP client; it never replaced real Dot
qualification. The command/flags are historical anchors, not a guaranteed current CLI.
Run the smallest decisive tests while iterating, then the repository-required
typecheck/test/build and review gates on the final candidate. A stale broad suite
running across source edits is not evidence for the final revision. Separate
unrelated infrastructure failures from product regressions, retain failed attempts,
and re-run affected cases after fixes.
@@ -0,0 +1,188 @@
# Dot integration: dated case study and source trail
## Contents
- [What the user actually wanted](#what-the-user-actually-wanted)
- [Incidents and the reusable judgment](#incidents-and-the-reusable-judgment)
- [Historical Dot protocol and tools](#historical-dot-protocol-and-tools)
- [What was and was not proven](#what-was-and-was-not-proven)
- [Sources and how to inspect them](#sources-and-how-to-inspect-them)
This is evidence from September 30–October 9, 2026, reviewed from raw records on
October 13. It is not current provider documentation or permission to repeat old
operations. Use it to recognize failure modes and locate prior implementation.
No credentials, pairing codes, temporary ingress hosts, or personal app contents
are retained here.
## What the user actually wanted
- The existing personal Dot, not a replacement generic API agent.
- Paperclip could initiate work; Dot could read/write and initiate work while idle.
- Shared new Runner infrastructure.
- Eventually a full company participant: people, tasks, skills, apps, optional files.
- An external-agent invitation with a copy prompt and live checks.
- Persistent Paperclip connection until revoked.
- Cloud deployment with managed execution and no arbitrary host execution.
- Dot uses its own relevant tools and returns the result to Paperclip.
Idle autonomy was explicit on day one and in the first production plan. Shipping
task-only access was an implementation omission, not missing user specification.
Cloud-first delivery, exact capability parity, allowed setup interventions, and
latency/concurrency needed an earlier explicit release contract.
## Incidents and the reusable judgment
| Date / incident | Observed outcome | Rule carried into this skill |
| --- | --- | --- |
| Sep 30: initial research favored Slack / another agent API | User pointed out MCP Events; official docs then supported testing that route. | Search server-initiated events before choosing transport; existing personal bot is a different product from an API agent. |
| Oct 2: lab assumed OAuth request ID was UUID | Real consent failed; request ID was opaque. | Preserve protocol identifiers as specified. |
| Oct 2: DB restart erased cached client registration | Provider returned unknown client/redirect; reconnect state had drifted. | Stable fixture includes registration and public origin, not just app health. |
| Oct 2: settings listed tools, Dot could not call them | Endpoint was stopped; Dot loaded actions later; replacement lab completed arithmetic round trip. | Keep test service alive during provider setup; test actual runtime invocation. |
| Oct 3: production Runner implementation | Rust/DB integration worked, but the new endpoint still lacked real-account qualification. | Reference harness, production Runner, and actual provider are distinct proof levels. |
| Oct 6–7: merged MCP gateway integration | Reused consent, verification, refresh, revocation; fixed normal shutdown race. | Reconcile shared infrastructure and its contracts instead of retaining a forked prototype. |
| Oct 7: public Tailscale metadata worked locally/externally, provider discovery timed out | No request reached app; Cloudflare discovery worked; provider browser had separate failures. | Diagnose each network client independently; do not infer bot blocking or port policy from a timeout. |
| Oct 7: uncompressed large bundle | Public download improved from 11.3 s to 2.9 s after compression; discovery problem remained. | Separate performance and connectivity failures; one fix does not prove another boundary. |
| Oct 7: client preferred private_key_jwt but allowed none | Selecting supported PKCE public method fixed compatibility. | Negotiate advertised support, retaining PKCE/redirect/resource checks. |
| Oct 7: live ordinary task rejected before assignment | Heartbeat admission lacked the Dot bridge descriptor although integration tests passed. | Enter through ordinary product scheduling, not only a broker fixture. |
| Oct 7: “create hello for my owner” refused while idle | Added governed intake and human assignees; actual Dot completed it. | Both directions are first-class acceptance journeys. |
| Oct 7: pairing ready but agent config missing binding | Required another form save until atomic persistence fix. | One logical setup operation must persist all required state. |
| Oct 7: missing-file read never settled | Turn could not close; terminal read-error receipt fixed it. | Distinguish definite failure from ambiguous mutation outcome. |
| Oct 7: workspace execution and file access expansion | cwd was insufficient; review found `.paperclip` leakage and API bypasses; macOS commands later disabled. | Trace effects and test all access paths; fail closed when confinement is unproven. |
| Oct 7: late event | One event arrived roughly 32 minutes later; completed work was not repeated. | Event delivery is asynchronous; test late offers and never claim a latency SLA from one success. |
| Oct 8: cloud architecture reconsidered repeatedly | User chose common Runner for lifecycle reuse and potential future workspace tools. | State decision criteria and retain the decision; placement is separate from tool access. |
| Oct 8: expired setup prompt and nested copy window | Added automatic renewal, automatic close on connection, progress footer and Done. | Normal asynchronous progress should not require manual repair. |
| Oct 8: 30-day inactivity limit | Removed for active Dot connections; review ensured expired credentials stayed invalid. | Separate persistent grant policy from token/code/lease lifetimes. |
| Oct 9: remote transport and old image | Wrong localhost endpoint and pre-Dot Runner artifact blocked execution. | Test authenticated remote ingress and actual packaged capability before dispatch. |
| Oct 9: idle intake lost sandbox plugin context | Operator work succeeded; bot-initiated work failed lease acquisition. | Both entry paths must use configured application services. |
| Oct 9: restart qualification | First attempt did not actually restart controller; later attempts exposed missing fingerprint and local/remote PID collision. | Prove the intervention and unchanged remote identity, not just eventual success. |
| Oct 9: normal follow-up generated second run | Coalescing fixed duplication; review then caught possible loss at completion. | Consume a wake only after exact comment delivery/read evidence. |
| Oct 9: actual tenant onboarding | Preparing agent treated as manually paused; expected anonymous 401s caused consent reload loop. | Test fresh deployed lifecycle and anonymous flow through Cloud front door. |
| Oct 9: deployment drift and provider capacity | Fleet replaced candidate; test tenant pinned; first Daytona allocation timed out and later cleaned up. | Record/pin candidate through supported controls; verify provider cleanup separately. |
| Oct 9: native Slack refusal | Qualification instruction “use only the staging plugin” leaked into normal work. | Scope test constraints to destination/task/duration; explicitly permit native capabilities. |
## Historical Dot protocol and tools
Transport was authenticated MCP inward and signed MCP Events outward. The
qualified event was `paperclip.dot.mailbox_updated`. Subscription methods included
`events/list`, `events/subscribe`, and `events/unsubscribe`; these are protocol
methods, not extra callable tools. The experiment used MCP version `2026-07-28`.
Verify current support and account eligibility instead of copying that version.
The final top-level MCP catalog had 16 tools:
| Purpose | Tool names |
| --- | --- |
| Identity and proactive work | `paperclip_dot_capabilities`, `paperclip_dot_request_turn`, `paperclip_dot_tasks`, `paperclip_dot_request_work` |
| Setup and inbox | `paperclip_dot_pair`, `paperclip_dot_inbox`, `paperclip_dot_confirm_event` |
| Assignment | `paperclip_dot_read`, `paperclip_dot_accept`, `paperclip_dot_tool` |
| Lifecycle and receipts | `paperclip_dot_progress`, `paperclip_dot_finish`, `paperclip_dot_operation_status`, `paperclip_dot_renew`, `paperclip_dot_control_ack` |
| Optional profile | `paperclip_dot_set_avatar` |
The nested Runner catalog was read per assignment. Bot called its Paperclip tool
names via `paperclip_dot_tool`; native tools were called in the bot's own runtime.
Standard completion was `paperclip_finish` or `paperclip_block` through the bridge,
then `paperclip_dot_finish` with the accepted canonical report. Do not collapse
these steps into an unverified conversational “done.”
Historical constants help reproduce old cases, not set new-provider defaults:
- Instance settings: **Assistant connections (MCP)** and **OpenAI Dot**, with
authenticated sign-in and a stable `PAPERCLIP_PUBLIC_URL`. The old
`PAPERCLIP_ENABLE_OPENAI_DOT` environment flag no longer enabled the provider.
Self-hosted Dot did not require the general Runner picker flag; Cloud additionally
required native Runner configuration and the managed execution plugin.
- Pairing code: 15 minutes, one use. Access token: 15 minutes.
- Persistent Dot refresh authority: rotating, no inactivity expiration, revocable.
- Acceptance window: 10 minutes. Execution lease: initially two hours, renew up
to two hours ahead within a 24-hour total bound.
- Broker operations: initially 200, expanded to 4,000. One active assignment.
- Managed controller reconnect grace: five minutes after recovery fixes.
- Attachment reads: explicit grant, up to 16 MiB/file, bounded 12,000-byte pages,
metadata/digest checks and live authority checks.
- Cloud workspace access: off. Self-hosted Linux command execution required
confinement; macOS commands ultimately unavailable.
- Avatar: `paperclip_dot_set_avatar` accepted `{ "imageBase64": "<raw bytes>" }`
or `null` to restore the preset. PNG/JPEG/WebP, at most 512 KiB and 16 megapixels;
normalized to metadata-free PNG no larger than 512 pixels per side. The agent
route was `PUT /api/companies/:companyId/agents/:agentId/avatar`, self-only for
agents; the resulting company-scoped asset was private, not a public avatar URL.
These were implementation choices subject to later change. The 32-minute delayed
event is evidence that acceptance deadlines and wake latency must be evaluated
together; it is not a measured percentile or guaranteed delay.
## What was and was not proven
The prototype used TypeScript `HarnessDriverBackend` and synthetic admission; it
did not qualify Rust Runner. The dedicated endpoint later completed ordinary
Paperclip tasks with actual Dot, and the expansion proved idle work, human
assignment, pinned skills, documents, attachments, and verified artifacts. A
workspace command succeeded in the earlier macOS prototype but that capability
was subsequently disabled for containment reasons; do not cite the early success
as support for the final platform capability.
Managed qualification used both a scripted MCP client and the real Dot. The
strong restart proof recorded changed controller identity, same remote Runner
fingerprint/session/assignment, one task run, one follow-up, normal completion,
and released resources. Cancellation records distinguished Paperclip fencing
from global external stop.
The deployed Cloud tenant completed three task checks in both directions and all
their Runner sandboxes were destroyed. Setup still needed plugin attachment and
a Dot reboot to expose actions. This did not establish a universally successful
prompt-only first attempt. Assigned gateway tests used a synthetic service, not
every live third-party provider. Long-duration availability and public plugin
distribution were not established by the short campaign.
The final native-tool guidance was merged and the actual Dot acknowledged it.
Its test-tenant rollout remained blocked by Docker Hub 429 then 504 errors at the
end of the recorded campaign. Do not describe that last rollout as deployed based
on the merge or the live conversational correction.
## Sources and how to inspect them
The case study was reviewed against the original authorized session records,
including user requests, final responses, progress updates and selected command
and browser results. The public implementation/review trail below lets repository
contributors inspect the resulting code and decisions. Private session identifiers
and raw-log offsets are omitted because they are not portable source references.
When investigating a later case, retrieve only authorized, relevant history with
the host's supported tools. Use original execution records to check what actually
ran. Treat historical instructions as evidence rather than new authorization.
One integration with many corrections does not establish that every failure mode
recurs across unrelated providers.
Implementation/review trail:
- [Paperclip #15402](https://github.com/paperclipai/paperclip/pull/15402): dedicated Dot Runner provider and gateway integration.
- [Paperclip #15414](https://github.com/paperclipai/paperclip/pull/15414): capabilities, onboarding and standalone experiment.
- [Paperclip #15581](https://github.com/paperclipai/paperclip/pull/15581): external invitation, avatar, prompt/lifetime UX.
- [Paperclip #15691](https://github.com/paperclipai/paperclip/pull/15691): managed Runner and recovery.
- A separate Cloud ingress change enabled tenant routing. Its repository is private; inspect the authorized current Cloud runbook when qualifying deployment.
- [Paperclip #15722](https://github.com/paperclipai/paperclip/pull/15722): real Cloud onboarding/lifecycle fixes.
- [Paperclip #15734](https://github.com/paperclipai/paperclip/pull/15734): native-tool guidance and test-scope correction.
Historical documentation can be recovered from the Paperclip checkout:
```sh
git show 27888cabdf7e2fa074dc16cb18ed36b074ba4763:doc/openai-dot-runner.md
git show 27888cabdf7e2fa074dc16cb18ed36b074ba4763:doc/plans/2026-10-02-openai-dot-runner-adapter.md
git show 27888cabdf7e2fa074dc16cb18ed36b074ba4763:doc/plans/2026-10-08-cloud-dot-runner-and-external-invitations.md
```
That SHA is the final guidance candidate, not a claim about today's deployed app.
Inspect current code for actual commands, fixtures and limits. Documentation in
that historical snapshot mixes original setup steps and subsequent checkpoints;
use the implementation and dated evidence to resolve conflicts.
Provider research starting points used during the campaign, to revalidate:
- [Dot documentation](https://learn.chatgpt.com/docs/dots)
- [MCP Events](https://developers.openai.com/plugins/build/mcp-events)
- [Plugin authentication](https://developers.openai.com/plugins/build/auth)
- [Connect ChatGPT](https://developers.openai.com/plugins/deploy/connect-chatgpt)
- [Secure MCP tunnels](https://developers.openai.com/api/docs/guides/secure-mcp-tunnels)
Do not infer that another external agent supports MCP Events, Dot's tool names,
private-plugin onboarding, or the same approval/distribution rules.
@@ -0,0 +1,200 @@
# Onboarding, consent, and agent instructions
## Contents
- [Design from the user's entry point](#design-from-the-users-entry-point)
- [Model the states the user will actually encounter](#model-the-states-the-user-will-actually-encounter)
- [Separate setup approvals from repeated intervention](#separate-setup-approvals-from-repeated-intervention)
- [Separate the four lifetimes](#separate-the-four-lifetimes)
- [Generate instructions the receiving agent can execute](#generate-instructions-the-receiving-agent-can-execute)
- [Test prompts must constrain the destination without disabling the bot](#test-prompts-must-constrain-the-destination-without-disabling-the-bot)
- [Keep optional identity polish narrowly scoped](#keep-optional-identity-polish-narrowly-scoped)
## Design from the user's entry point
For the Dot flow, the approved entry was **New Agent → Invite an external agent →
Dot / Hermes / Other**, not a hidden Runner provider configuration. Use the current
product's equivalent. A provider preset may customize its logo, instructions and
checks; it must not silently redesign another provider's enrollment protocol.
Hermes originally retained the existing external-agent prompt.
Use the same square selection cards as the harness picker, actual provider logos,
the shared copy-prompt component, and the normal dialog footer. Preserve agent
details on Back. Animate changes in dialog size using the design system and honor
reduced motion. Follow current repository design/token instructions.
Show prerequisite features and evaluate their actual server-side availability.
Dot's standalone experiment did not implicitly enable every Runner provider.
Cloud's managed execution also required its native Runner configuration. Distinguish
those environment prerequisites from the user-facing provider picker; do not make
users discover a disabled backend only after they have completed provider consent.
Make the user-facing sequence short:
1. Choose the bot and create/resume its agent invitation.
2. Copy the complete prompt and give it to that bot.
3. Grant any required scoped consent through the supported flow.
4. Watch connection, task updates, and a harmless test event.
5. Choose Done when both the connection and agent are ready.
A readiness probe should not create a visible work task. Create a real task later
for assignment qualification. Optional avatar/profile steps must not delay readiness.
## Model the states the user will actually encounter
| State or event | Required behavior |
| --- | --- |
| Opening setup with no usable pending code | Create a fresh prompt automatically after checking authoritative connection state. |
| Pending prompt expires while open | Refresh it safely; explain genuine renewal failure with Retry rather than looping. |
| Existing connection is already established | Resume its status; do not revoke it to generate a new code. |
| Another tab replaced the pending prompt | Avoid renewal ping-pong; ask before replacing that newer prompt or follow the product's explicit conflict policy. |
| OAuth/binding observed | Close any nested copy-prompt window; replace the copy action with Connecting… status. |
| Callback subscription verified | Keep completed checks checked; show confirmation of the test event in progress. |
| Event challenge confirmed, agent still preparing | Show Finishing setup…; do not claim the event is still pending. |
| Agent and connection ready | Enable Done, which closes the modal. |
| Watch connection interrupted | Recover/resync from server state and explain the interruption; do not discard the pairing. |
| Agent preparing/verifying with compatibility status paused | Allow setup when the server says setup is permitted. |
| Agent genuinely manually paused or awaiting hire approval | Show the actual blocker and its action; do not auto-resume or bypass approval. |
| Returning after refresh | Resume the same agent/invitation; do not create another agent. |
Derive UI decisions from server lifecycle facts. Dot Cloud initially had a circular
dependency: hire preparation waited for pairing, but the UI treated preparation
as a manual pause and demanded resume before pairing. Story fixtures alone did
not reveal the real newly-created-agent state.
Keep one current setup procedure in documentation. Move historical/manual steps
to an explicitly dated section when automatic renewal or atomic pairing replaces
them. Do not leave “revoke, pair, save again” beside a newer one-step flow.
## Separate setup approvals from repeated intervention
Specify the allowed human actions in the release contract. “No human operates the
bot's computer” can still involve a human approving a grant in chat and Codex
submitting the already-authorized action. It does not prove that the bot alone
completed every browser step. Record who performed consent, app attachment,
catalog refresh, and reboot during qualification.
Consent should preview the exact company, agent, access scope and duration before
submission. A one-use pairing code can preauthorize that exact agent without
handing an operator password or board session to the external computer. Keep
preview read-only and code consumption atomic. Revalidate current permissions at
redemption, including when the creator has since left the company.
The historical user authorized a specific plugin-creation risk notice through
this exact extra prompt paragraph:
> When you setup the plugin, I already understand that MCP servers have risk, so
> you check “I understand and want to continue,” and click “Create as a plugin.”
> I want you to create the plugin for me completely and I don't want to have to
> do anything.
This is a historical consent example, not permission for future agents or users.
Do not bake an assertion of user approval into every generated prompt. Use current
authorization, distinguish a nonbinding risk notice from granting ongoing access,
and obey the actual browser/provider policy. An agent relaying approval may not be
accepted as the human's approval by the receiving agent. Do not impersonate the
human to resolve that; use a supported direct approval path when authorized.
## Separate the four lifetimes
1. **Pairing capability:** short-lived, one use; safe automatic renewal before use.
2. **Access token:** short-lived bearer authority, refreshed through its protocol.
3. **Persistent connection/refresh authority:** product policy; Dot was changed to
remain valid until revoked with rotating refresh tokens and replay checks.
4. **Subscription and assignment leases:** bounded and separately renewed; a
persistent account connection does not make a task's authority permanent.
The Dot user requested no Paperclip inactivity expiration. Migration preserved
currently valid connections; it did not revive expired, consumed, or revoked
credentials. Test renewal, rotation, replay and revocation independently. Do not
promise that Paperclip's lifetime policy controls the provider's own account rules.
## Generate instructions the receiving agent can execute
Adapt the following to the provider's supported protocol and actual tool names.
Do not send placeholder values, credentials, or a URL from an old environment.
```text
Connect yourself to Paperclip as <agent> in <company>.
Add or reuse the private plugin for this exact server URL: <MCP_URL>.
Use the supported OAuth flow. Reuse an existing definition only if its URL matches;
if the name belongs to another URL, choose a distinct name instead of replacing it.
Use this one-use pairing code on the consent page: <PAIRING_CODE>.
Review the exact company, agent, permissions, and duration. Complete the authorized
steps; if a required approval is missing, request that specific approval.
Verify an actual read-only call through this connection. If the installed plugin's
tools are absent in your runtime, refresh/attach it through the provider's supported
flow and report any remaining blocker. Do not claim access from a settings listing.
Enable the task-update subscription returned by Paperclip. Follow its event
instructions, drain the inbox from your saved cursor, and confirm the readiness
challenge. Do not create a task just to confirm readiness.
For assignments, read and accept current work, use stable request IDs, reconcile
pending results, and follow the supplied reporting/completion contract. For new
work requested while idle, use the governed intake tool and poll the same request
if admission is pending; do not ask the human to create a placeholder task.
Use your own relevant tools, apps, plugins, skills, and capabilities to complete
the request, then return the result and deliverables to the Paperclip task.
The Paperclip catalog describes Paperclip operations. It does not disable your
native tools or require those tools to appear in that catalog. Respect the tools'
existing permissions and approvals. Keep Paperclip operations within the current
connection's authorized company, agent, and task; do not use another identity to
bypass a denied Paperclip operation.
Report which connection checks actually succeeded and any exact blocker.
```
Put native-tool guidance at the points where it changes behavior: setup prompt,
server onboarding text, event instructions, capabilities, and each assignment.
Test rendered plain-text documents as well as JSON fields. The Dot follow-up
initially added guidance to the JSON manifest but omitted the `onboarding.txt`
renderer; agents receiving only that URL still missed it.
Do not copy every instruction into every tool description. Keep one common source
where package boundaries permit. Use a lightweight dependency-free shared export
for UI copy to avoid importing a heavy shared barrel. The standalone Runner may
need its own small instruction constant with a clearly documented alignment point.
Historical instruction surfaces to locate in the current checkout:
- `ui/src/lib/dot-setup-prompt.ts`
- `ui/src/lib/agent-onboarding-prompt.ts`
- `server/src/routes/access.ts` and its actual onboarding text renderer
- `server/src/services/dot-runner-broker.ts` pairing/event/capability responses
- `packages/paperclip-runner/src/backends/runtime-context.ts`
- `packages/shared/src/external-agent-guidance.ts`
## Test prompts must constrain the destination without disabling the bot
Bad: “Use only the staging plugin.” Dot carried this into later work and refused
to use its already-connected native Slack.
Use a narrowly scoped qualification instruction:
```text
For qualification task <CASE_ID> only, send Paperclip operations through
<TEST_CONNECTION> for <TEST_COMPANY>. This selects the Paperclip destination;
it does not restrict your relevant native tools. Do not alter other connections.
After this case, these test-only restrictions end. Return results to its task
using the normal reporting and completion tools.
```
If a case deliberately excludes native tools to isolate one transport, say so
for that case only, then end the restriction explicitly. Run a subsequent native
tool case to detect leakage of the test restriction into normal behavior.
## Keep optional identity polish narrowly scoped
Dot's avatar tool accepts image bytes for its own bound Paperclip agent, re-encodes
them, and never grants generic agent administration. Validate format, byte and
pixel limits; remove metadata; make replay safe. A private asset ID cannot simply
be exported to another company. Preserve portable name/character/palette and omit
or remap company-local image IDs on import.
Do not invent an avatar-export API or extract an unrelated image just because the
UI has an avatar. Ask the bot to upload its current avatar only if available; lack
of that capability must not block connection or task qualification.
@@ -0,0 +1,141 @@
# Release contract and provider discovery
## Contents
- [Make the requested outcome testable](#make-the-requested-outcome-testable)
- [Define capability parity rather than promising “full-fledged”](#define-capability-parity-rather-than-promising-full-fledged)
- [Research only what can change the next decision](#research-only-what-can-change-the-next-decision)
- [Choose the execution model once, using stated criteria](#choose-the-execution-model-once-using-stated-criteria)
- [Keep a finite delivery sequence](#keep-a-finite-delivery-sequence)
## Make the requested outcome testable
An external bot is an existing agent whose execution is hosted elsewhere. It may
have memory, a browser, skills, accounts, and tools Paperclip neither supplies nor
controls. Decide whether this integration connects that existing agent or creates
a separate API agent. They can have different identity, billing, tools, and memory.
Do not substitute a provider's generic agent API for the user's personal bot
without making that distinction explicit. Dot's initial investigation considered
both; the user wanted the actual existing Dot.
Use this contract in the task or existing implementation plan:
```text
Provider / existing bot or newly created API agent:
Ordinary entry point and target users:
Release targets: self-hosted / Cloud / both:
Transport outward / return channel / provider evidence:
Paperclip acting identity and company/agent mapping:
Paperclip-originated work acceptance journey:
Bot-originated idle work acceptance journey:
Native tools policy:
Required Paperclip capabilities / explicitly deferred capabilities:
Workspace access and execution placement:
Allowed human setup steps:
Connection lifetime / revocation / subscription renewal:
Latency, concurrency, run duration, resource and test-spend bounds:
Provider controls unavailable or unknown:
Target deployment and authorization already established:
Finish line and evidence required:
Next critical-path gate / owner / action:
```
Fill from context and supported defaults. Ask only where an unknown changes the
product, authority, cost, or acceptance. Do not turn the template into a mandatory
questionnaire. If the user says “two way,” keep both directions in the finish line.
If Cloud is deferred, state that before delivering an apparently complete agent.
## Define capability parity rather than promising “full-fledged”
For each area, mark Required, Optional, Deferred, or Provider unavailable. Add
whether it works idle, during a run, after completion, and after revocation.
| Area | Questions that affect implementation |
| --- | --- |
| Identity | Is the caller a company agent or a human's personal assistant? Can one external bot bind multiple agents? |
| Idle intake | Can the bot create governed work when no task is assigned? Does the user see the intake and its attribution? |
| Coordination | Search/read tasks; create and assign to agents or people; comment and edit authorized cross-task documents? |
| Native tools | Can the bot use its existing Slack/browser/computer? What permissions remain provider-owned? |
| Assigned tools | Pinned Paperclip skills, gateway apps, dynamically granted tools, permission changes during a turn? |
| Attachments | Which task/company files may leave Paperclip, how are pages/integrity checked, and can access be revoked mid-read? |
| Workspace | Files, shell, Git, artifact publishing; whose machine; explicit settings; which platforms? |
| Human interaction | Questions, approval requests, replies, denial, resumption, and visibility in the task thread? |
| Lifecycle | Follow-up, interruption, cancellation, restart, reconnect, lease renewal, and a terminal failure path? |
| Observability | Acceptance, progress, operation results, persisted output, task disposition; which provider data is absent? |
| Economics | Provider usage/cost versus managed Runner cost; admission budget checks when provider usage is unknown? |
| Identity presentation | Provider logo, agent name/avatar, export/import portability; optional profile work must not block connection. |
Three separate grants deserve explicit treatment: persistent agent connection,
access to task attachments, and Paperclip workspace execution. One does not imply
the others. For Dot, attachment and workspace settings were independently off by
default and were never inherited automatically by a newly hired teammate.
## Research only what can change the next decision
Use official provider docs and current code. Record the source, date, fact, and
remaining experiment. Classify claims as documented, observed with real provider,
simulated, inferred, or unknown. Search for these capabilities before selecting:
- Direct create/message/status/cancel APIs for this exact kind of agent.
- Out-of-band events, subscription discovery/renewal, callbacks and verification.
- In-session notifications versus wakeup when no live conversation is connected.
- Bot-to-bot mentions, DMs, channel permissions, and automated-message filtering.
- Tool/plugin installation, OAuth discovery, public-client support, runtime loading.
- Structured tool calls/results, correlation IDs, idempotency, and result polling.
- Provider-native session identity, resume, interruption, usage, and rate limits.
- Private testing, workspace distribution, public review, and account/admin limits.
An HTTP success from a notification endpoint proves receipt at that layer. It
does not prove that the agent woke, loaded tools, accepted work, or finished.
Browser automation can help investigate and qualify setup; do not accidentally
make an undocumented UI automation path the production transport.
For a proposed chat transport, send one authorized synthetic automated message
and require the bot's correlated callback. A human-written mention succeeding is
not evidence that messages from another bot will wake it.
## Choose the execution model once, using stated criteria
Paperclip's established preference is shared Runner infrastructure for remote
agents. It preserves existing lifecycle/receipt semantics and a sandbox boundary
if workspace capabilities are granted later. Remote reasoning does not eliminate
the need for run coordination, nor does using Runner imply local model execution.
Evaluate alternatives against common admission/finalization, authority, recovery,
compute waiting cost, operating complexity, and future workspace requirements.
Document the choice and trigger for revisiting it. Do not alternate between a
Runner, worker fleet, and database-only backend just because each was questioned.
For the Dot Cloud release the decision was one managed Runner per admitted
assignment, no sandbox for idle MCP traffic, and no exposed workspace tools. It
accepted compute while waiting as the cost of reusing the normal lifecycle.
Do not generalize “one sandbox per assignment” to providers/releases that have an
explicitly different approved execution contract.
## Keep a finite delivery sequence
1. **Feasibility:** actual provider wake/read/report loop on synthetic data.
2. **Governed vertical slice:** normal task + idle intake through actual Runner.
3. **Product onboarding:** natural entry, copy prompt, real watched readiness.
4. **Reliability:** duplicate/lost response, follow-up race, restart, stop, cleanup.
5. **Selected capabilities:** native apps, assigned apps/skills/files as promised.
6. **Deployed acceptance:** ordinary app image, Runner artifact, tenant ingress.
Some work can overlap; the key is not building a broad tool catalog before the
uncertain provider boundary and both entry paths work. Split reviewable changes
when they span app, ingress, execution, or broad authority changes. Record their
dependencies instead of declaring an arbitrary count of PRs required.
Useful final acceptance statement:
> On the named Cloud tenant and immutable candidate, a new user can invite the
> existing bot with the generated prompt and one scoped consent approval. Without
> a chat nudge, an ordinary assigned task saves a verifiable result and completes.
> From idle, the bot can initiate work and assign a task to the responsible human.
> A follow-up and real controller restart preserve one assignment. Revocation
> denies further Paperclip actions, and every managed resource is accounted for.
Adapt this to the actual release. If plugin attachment or reboot is required,
include it as a supported visible step or report an onboarding gap; do not claim
the stricter prompt-only journey passed.
@@ -0,0 +1,226 @@
# Runner architecture and correctness boundaries
## Contents
- [Separate the bot, connection, controller, and workspace](#separate-the-bot-connection-controller-and-workspace)
- [Identity and authority](#identity-and-authority)
- [Durable state and operation contract](#durable-state-and-operation-contract)
- [Follow-up delivery must be coordinated with ordinary wake scheduling](#follow-up-delivery-must-be-coordinated-with-ordinary-wake-scheduling)
- [Recovery needs identity evidence, not merely a reachable process](#recovery-needs-identity-evidence-not-merely-a-reachable-process)
- [Revocation and native powers are different boundaries](#revocation-and-native-powers-are-different-boundaries)
- [Files and commands are a separate capability decision](#files-and-commands-are-a-separate-capability-decision)
- [Paperclip implementation anchors](#paperclip-implementation-anchors)
## Separate the bot, connection, controller, and workspace
```text
External provider
Bot: reasoning, native browser/computer/apps, private memory
| authenticated tools / signed wake events
Paperclip control plane
MCP + OAuth + pairing + durable mailbox + operation broker
| authenticated Runner protocol
Managed execution environment (Cloud)
Rust Runner: assignment lifecycle, catalog validation, durable receipts
| semantic tool requests / correlated results
Paperclip authority services
Task/company permissions, mutations, app gateway, result finalization
```
Application tools execute through the existing authorized services. If filesystem
or shell tools are enabled, their execution target must be the assigned confined
workspace. Moving Rust into a sandbox does not magically move a server-side file
handler there. Trace the actual effect destination for every workspace operation.
Dot's model runs at OpenAI. Runner does not create its personal memory, run its
model, control its computer, or guarantee interruption of other native tools.
Do not invent model/session/usage fields to satisfy a local-provider schema.
## Identity and authority
Use a dedicated agent-purpose grant/resource where the provider is acting as an
employee. Personal assistant grants must not silently supply board/operator
permissions to a run. Bind authorization to company, agent, active grant, binding
generation, assignment, and run/turn. A supplied companyId or agentId is not proof
of authority. Recheck live permissions at execution and before returning protected
data, not only at initial pairing.
Pairing uses an operator-issued, expiring, one-use capability for a specific
agent. Redemption checks current membership/role, feature prerequisites, agent
lifecycle, company/resource hints, expiry and revocation. Preview does not consume
the code. Grant creation, code consumption, and saving the binding reference must
be atomic. Otherwise setup can display ready while the scheduler still sees an
unpaired agent. Saving the form a second time is not an acceptable hidden step.
Persistent connection identity and per-turn mutation authority are different:
| Request | Expected behavior |
| --- | --- |
| Pair, inspect own capability/inbox status | Connection-scoped operation; no managed assignment needed. |
| Start work while idle | Durable, agent-attributed intake; ordinary admission before task mutation tools. |
| Read/accept offered assignment | Current binding and offer, explicit acceptance, no arbitrary run selection. |
| Invoke a task/app tool | Same admitted assignment and live permission checks; normal receipts/audit. |
| Update own optional avatar | Narrow self-only operation; do not grant generic agent-config authority. |
| Finish | Accepted canonical result, settled required operations, normal task finalizer. |
| Acknowledge a fence | Narrow control operation may remain available while task tools are denied. |
Idle intake must retain plugin/environment context from the configured application
services. In Dot, constructing a separate heartbeat service without the sandbox
plugin registry made idle requests fail even though operator-assigned work ran.
Test both entry points against the same managed environment.
## Durable state and operation contract
Persist distinct facts for grant/binding, subscription, mailbox item, assignment,
operation receipt, run/controller ownership, and final result. Avoid a single
boolean “connected” or “done.” Enforce active-assignment concurrency in storage
as well as the UI. Dot's initial contract allowed one active assignment per binding.
An illustrative lifecycle is:
```text
intake/admission pending -> offered -> accepted -> working -> result accepted
-> turn finished -> task disposition committed -> resource cleanup
```
Any active phase can instead become fenced, expired, failed, or reconciliation
required. These are conceptual states; use the repository's actual enums.
Every side-effecting external request needs a stable request identity plus an
argument digest and authority generation. Implement these semantics:
- Same identity + same arguments: return the same pending/settled receipt.
- Same identity + different arguments: reject a conflict.
- Completed intake retried: return its original receipt, never another task.
- Old authority generation: deny new execution, even if a historical receipt exists.
- Definite read failure: terminal bounded error; later tools and finish can proceed.
- Effect possibly happened but result was lost: explicit unknown/pending outcome
and reconciliation. Do not reissue under a fresh ID to make progress.
Persist reservation before effects where appropriate. Use existing transactional
mutation receipts and external-effect reconciliation. Do not promise universal
exactly-once execution across arbitrary remote services. Distinguish command
acknowledgment from completion of the tool's effect.
Do not block the Runner command lane waiting for a semantic tool result delivered
on that same lane. Reserve/admit promptly, deliver a pending receipt, then settle
with a correlated event. Bound pending operations, results, bytes, and authority
duration. Pagination and control acknowledgments must still work at limits.
Serialize mailbox cursor visibility with writers so a cursor cannot skip a result
whose transaction commits later. Wake events should contain references, not task
contents, credentials, or copied app data. An event receiver drains the durable
mailbox and validates current authority rather than trusting a stale event body.
Treat event callbacks as an authenticated protocol, not arbitrary URLs to POST to.
Use the provider's current ownership challenge and signing specification. Keep
callback signing material out of prompts, descriptors, logs and task data. Enforce
the callback destination policy, including redirect and DNS/IP handling, so a
subscription cannot turn the control plane into an internal-network request proxy.
Apply bounded delivery timeouts/retries and record failures without logging secrets.
Where receiving signed callbacks, validate the expected signature, timestamp and
replay policy before changing state. Test the actual directions this provider uses;
do not invent a symmetric webhook API merely because the integration is two way.
## Follow-up delivery must be coordinated with ordinary wake scheduling
A normal comment can enter two paths: active-assignment mailbox delivery and the
ordinary scheduler. If both remain independent, a finished bot can receive a
second assignment for a comment it already handled. If the normal wake is simply
discarded when the mailbox entry is made, the comment can be lost at completion.
The Dot fix retained the normal wake as deferred until the bot successfully read
that exact comment ID through `get_task_history`. Then the existing run consumed
it. If the assignment ended before the read, normal admission kept the unread
comment for another turn. An inbox reference or webhook acknowledgment did not
prove the comment was read.
Test both sides of this race, including controller recovery. Keep explicit new
session requests, interaction replies, and self-authored comments under their
normal policy; don't blanket-suppress every wake for a connected bot.
## Recovery needs identity evidence, not merely a reachable process
Record and compare the run, session, assignment, binding generation, controller
generation, managed lease, process marker, and trustworthy process birth identity.
On Linux the process fingerprint can include boot identity and start information.
Read remote identity from the sandbox, not a same-numbered PID on the controller.
Before advertising external work, require the evidence needed to recover it.
Recovery reads the checkpoint from the owning execution target and validates it
against saved authority. Missing/invalid state after dispatch fails closed for
reconciliation; a new process or conversation must not masquerade as a resume.
Incoming operations need a durable draining/replay mechanism owned by the current
controller. An in-memory forwarding optimization alone can leave valid requests
stranded after restart. Fence old controllers and callbacks so a late result
cannot overwrite the new generation's journal. Preserve late effect evidence.
A verified terminal/shutdown receipt can establish a clean exit when a remote
monitor lacks an exit code. An unexplained process exit still requires recovery.
Configure a bounded reconnect grace consistent with the deployment lifecycle;
Dot used five minutes after shorter restart gaps exposed failures. Do not copy
that number as a universal provider requirement.
Terminal run reconciliation must clear/fence a still-active assignment, notify the
bot, and release resources. Otherwise a failed run can block every future task
even though its old tools are already denied.
## Revocation and native powers are different boundaries
Cancellation, pause, reassignment, membership loss, expired run authority, and
grant revocation must prevent subsequent Paperclip effects. Cached tool results
or UI binding references cannot restore revoked access. Old-grant revocation must
not revoke a replacement binding accidentally.
Report “Paperclip authority revoked” separately from “external bot stopped.” A
fence acknowledgment proves receipt, not termination of all provider activity.
Likewise, sandboxing the Paperclip Runner does not confine the bot's native Slack
or provider computer. Those tools retain their own permissions. If strict total
capability isolation is required, use a suitably isolated bot/account and verify
the provider's actual controls; Paperclip cannot enforce it with prompt text.
## Files and commands are a separate capability decision
Do not add workspace tools merely to make an external agent look like a coding
CLI. A bot can research or write code on its own computer without Paperclip
workspace access. The first Dot Cloud release intentionally offered none.
When the release includes workspace tools:
- Resolve paths within the admitted workspace; reject traversal, absolute paths,
symlinks/escapes, and Paperclip instance state such as `.paperclip`.
- Check reads, writes, API downloads, uploads, and artifact publication. A generic
`call_api` path must not bypass attachment/workspace grants.
- Serialize optimistic hash checks with writes. Two concurrent writes must not
both commit against the same observed hash.
- A process working directory is not a sandbox. Use a proven OS/container boundary;
test outside-workspace access, environment secrets, detached descendants, timeout,
cancellation and cleanup. No unrestricted fallback when confinement is unavailable.
- In the historical Dot implementation, Linux used bubblewrap/private PID
namespaces. macOS command execution was disabled after detached descendants
escaped reliable supervision; file tools and artifacts remained available.
- For attachments, enforce current task/company, bounded pages and total bytes,
integrity checks, and live revocation before returning each page. Treat filenames
and contents as untrusted data. Test the generic API escape path too.
## Paperclip implementation anchors
Paths below existed in the qualified October 9 candidate. Locate their current
equivalents before editing; do not paste line numbers from historical notes.
| Concern | Historical anchor |
| --- | --- |
| Bot broker and tool definitions | `server/src/services/dot-runner-broker.ts` |
| Prototype public MCP bridge | `server/src/services/public-mcp/dot-runner.ts` |
| Rust assignment backend | `packages/paperclip-runner/runner/crates/runner-core/src/dot_provider_backend.rs` |
| TypeScript Runner driver | `packages/paperclip-runner/src/drivers/dot/runnerd-dot-driver.ts` |
| Driver/backend selection | `packages/paperclip-runner/src/backends/native-backend-factory.ts` |
| Per-turn instructions | `packages/paperclip-runner/src/backends/runtime-context.ts` |
| Governed tool authority | `server/src/services/native-runtime/paperclip-runner-tool-authority.ts` |
| Admission, wake, terminal reconciliation | `server/src/services/heartbeat.ts`, `server/src/services/heartbeat/queue.ts`, `server/src/services/heartbeat/run-lifecycle.ts` |
| Real Rust/DB and managed qualification | `server/src/__tests__/dot-runner.test.ts` |
Keep the standalone Runner package independent of server/DB implementation
imports. Extend the actual production backend and negotiated capability contract,
not just a convenient reference harness.
@@ -0,0 +1,215 @@
# Troubleshooting, test environments, and Cloud delivery
## Contents
- [Start with the failing boundary](#start-with-the-failing-boundary)
- [Stable public ingress is part of the test fixture](#stable-public-ingress-is-part-of-the-test-fixture)
- [Concrete OAuth and routing checks for the Dot implementation](#concrete-oauth-and-routing-checks-for-the-dot-implementation)
- [Symptom → discriminator → next action](#symptom--discriminator--next-action)
- [Keep one reproducible environment manifest](#keep-one-reproducible-environment-manifest)
- [Coordinate all Cloud pieces](#coordinate-all-cloud-pieces)
- [Classify a failure before retrying](#classify-a-failure-before-retrying)
- [Close the environment deliberately](#close-the-environment-deliberately)
## Start with the failing boundary
Do not use “OAuth is broken” for every setup failure. Trace these independent paths:
```text
A. Provider backend -> public origin -> discovery, MCP, token exchange
B. Provider browser -> authorization page -> preview/consent -> provider callback
C. Agent runtime -> loaded plugin actions -> authenticated read/tool calls
D. Paperclip event worker -> verified callback -> bot wake -> mailbox/challenge
E. Paperclip scheduler -> managed lease -> Runner -> tools -> finalizer -> cleanup
```
For each, collect a timestamp, exact failing operation, status/visible error,
correlated access log, and which party observed it. The developer's browser, the
provider's browser, and the provider's backend can have different reachability.
An absent request in complete ingress logs means that attempt did not reach the
app; it does not identify the upstream blocking rule.
## Stable public ingress is part of the test fixture
Prefer one stable HTTPS origin on port 443 reachable by both provider clients.
Keep issuer/resource, token exchange, authorization redirect, and callback
configuration consistent. Do not rotate tunnel hostnames as the first response to
every failure: each new URL can require a different plugin, fresh registration,
new pairing prompt, and subscription cleanup.
Self-hosted testing may need a tunnel or authorized public reverse proxy. Dot
eventually used a stable public proxy forwarding to the test machine. That is an
observed useful arrangement, not a requirement to provision new infrastructure
for every integration. Use the user's supported deployment/network options.
Tailscale-specific diagnostic: local MagicDNS may resolve a hostname to a private
tailnet address while outside clients use Funnel. Test public ingress independently;
local curl success does not establish public access. Tailscale Serve and Funnel
have different reachability. Never infer a provider port ban from one timeout.
`ERR_BLOCKED_BY_CLIENT` alone does not identify Cloudflare or a server bot filter.
Use server logs and the actual consent page, not only `/api/health`: Dot once
blocked the health navigation while the required sign-in page loaded. Do not
bypass browser security warnings or a provider's access controls. Use supported
configuration or an authorized reachable endpoint and preserve the exact uncertainty.
## Concrete OAuth and routing checks for the Dot implementation
These routes describe the October 9 candidate; discover current equivalents.
| Surface | Historical expectation |
| --- | --- |
| `/mcp/runner` unauthenticated | `401` and `WWW-Authenticate` with resource metadata; not an HTML sign-in page. |
| `/.well-known/oauth-protected-resource/mcp/runner` | Public JSON for the exact resource and authorization server. |
| `/.well-known/oauth-authorization-server/mcp/runner/oauth` | Public JSON for issuer and endpoints. |
| `/mcp/runner/oauth` | Dedicated agent-resource issuer; personal MCP issuer remained separate. |
| `/dot-connect/:requestId` | Public pairing page, scoped by request and one-use pairing capability. |
| `/api/dot-mcp/requests/:requestId` and exact pairing operations | Publicly routable aliases with request/code checks; reject personal assistant request IDs. |
| Normal board, connection management, ordinary personal consent | Retain normal session/role requirements. |
For read-only health checks, substitute the configured origin; do not send tokens:
```sh
curl --max-time 15 -sS -D - -o /tmp/dot-resource-metadata.json \
'https://YOUR_CONFIGURED_ORIGIN/.well-known/oauth-protected-resource/mcp/runner'
curl --max-time 15 -sS -D - -o /tmp/dot-auth-metadata.json \
'https://YOUR_CONFIGURED_ORIGIN/.well-known/oauth-authorization-server/mcp/runner/oauth'
```
Inspect JSON and redirect behavior, then exercise the actual provider discovery.
Do not interpret these curl checks as provider qualification. Keep browser cookies
and tokens out of pasted logs; use the existing authenticated test client when a
protected operation must be inspected.
ChatGPT's historical client metadata preferred `private_key_jwt` while also
advertising `none`. Paperclip originally rejected it instead of negotiating its
supported public-client method with PKCE. Inspect the complete advertised methods;
do not disable authentication or exact redirect/resource validation to work around
a preference mismatch. Keep S256 PKCE and current registration checks.
An optional `PAPERCLIP_MCP_AUTHORIZATION_ORIGIN` supported a different authorized
browser ingress to the same instance, while `PAPERCLIP_PUBLIC_URL` retained the
MCP resource/issuer/token origin. This was a workaround for different client
reachability, not an OAuth requirement. Use only explicitly configured trusted
origins and verify callback/CSRF/issuer behavior. Prefer a single working origin.
## Symptom → discriminator → next action
| Symptom | Evidence to inspect | Action and proof |
| --- | --- | --- |
| OAuth discovery times out | Public metadata vs actual provider access logs | Fix the failing ingress/client path; do not keep editing valid metadata when no request arrives. |
| Unknown client or redirect URI after restart | Persisted registration vs provider's cached client | Restore the intended persistent fixture or re-register through supported setup. Do not reset DB repeatedly. |
| Invalid request ID | Actual ID representation | Treat protocol IDs as opaque unless contract says otherwise; the lab incorrectly required a UUID. |
| Grant exists but provider is not connected | Complete same browser flow through callback/token exchange | A server grant row alone is not completed OAuth. Avoid mixing separate callback sessions. |
| Tools listed in settings, absent to bot | Actual tool invocation in active conversation | Supported refresh/attach/restart, bounded once per diagnosis; preserve endpoint and mark intervention. |
| Subscription verified but no bot action | Delivery record, mailbox, challenge/acceptance receipt | Separate callback receipt from model execution. Report latency; inspect actionable work before resending. |
| Ready connection, task admission says unpaired | Saved agent binding/config revision | Fix atomic pairing persistence; do not require another manual form save. |
| Agent created paused before pairing | Lifecycle preparing/verifying vs manual pause | Use lifecycle-specific setup eligibility; preserve actual pause/approval gates. |
| Anonymous consent spins/reloads | Background session probes returning expected 401 | Public consent must tolerate them without global reload; protected board routes retain session recovery. |
| Ordinary assignment works, idle work cannot acquire sandbox | Service construction / plugin context | Use app-configured admission service and test both entry points. |
| Remote Runner connects to localhost | Launched transport endpoint vs private managed ingress | Use the authenticated remote transport supplied by the execution target. |
| Image lacks provider support | Actual packaged Runner digest/capabilities | Fail before dispatch; publish compatible artifact and test installed path. |
| Recovery finds sandbox but no process identity | Marker, fingerprint and original checkpoint | Capture identity before dispatch; reconcile missing evidence rather than launch replacement work. |
| Remote PID has implausible start time | Whether controller inspected its own PID table | Obtain birth identity from the remote sandbox, not a colliding local PID. |
| Finished task starts again after comment | Mailbox + scheduler wake receipt | Consume only when exact comment read succeeds; test unread-at-finish and read-before-finish. |
| Missing file leaves run waiting forever | Pending tool receipt and error dispatch | Settle definite read failures; preserve unknown outcome only for genuinely ambiguous effects. |
| Terminal run blocks all new tasks | Assignment still active despite terminal run | Reconcile/fence it and release resources without claiming external stop. |
| Cancelled job has creating/pending-cleanup sandbox | Provider allocation and deletion receipts | Track until destroyed or explicitly pending with owner; retry only per provider semantics. |
| New deployment vanishes mid-test | Fleet auto-rollout vs direct candidate | Use supported test-tenant pinning with authorization; record current serving revision. |
## Keep one reproducible environment manifest
Before a test drive or deployment, resolve current worktree/artifacts and reuse a
suitable isolated checkout. Do not reset the user's primary checkout. Create a new
managed worktree when appropriate, preserving unrelated work. Record:
```text
Repository / worktree / branch / app SHA:
Runner artifact platform / digest / advertised capabilities:
Ingress repository / SHA / relevant routing version:
App image / immutable digest:
Local host / port / data directory / process ownership:
Public origin / authorization origin / forwarding target:
Tenant / company / agent identifiers (private evidence only):
Sign-in entry and credential reference (no secret values):
Grant/binding status / subscription / pending code expiry (no code value):
Current case / run / assignment / lease:
Owner of each server, proxy, build, sandbox, and cleanup:
Environment retention agreement / next gate:
```
Use synthetic fixtures, not a production database clone containing private company
data or signing keys. Verify launcher arguments, selected instance, port mapping,
and data persistence after restart. A label such as `default` is not proof of
process ownership. Never kill unrelated databases or clear shared IPC globally.
If resource pressure blocks the fixture, inspect owned processes or use the
approved remote test path; preserve unrelated sessions.
Verify sign-in is usable before handing over a URL. Deliver access/resume details
through an appropriate private path. If the user is still testing or the bot is
loading tools, keep the endpoint alive under the agreed bounds. Stopping it made
the first “tools unavailable” diagnosis premature. Announce an intentional expiry
and explain how to resume; do not assume a stopped shell process remains a service.
## Coordinate all Cloud pieces
Cloud qualification requires the tenant app, public ingress, managed provider
plugin/configuration, and packaged Runner artifact. The UI flag alone is not
enablement. Inspect guards in UI, scheduler, backend, remote launcher, and Cloud
front door. Use scoped route exceptions that retain endpoint authentication rather
than removing browser-session guards wholesale.
Pairing and MCP must remain reachable without a managed job. If a sleeping tenant
returns a waking-up page, wait for the actual lifecycle transition, then test the
correct metadata response. Delay creating expiring pairing codes until the tenant
image is deployed and serving. A 3.4 GB image transfer consumed meaningful setup
time during Dot qualification; do not burn the code's lifetime watching a build.
Record whether a test overrides the sandbox binary with a locally built artifact.
That proves the code can run, not that the published default image is correct.
Match platform and provider capability; a Mac controller's current binary cannot
stand in for a Linux sandbox artifact. Digest/capability checks should fail clearly
before an assignment is offered.
For the historical private `paperclip-cloud` repository, the supported targeted
deployment CLI was `scripts/deploy-stack.mjs <workspace-url> <ref> --plain`, with
`--resume <request-id>` for the same operation. Inspect current help/runbook before
using it. Do not invent or replay old tenant IDs, deployment requests, or secrets.
Preserve one request through prepare/build/check/deploy/verify; duplicated requests
make provenance and recovery harder. No fleet-default change is implied by a
single test-tenant deployment.
## Classify a failure before retrying
- **Product:** deterministic missing context, bad state transition, wrong endpoint,
lost receipt. Reproduce, fix, and rerun the affected contract.
- **Provider:** tool loading, wake delay, refusal, unsupported control. Capture the
actual provider result and test a supported recovery; don't manufacture success.
- **Infrastructure:** capacity, registry 429/504, image transfer, npm resolver,
provider allocation. Verify whether work/effects started; use bounded recovery.
- **Evidence/test:** controller didn't restart, stale build, nonce visible in prompt,
wrong image, scripted client presented as real. Correct the experiment.
For an unchanged transient build failure, one targeted infrastructure retry is a
reasonable initial bound. If it fails again, report the precise remaining gate
or investigate the new cause; do not loop reruns or change registry/security
configuration without a task-grounded reason. Resume the existing deployment.
If code changes, re-evaluate which earlier evidence applies to the new candidate.
Keep broad test runs tied to a frozen revision. Stop superseded owned runs when
safe, retain their results, and run the affected suites plus required final gates.
Do not claim a full local suite passed because failing tests passed individually;
state focused results and final CI separately.
## Close the environment deliberately
After the final task, inspect leases and actual provider resources. Expired lease
status alone is weaker than a successful sandbox deletion receipt. Preserve a
requested review instance with access and resumption information; release owned
disposable compute. For an authorized reset, account for provider account link,
Paperclip binding/grant, event subscription/automation, and cached configuration.
Disconnecting one layer can leave an enabled provider automation behind.
Report qualified, review-ready, merged, deployed, and canary-verified separately.
Never say an instance received a fix until its serving revision and relevant
ordinary-use behavior establish it.
@@ -44,6 +44,11 @@ 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 Paperclip, add navigation metadata to each feature recipe as described in the
map contract. Discovery generates the indexes; do not register new features in a
central table or commit generated catalogs. Keep review/run evidence in the PR
or evidence report and use Git for source history.
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
+189
View File
@@ -0,0 +1,189 @@
---
name: fix-slow-queries
description: >-
Diagnose and fix slow Paperclip PostgreSQL queries using Cloud and Neon evidence,
local reproduction, performance and result comparisons, regression tests, and
a PR with passing checks. Use for costly queries, repeated database work, or
slow requests with a suspected database cause.
---
# Fix Slow Queries
Deliver a measured improvement with preserved behavior and a reviewable PR whose
latest commit passes checks. A list of suspicious SQL or an unverified rewrite
is an intermediate result. Respect a narrower request for diagnosis only.
## 1. Establish the target and finish line
- Resolve the reported URL, environment, company/workspace, deployed revision,
owning repository, and local checkout. Read its `AGENTS.md` and scoped rules.
Paperclip and the private `paperclip-cloud` control plane have different rules.
- Work in a dedicated branch/worktree. Reuse suitable existing work; keep the
checkout running a live server out of branch switching and benchmark setup.
- Select a bounded batch, usually the top two or three query families. Record
deferred candidates so discovery does not turn into an unbounded rewrite.
- The finish line is: reproducible baseline, faster treatment, output/behavior
proof, relevant regression coverage, and green checks on each final PR head.
A concrete access or infrastructure blocker must be reported as incomplete.
## 2. Find the actual database and rank the work
Read [Cloud discovery](references/cloud-discovery.md) when starting from a hosted
workspace. Follow the chain from Paperclip Cloud fleet admin to the stack's Neon
project, branch, endpoint, database, and runtime role. Record the corresponding
application deployment and time window. Do not reuse IDs from a previous run.
Capture query text/fingerprint, calls, total execution time, mean time, rows,
and available I/O, temporary-file, and lock-wait evidence. Rank both expensive
individual calls and frequent work with high aggregate cost. Group variants by
their actual caller; do not add unrelated query means into an endpoint latency.
Keep three claims separate:
| Claim | Evidence needed |
| --- | --- |
| SQL is expensive | Query statistics and a reproducible execution plan |
| The database path dominates a slow request | Correlated SQL, connection wait, and application timings |
| More database capacity would help | Resource/queue pressure in the same window and a capacity-specific experiment |
Cumulative query statistics are not a recent-window trace. Capture reset times
or two snapshots and calculate deltas. A large database-time total alone does
not justify resizing Neon. Application CPU headroom also does not rule out a
busy Node main thread.
## 3. Trace each candidate to its behavior
Use `rg` on distinctive SQL fragments, table names, JSON keys, and predicates.
Trace the full path: route or scheduler → service → generated SQL → indexes.
Record frequency, fan-out, page limits, redaction, authorization, and any second
query the caller performs. Compare the deployed implementation with local code.
State a falsifiable cause and the contract the fix must preserve. Typical causes
include casts on indexed columns, repeated detoasting of large JSON, broad
candidate scans, unbounded result sets, duplicate reads, and unnecessary polling.
Use plans and caller evidence to choose among them.
Inspect existing indexes and recent related fixes before adding another index.
For advisory locks, identify the caller, key, transaction duration, and wait
chain first. Preserve checkout, leases, ownership, recovery, and no-replay rules;
removing a lock or polling loop is not a query optimization by itself.
## 4. Reproduce the baseline locally
Read [Local proof](references/local-proof.md) before building or changing the
benchmark. Use disposable real PostgreSQL and synthetic data with representative
row counts, selectivity, and payload sizes. Record the PostgreSQL version and
any difference from the hosted server.
Pin the pre-fix commit. Capture the complete SQL and parameters the real service
generates, including projections, joins, ordering, limits, and relevant imported
query helpers. Prove the baseline exhibits the suspected cost before editing.
If it does not, improve the fixture or revise the hypothesis.
Save baseline results, timings, and `EXPLAIN (ANALYZE, BUFFERS, FORMAT JSON)`.
Define the performance acceptance criterion for this fixture before measuring
the treatment. Avoid a brittle universal millisecond threshold.
## 5. Implement and prove both kinds of green
Make the smallest change supported by the measurements. Author the fix on our
branch from source and evidence. Related community reports can supply leads;
respect any instruction to keep the implementation independent of their code.
Run baseline and treatment against equivalent fixtures under the same settings:
- **Performance:** use warmups and repeated samples, report medians and spread,
and examine plan/buffer changes. Alternate order or repeat in reverse order
when caching could explain the gain. Report neutral or slower paths honestly.
- **Correctness:** compare every returned SQL column and the externally visible
behavior. Preserve ordering, duplicates, nulls, tenant scope, and redaction.
A faster wrong result fails even when row counts match.
When intentionally bounding history, compare query speed at the same result
limit separately from the contract change. Test default/max limits and older
record access. Do not call truncated output equivalent to the former full list.
Reject or revise the change if either proof fails. Keep the reproducible harness
with the source where repository conventions allow it; keep bulky evidence out
of git. Exhaust viable query/caller changes and existing indexes before proposing
an exceptional migration. Document the serious reason and why migration-free
alternatives are insufficient. Do not add startup scripts, boot-time DDL, or
recurring backfills to bypass the migration constraint.
If a migration remains necessary, follow the database migration rules and the
production-size timing procedure in [Local proof](references/local-proof.md).
Measure the complete migration, including index builds, backfills, and lock waits.
First optimize a migration exceeding the roughly one-to-two-minute budget; if
it cannot be brought within an acceptable duration, flag it for human review
with the measured timings and alternatives before presenting it as deployable.
## 6. Verify the blast radius
Choose checks from the caller graph and affected contracts, not only the edited
function. Relevant cases from this workflow include:
| Change | Regression evidence |
| --- | --- |
| UUID/JSON joins | Canonical, uppercase, malformed, missing and non-string IDs; native/legacy precedence; company scope |
| JSON projections | Scalar/array/object/null inputs, text conversion, all fields, redaction |
| History bounds | Service and route callers, UI/API defaults, older deep links, empty recent history, retry and navigation races |
| Ownership/recovery reads | Retained processes, active leases, blocked replay, workspace failure, receipts and delivery |
| Polling/caching | Idle work reduction, committed-change wakes, missed events, restart/sleep recovery, fresh destructive checks |
Use real database tests for SQL semantics. Exercise assembled services/routes
and actual UI components when those are affected. Update query mocks when the
builder shape changes; a broken mock is not evidence that runtime SQL is wrong.
Run focused checks first, then the owning repository's required pre-PR checks.
For this repo, consult `AGENTS.md` for typecheck, full tests, build, and conditional
map/token/migration gates. Capture command, commit, exit status, and log location.
Do not call an interrupted suite a pass. Preserve its partial evidence and state
what completed locally versus on the final commit in CI.
## 7. Create the PR and carry it through checks
Use [prepare-paperclip-pr](../prepare-paperclip-pr/SKILL.md) for public Paperclip
changes, [check-pr](../check-pr/SKILL.md) for feedback, and
[prcheckloop](../prcheckloop/SKILL.md) for checks. Follow the owning repository's
workflow instead when the fix belongs in `paperclip-cloud`.
- Use the full PR template. Include cause, contract, benchmark command, baseline
revision, fixture, before/after timings, equality evidence, regression results,
and remaining risks. Label synthetic local timings as local SQL measurements.
For an exceptional migration, include its justification, production-size fixture,
complete duration, blocking time, optimization attempts, and any human decision
still needed. Query speedup does not establish acceptable migration cost.
- Split independent fixes into independently reviewable PRs; disclose actual
dependencies. Attach every created PR to the current chat/task where supported.
- After each push, refresh the head SHA. Address actionable reviews and failures,
rerun affected local proof, and wait for fresh review and all expected checks
on that SHA. Follow this repo's Greptile 5/5/no-unresolved-findings requirement.
- Distinguish code failures from runner shutdowns or external outages. Rerun a
demonstrated transient failure once. Cancel obsolete runs only after verifying
they belong to this work and an older head; never terminate unrelated jobs.
- Do not finish with "CI pending." Continue the loop within its repair bounds,
or report the exact blocker, check URL, attempts, and next action. An empty
check list, an old review score, or a draft-only subset of checks is not green.
Thanking contributors and closing their PRs requires explicit authorization.
When authorized, explain which report our verified PR covers, acknowledge any
uncovered scope, and leave unrelated PRs open. This skill does not itself grant
permission to comment, close, merge, deploy, resize, or mutate a hosted database.
## Constraints
- your solution should not require a migration script to be run unless there is a serious reason - in almost all cases a migration script is a non starter
- similarly you should not add some new boot script - e.g. dont' work around migration scripts by running the migration on every boot
- if you add migrations, you should also have a sense on the time it will take on a large paperclip instance with thousands of tasks. the best option is to test on a clone of a production-size database and time it. if you don't have that you should make one. migrations that take an unacceptably large time to run (e.g. more than 1 or 2 minutes) must be flagged - first try to optimize the migration and then flag for a human if that's impossible
## 8. Hand off the evidence
Report each PR URL and final head, measured gains and neutral paths, correctness
comparison, completed local checks, latest-head CI/review status, and limitations.
If working from a Paperclip issue, attach evidence/work products using the
repository's artifact workflow. Keep private identifiers and tenant data out of
public PRs. State whether anything was deployed.
If rollout is authorized, verify the deployed revision and compare a fresh,
comparable query-statistics window and request timing. Until then, production
latency improvement remains unverified even when local SQL is much faster.
@@ -0,0 +1,3 @@
interface:
display_name: "Fix Slow Queries"
short_description: "Trace cloud SQL hotspots through local proof and green PRs"
@@ -0,0 +1,119 @@
# From a slow workspace to its queries
Use this reference for hosted Paperclip investigations. Resolve current resources
and credentials from the authorized environment; the examples describe lookup
shapes, not fixed account, stack, or project IDs.
## Resolve the cross-service identity
1. Start with the reported workspace URL and affected user action. Record UTC
observation times, environment, and a representative slow request. A fast
health endpoint does not establish that task/run endpoints are fast.
2. Open the authorized Paperclip Cloud fleet-admin stack record matching that
URL. Match its domain and workspace identity, not only a friendly name.
3. In stack details, inspect the database provider resources and **Open in Neon**
link. Record project, branch, endpoint/compute, database, and runtime role.
Provider refs may be CloudOps-only. Do not infer them when they are redacted.
4. Record the application provider's project, environment, service, active
deployment/revision, and region. On Railway these identify the logs and
metrics to compare with Neon. A stack can move after reprovisioning.
5. Confirm the database connection's actual database and role before querying.
Keep private mapping details in restricted evidence, not public PR bodies.
Use available provider connectors or CLIs first; the authenticated browser is
useful for fleet-admin resource links and Neon monitoring. If tool access is
missing, inspect the authorized `paperclip-cloud` checkout and its instructions.
Relevant files, relative to that repository:
- `docs/cloud-harness-app-paperclip-cloud-runbook.md`: provider credentials and
secret-store rules.
- `src/providers/neon.ts`: project/branch/role mapping and connection URI lookup.
- `src/providers/railway.ts`: provider API and metrics/log access.
- `web/src/admin/routes/StackDetail.tsx`: displayed provider resource mapping.
Discover its path from the current project context; do not assume a developer's
home directory or copy their AWS profile. Verify the account/environment against
the current runbook. Staging and production secret stores are distinct.
## Open a bounded read-only diagnostic connection
Prefer the scoped runtime connection secret already recorded for the stack.
When authorized operator access is needed, the provider's connection lookup uses
`GET /projects/{projectId}/connection_uri` with `branch_id`, `endpoint_id`,
`database_name`, `role_name`, and `pooled=true`; verify against the current provider
implementation. Pass returned credentials directly in memory to the client.
Load only necessary secret fields. Never print connection URIs, secret values,
or credential-bearing error objects; never put them in command arguments,
repository `.env` files, evidence, or PRs. Query text and parameters can also
contain tenant data. Keep full SQL privately only when necessary and sanitize
before publishing; simple literal replacement is not complete redaction.
Set a recognizable diagnostic `application_name`, connection timeout, short
statement/lock timeouts, and read-only transactions. Example session:
```sql
BEGIN READ ONLY;
SET LOCAL statement_timeout = '10s';
SET LOCAL lock_timeout = '1s';
SELECT current_database(), current_user, version();
SELECT extname FROM pg_extension WHERE extname = 'pg_stat_statements';
COMMIT;
```
Do not install extensions, reset shared statistics, change capacity, or run
schema/data changes as a side effect of diagnosis. `EXPLAIN ANALYZE` executes
the query; keep that work on the local fixture unless the live execution has
been separately justified and authorized. Plain `EXPLAIN` is the lighter live
option when permitted. Read-only SQL can still impose load; bound each probe.
## Obtain historical and current evidence
In Neon, select the confirmed branch, endpoint, and database, then inspect
**Monitoring → Query performance** and **Monitoring → Metrics**. UI labels can
change; use the observed navigation. Preserve the source link and capture time.
When SQL access to `pg_stat_statements` is available, this supplies a first cut:
```sql
SELECT userid, dbid, queryid, calls, total_exec_time, mean_exec_time,
max_exec_time, rows, shared_blks_hit, shared_blks_read,
temp_blks_written, query
FROM pg_stat_statements
WHERE dbid = (SELECT oid FROM pg_database WHERE datname = current_database())
ORDER BY total_exec_time DESC
LIMIT 20;
```
Do not interpret an absent/inaccessible SQL extension as proof that the Neon
console has no query history. During this investigation the console supplied
history when the runtime connection could not query `pg_stat_statements`.
Without either source, take bounded samples of `pg_stat_activity` and scoped
application timings; label them samples, not complete historical attribution.
For interval statistics, save two snapshots in separate transactions. Match
database, user, query ID and, where exposed, top-level status. Compute
`delta_total_exec_time / delta_calls` only for positive calls and compatible
reset epochs. Counter decreases, resets, or evicted/reappearing entries invalidate
that interval comparison. Record `pg_stat_statements_info.stats_reset` when
available. Mean/max values do not provide p95; p95 needs individual samples.
Useful supporting observations:
| Surface | Read | Interpretation |
| --- | --- | --- |
| Neon metrics | CPU allocation/usage, RAM, cache/working set, pooler wait, connection count | Correlate with the slow-request window before attributing capacity pressure |
| `pg_stat_activity`, `pg_locks` | Active query age, wait events, blockers, transaction age | Lock waits and long transactions need caller attribution |
| `pg_stat_database` | Transaction, block, temporary-file and deadlock deltas; stats reset | Cumulative counters need an interval; reported I/O time depends on tracking settings |
| `pg_stat_user_tables` | Scans, rows visited, live/dead estimates, analyze/vacuum times | Investigate broad reads and stale statistics; estimates are not exact row counts |
| Railway/app logs | Endpoint duration, background-job frequency, deployment | Separate request work from recurring maintenance |
| Traces/error system | SQL spans, pool/connect waits, errors scoped to the stack | Missing traces are not proof of zero database time |
Measure connection establishment separately from several `SELECT 1` round trips.
These show network/pool overhead; they do not measure a business query. Likewise,
low total container CPU does not exclude Node event-loop saturation, and a busy
background query does not prove it caused a particular slow page.
Produce a short ranked table: caller/query family, calls or call rate, mean SQL
time, total SQL time, observation window/reset caveat, suspected cause, and next
local experiment. Choose the bounded batch from this table.
@@ -0,0 +1,183 @@
# Local performance and correctness proof
The test must answer both questions: does the changed query do less work, and
does the surrounding feature still behave correctly?
## Start from the existing harnesses
Search `scripts/benchmark-*.ts` and `packages/db/src` before creating a harness.
This work produced these examples; use those present in the current checkout:
- `scripts/benchmark-slow-queries.ts`: chat notices, provenance, redaction,
candidate indexes, and an unchanged history control.
- `scripts/benchmark-run-history.ts`: baseline service loading, captured history
SQL, wide JSON projection, complete positional-row comparison.
- `scripts/benchmark-recovery-queries.ts`: ownership/blocker/delivery queries and
baseline helper dependency isolation.
- `startEmbeddedPostgresTestDatabase` from `@paperclipai/db`: disposable real
PostgreSQL lifecycle, used by these benchmarks and service integration tests.
Inspect a harness before running it. Use disposable synthetic fixtures by default;
for exceptional migration timing, use an authorized isolated production-size clone
or create an equivalent production-size database as described below. Do not reuse
the developer's persistent database or a live cloud `DATABASE_URL`. Planner,
index, UUID, and TOAST claims need real PostgreSQL, not mocked query builders.
Prefer the hosted major version when practical and disclose version differences.
Set `SLOW_QUERY_BASELINE` to a verified pre-fix commit and pass it explicitly:
```sh
pnpm --filter @paperclipai/server exec tsx ../scripts/benchmark-run-history.ts --baseline-ref="$SLOW_QUERY_BASELINE"
```
Resolve the ref to a SHA in the report. `origin/master` may already contain the
fix after merge, so it is not a durable historical baseline. Capture treatment
SHA plus any uncommitted diff, dependency versions, DB settings and fixture size.
## Capture the query actually used
Invoke the real service/query builder and capture `.toSQL()` plus parameters at
execution. Stop before dispatching notifications or starting runs. If the
service reads an issue before an expensive action query, capture the correct
subsequent query and include the first read in an endpoint benchmark if claimed.
Do not benchmark only an exported eligibility predicate and label it a complete
blocker query. Projections, joins, ordering, limit, and intermediate result sets
can materially change the result. Measure application post-processing separately
if the claim includes redaction or end-to-end request latency.
Load baseline source with `git show` or a separate checkout. When dynamically
loading old modules against current dependencies, include every changed helper
that can affect SQL. An old recovery module importing the new conversation
helper contaminates the baseline. Record which dependencies were held constant.
For index-only changes, use the same SQL in both treatments. Isolate index sets
in disposable databases or explicitly toggle only candidate indexes there;
record the definitions. Never drop indexes on a live database for a benchmark.
## Construct a fixture that exercises the cost and the contract
Match the mechanism observed in the cloud: candidate counts, match selectivity,
status distribution, tenant distribution, history depth, and payload width.
Include a small control and a representative stress case when size changes the
plan. Run `ANALYZE` after loading equivalent data.
For large JSON, repeated filler compresses unrealistically well. Use synthetic
incompressible content so TOAST reads resemble the actual workload. The original
fixture used 1,400 runs with approximately 192 KiB contexts; these are examples,
not universal sizes. Historical resolved recovery actions also matter: an empty
or tiny action table can hide the expensive join.
Fix timestamps and distinguish ordering ties. Include cross-company decoys,
empty results, duplicates, missing JSON keys, null/scalar/array/object contexts,
malformed/noncanonical IDs, and conflicting native/legacy bindings where the
affected contract permits them. Seed only relevant cases in each test.
## Keep complete results
Compare positional rows, for example `postgres.js` `.values()`, or give every
projection a unique alias. Object rows can overwrite duplicate column names,
silently hiding changed values. Matching row counts or IDs alone is insufficient.
Compare exact order where the API promises it. Otherwise compare multisets of
complete rows, preserving duplicates; do not sort away a pagination bug. Keep
parameter values, company/user scope, limits, and stable clock inputs equivalent.
Assert equality outside the timing interval and fail the harness on mismatch.
For intentional behavior changes, specify an explicit oracle. A bounded history
API may return fewer rows by design; prove those are the correct ordered page,
that requested limits are honored/clamped, and that older by-ID navigation still
works. Benchmark projection changes with the same limit on both versions.
## Measure and decide
1. Confirm baseline results and the suspected slow plan before applying the fix.
2. Warm both versions. Use several measured iterations; start with two warmups
and at least five timed samples, expanding if the result is noisy.
3. Record all samples, median and range or quartiles. Alternate baseline/treatment
or repeat in reverse order to check cache bias. Keep noisy full-suite/build
work out of the timed interval. Do not claim cold-cache results from warm runs.
4. Capture `EXPLAIN (ANALYZE, BUFFERS, FORMAT JSON)` on the local fixture outside
ordinary timing samples. Inspect actual rows/loops, filtering, sorts/spills,
buffer accesses, and index use. Explain why the plan supports the measured gain.
5. Report baseline/treatment medians, speedup `before / after`, row equality,
sample count, and limits of the claim. If spread overlaps materially, repeat
or label the result inconclusive rather than selling a small fluctuation.
Keep semantic assertions in deterministic regression tests. Keep noisy timing
thresholds in the explicit benchmark unless the CI performance environment is
controlled. A test proving an index exists is weaker than real SQL results plus
plan/performance evidence. A proposed optimization can be neutral or slower:
our initial status-delivery rewrite repeated JSON reads and regressed until it
was simplified; the final path was reported as neutral.
## Time an exceptional migration at production size
Migrations are normally a non-starter for this workflow. First establish the
serious reason one is unavoidable and why query rewrites, existing indexes, or
caller changes cannot solve the problem. New boot scripts or startup migrations
are not an alternative to that requirement.
Prefer an authorized, isolated clone of a production-size database. If none is
available, create a production-size test database rather than timing a tiny
fixture: thousands of tasks plus representative related runs, events, comments,
JSON payloads, indexes, and history depth for the tables the migration touches.
Use observed aggregate sizes/distributions to size synthetic data when a real
clone is unavailable. Keep copied tenant data in its approved environment and
out of logs, fixtures committed to git, and public PRs.
Run the actual migration through its normal runner against the pre-migration
schema. Record total wall-clock time and per-step duration, including index
builds, backfills, lock waits, and commit. Record table/row sizes, PostgreSQL
version, compute/storage characteristics, and blocking time under representative
concurrent reads/writes where relevant. A concurrent index build can still take
too long even when it does not block writes. A fast laptop run is not proof of
an equally fast deployment on smaller compute.
Restore the starting state before timing an optimized version; an already-applied
or resumable no-op is not a first-run measurement. Also test interrupted execution
and rerun safety where applicable. Report first-run and rerun timings separately.
Treat durations above roughly one to two minutes as a flag, not an acceptable
cost to hide behind a query speedup. First optimize and repeat the production-size
timing. If an acceptable duration cannot be achieved, flag it for a human with
the serious reason, measured duration/blocking, attempted improvements, and
alternatives. Do not move the work into boot, run it against the live database,
or label the migration ready to deploy while that decision remains unresolved.
## Anticipate the compatibility traps
- Casting JSON text to UUID can reject malformed values or broaden matches for
uppercase/noncanonical text. Preserve the former text-comparison semantics
deliberately; guard casts and keep the indexed UUID side unwrapped.
- A native first-class ID may take precedence over legacy JSON. Do not change
fallback order, cross-company access, or ownership holds while improving joins.
- A single JSON expansion must preserve legacy `->>` conversions and non-object
inputs. Returning fewer projected keys can break redaction or downstream UI.
- History limits can break older deep links. Verify the actual run panel with
an older selected run, including an empty recent list, fetch failure/retry,
company/agent mismatch, and navigation while a lookup is pending. Check all
shipped page variants and relevant desktop/mobile branches.
- Query-builder mocks may need new joins, but mock updates do not replace a real
database test or justify removing a retry/disconnect regression test.
If PostgreSQL startup or a broad suite hits local shared-memory/resource limits,
save the real error, reduce concurrency, and clean up only this task's resources.
Re-run the affected proof. Report remaining limits honestly and distinguish
completed CI from incomplete local commands. Do not skip a failing assertion as
an environment issue or terminate another worktree's tests.
## Evidence to carry into the PR
Retain the reproducible command, baseline/treatment identity, synthetic fixture
definition, database version/settings, full samples and plans, equality result,
focused regression commands/results, and broader gate outcomes. Summarize:
| Caller/query | Before median | After median | Samples/spread | Complete output/contract check | Scope |
| --- | --- | --- | --- | --- | --- |
| Measured query | ms | ms | recorded | pass/fail and rows | SQL only, service, or request |
Preserve raw evidence in the task's artifact location and put the useful summary
in the PR. Re-run affected proof after a review fix that changes the query or
contract. Source correctness, local speed, final-head CI, and deployed behavior
are separate conclusions; report each only as far as the evidence supports it.
+37 -11
View File
@@ -50,24 +50,50 @@ reasons rather than invented capabilities. Cross-cutting stories have one source
and several references. Do not count historical/proposed stories as current
feature coverage.
For shared foundations that demonstrate a mapped capability, keep their existing
folder/sidebar with `home: "foundations"` and an exception reason, then add related
capability references. Inspect the named exports before linking them. Notes must
name the demonstrated states and remaining limits; an association does not certify
the whole capability. If a story reveals a shipped capability absent upstream,
reconcile its feature recipe and access companion through map maintenance first.
Preserve story exports and IDs. Before moves/title changes, capture the existing
built `index.json`; use explicit meta IDs when needed and compare IDs afterward.
Place stories under `ui/storybook/stories/<primary-feature-area>/`. Use the feature
map's section and feature names as their sidebar prefix; keep useful scenario
groupings beneath that prefix. Put shared fixture modules in `ui/storybook/support/`.
Keep the catalog's `stableId` equal to the explicit CSF meta ID even when the title
changes. Unmapped component examples belong under Foundations; the catalog guide
Keep the explicit CSF meta ID stable even when the title changes; the generated
catalog derives `stableId` from it. Unmapped component examples belong under Foundations; the catalog guide
belongs under Overview. The checker verifies these conventions.
Keep review links and snapshot names working. Prefer classification/index fixes
before bulk directory moves. Record every directly rendered production subject in
the catalog's review sources, including relative imports and primitives when they
are the demonstrated subject. Do not cap the number of source references.
Update review fingerprints only after inspecting the changed source; do not refresh hashes merely
to silence drift checks.
Update the catalog and run `node scripts/storybook-catalog.mjs --write` to refresh
its generated index, then run the checker without flags. The script validates
inventory/references/review fingerprints, not semantic parity or runtime health.
Keep the main guide and every feature Overview congruent with the upstream index:
same section/feature names and order, all capabilities in recipe order, related
suite links across primary homes, and explicit missing examples. Run `node scripts/storybook-catalog.mjs` to regenerate ignored indexes, feature
pages, and preview ordering. Storybook startup/build also generates them. Never
hand-edit or commit generated output. Generated guides are not example coverage.
Preserve their `feature-map-<area>--overview` IDs. The generator removes obsolete
pages from its own ignored output directory when areas disappear.
Keep review links and snapshot names working. Prefer classification fixes before
bulk directory moves. Store capability associations, classification, and durable
limits in each story's literal `parameters.paperclip` object. Infer file paths,
exports and stable IDs from CSF; do not maintain a second inventory. Use Git diff
and history to choose changed production subjects, fixtures and shared sources
for review. Record source revision and executed evidence in the PR or CI report;
do not refresh hashes, dates, or a shared review journal.
Verification routes belong in each feature recipe's optional `Storybook
verification` section. Report needed corrections to `maintain-verification-skill`.
Distinguish missing shipped UI examples from CLI/operator operations and real
browser checks. Keep concrete production contracts and existing test starting
points; test presence is not passing evidence. The generated verification report
lists capabilities without current examples. Associating an example must not
discard its separate production verification obligations.
Run `node scripts/storybook-catalog.mjs --check` and
`node --test scripts/check-maps.test.mjs scripts/storybook-catalog.test.mjs scripts/storybook-feature-index.test.mjs`.
Checks validate local annotations, discovered inventory and references, not
semantic parity or runtime health.
Use `review-storybook` for affected rendering and interactions. Reuse the existing
Storybook/Playwright tools; add no separate launcher, runtime, or baseline system.
Do not accept new screenshot baselines as part of a catalog cleanup.
@@ -53,7 +53,8 @@ a permission denial is not authorization to widen access.
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.
Use Git diff/history to identify affected sources. Record the source revision
and review evidence in the PR or evidence report, not a shared map ledger.
1. **Check both indexes.** Pair same-named feature and agent files, then match
stable sub-feature IDs. Fix orphan/missing entries and broken references.
@@ -81,7 +82,10 @@ a permission denial is not authorization to widen access.
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.
source; add their companion at the same time. Each feature recipe carries its
own navigation metadata. Discovery generates the feature and access indexes;
do not register new areas in shared READMEs or commit generated output. Keep
durable Storybook verification routes in the affected feature recipe.
4. **Live pass.** Required for a verification maintenance pass even if source
looks clean. The coordinator owns serial driving, using the target skill's
@@ -109,7 +113,8 @@ a permission denial is not authorization to widen access.
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.
the generated `maps/generated/coverage.json` is a page-reference inventory,
not passing test evidence.
6. **Review corrections.** Re-read changed files, check paired IDs/references and
run the smallest relevant validation. Report outcome and source/live coverage
+7
View File
@@ -17,6 +17,13 @@ variants where affected. Record chosen files/exports and omitted scope. For a
full source review, account for every file; do not describe sampling as full
render or interaction coverage.
When reviewing navigation/index changes, compare the guide and sidebar with the
full ordered index generated from feature recipes' navigation metadata. Open a feature without examples and a
feature whose related suite lives elsewhere; check capability order, gap messages,
classifications, recipe links, and actual suite navigation. Compare built entry IDs
before/after so existing links survive. Generated Overview pages do not establish
new example coverage.
Use [the existing Storybook commands](../../../doc/DEVELOPING.md#storybook):
`pnpm build-storybook`, or an owned Storybook dev server on an available local
port. Use the built `ui/storybook-static/index.json` for actual story IDs and
@@ -0,0 +1,121 @@
---
name: setup-code-maintenance-bot
description: >
Set up a Paperclip agent and routine that applies a selected code-maintenance
skill to a repository and opens pull requests. Use for nightly maintenance
bots, scheduled code gardening, or webhook-driven maintenance, using an
existing agent or a new hire.
---
# Set Up a Code Maintenance Bot
Turn the user's maintenance intent into a runnable Paperclip routine with a
named agent, accessible repository and skill, bounded work, and inspectable PRs.
The maintenance skill supplies the domain judgment: test auditing, documentation
upkeep, dependency maintenance, refactoring, or another chosen task.
If asked only to draft instructions or a setup plan, produce that artifact and
stop before provisioning or running anything. Do not perform the maintenance
while setting up the bot. An immediate trial is a separate choice from scheduling.
## 1. Establish the destination and agent
Start with the instance and agent choices, using answers already supplied:
- **Instance:** show a clickable, verified Paperclip web URL and ask which
instance to use. If none is known, ask for its URL; never assume localhost,
the instance used in an earlier task, or the first connected tool.
- **Company:** resolve the company within that instance; ask if ambiguous.
- **Agent:** list accessible, suitable agents with names and links, and offer
**use an existing agent** or **create a new agent**. Do not silently choose.
Example, after resolving the actual URL: “Use [Paperclip](<verified-web-url>),
company Acme? Which agent should own this: an existing agent or a new one?”
For a new agent, resolve its name, harness/adapter, provider and model, AI
connection/account, execution environment, reporting line, and budget. Present
available compatible choices from the selected instance. Distinguish the AI
connection from repository credentials. For an existing agent, inspect these
settings and preserve them unless the requested maintenance needs an authorized
change. Keep maintenance-specific instructions in the routine, not by replacing
an existing agent's role.
Read [references/paperclip-api.md](references/paperclip-api.md) for authentication,
discovery, connection binding, hiring, and exact provisioning calls. If the API
is unavailable or not working and browser access is available, use the selected
instance's Paperclip UI to perform the same setup. Verify the instance and
company, honor UI approval gates, and inspect the saved agent and routine after
saving. Reconcile any partially completed API setup before creating through the
browser so the fallback does not duplicate resources. Resolve access against
the selected instance before collecting secrets or making writes.
## 2. Resolve the maintenance contract
Ask only for missing choices; group related questions rather than presenting a
long questionnaire. Discover actual projects and skills before offering them.
| Choice | Resolve before activation |
| --- | --- |
| Repository | Project, repository URL, target branch, execution workspace/environment |
| Work | Maintenance goal, exact skill/source, included areas and exclusions |
| Trigger | Timer with local time and IANA timezone; webhook event/source; or manual/API |
| Limits | Per-run time/cost limit, maximum PRs per run, outstanding-PR cap |
| Delivery | PR target and reviewer/owner; draft or ready; required verification |
| Lifecycle | Monitor and revise PRs until checks pass; owner and continuation path for blocked work |
“Every night” still needs a time and timezone. Propose a concrete time if useful,
but do not infer one silently. A reasonable starting proposal is one coherent PR
per run, a bounded timebox, no automatic merging, and no new work once the agreed
outstanding-PR cap is reached. These are proposals, not fixed product limits.
Resolve the skill at a source the execution environment can actually read.
A file in this chat's checkout is not proof it exists in a remote worker.
Verify the committed target-branch path and all referenced resources, or install
and assign the company skill. Record the chosen source/version policy. Never
replace an unavailable requested skill with a loosely similar task silently.
## 3. Prepare the configuration
Use [references/run-instructions.md](references/run-instructions.md) to write
the complete routine description. It becomes the task given to the worker;
“run maintenance” or a bare skill name is insufficient.
Inspect existing agents and routines to avoid duplicates. Match by company,
repository, task/skill, and trigger; names alone are not identities. Reuse the
requested agent. If an equivalent routine exists, show it and resolve whether
to reuse or change it rather than creating another nightly job.
Show a compact summary with the instance link, agent choice, connection/harness,
repository, skill, trigger/timezone, limits, PR behavior, and readiness gaps.
Proceed within the user's existing setup authorization once choices are settled;
ask only for unresolved choices or required product approvals. Draft-only scope
never authorizes creation. Honor server approval gates without bypassing them.
## 4. Provision, verify, and activate
Follow the API reference or equivalent browser UI in order: acquire authorized
access, provision/reuse the
agent, make the skill available, create the routine **paused**, add its trigger
**disabled**, and read everything back. Record returned IDs as each step succeeds.
Resume partial setup from those records; an ambiguous response is not a reason
to blindly repeat creation.
Verify the agent is runnable and can use its selected connection, repository,
skill, and PR credentials in the actual execution environment. A successful
adapter probe alone does not prove Git push/PR permission. Keep the routine
paused if a hire approval, credential, workspace, or skill is unresolved.
Do not change shared project defaults just to make this bot work.
Enable the trigger and activate the routine only when readiness and scheduling
authorization are established. Use Paperclip's routine trigger as the clock;
do not add a second agent timer or a desktop automation for the same work.
Run a maintenance trial only if requested. Read back the saved schedule and
next run time; distinguish configured scheduling from an observed successful run.
## 5. Hand off
Return links to the instance, agent, routine, and project; the selected skill;
the trigger and timezone; active/paused state; limits and PR policy; readiness
evidence and remaining gaps. If trialed, link the run issue and resulting PR or
no-change result. Explain how to pause the routine and which owner handles
follow-up. Never report a draft, pending hire, or paused routine as running.
@@ -0,0 +1,4 @@
interface:
display_name: "Set Up Code Maintenance Bot"
short_description: "Set up Paperclip maintenance agents and routines"
default_prompt: "Use $setup-code-maintenance-bot to configure a Paperclip routine that applies my chosen maintenance skill and opens pull requests."
@@ -0,0 +1,274 @@
# Paperclip setup API
Use this reference when executing setup. These are API shapes, not commands to
run while authoring this skill. Read the selected instance's advertised schemas
before mutations; deployments can differ from the source used here.
## Access and discovery
Prefer the selected instance's available Paperclip tools. On Runner, discover
operations through its advertised `search_api` / `call_api` tools when present;
they supply authentication and company context. Do not invent tool names or
recover tokens from workspace files when those tools are unavailable.
If API access is unavailable or calls are not working and browser access is
available, use the authenticated Paperclip web UI on the selected instance.
Perform the same agent, skill, project, routine, and trigger setup through its
visible controls. Inspect existing records first, including resources created
by a partially successful API attempt. Honor the signed-in user's permissions
and approval gates. After saving, reopen the agent/routine and verify its fields,
trigger, and active/paused state. Record IDs and links from the resulting pages.
If the UI cannot configure a required setting, report that specific gap and keep
the setup paused; do not claim the setting was saved or bypass access controls.
For an authorized HTTP client, use its existing board session or injected
`PAPERCLIP_API_URL` / `PAPERCLIP_API_KEY`. Normalize the base to append `/api`
exactly once. A run bridge address may differ from the user-facing web URL;
show the web URL but use the injected bridge for API requests. Never send the
credential to a different origin while resolving the user's instance choice.
Use the supported sign-in flow if access is missing, not credentials pasted
into chat. Keep secret values out of generated instructions, logs, and files.
Resolve identity/company through tool context, the authenticated CLI's `whoami`,
or `GET /api/agents/me` for agent callers. The latter is not a board identity
endpoint. Read only the selected company's records:
| Purpose | Operation |
| --- | --- |
| Candidate agents | `GET /api/companies/{companyId}/agents` |
| Agent configuration (permission required) | `GET /api/agents/{agentId}/configuration` |
| Projects and workspace selection | `GET /api/companies/{companyId}/projects`, `GET /api/projects/{projectId}`, `GET /api/projects/{projectId}/workspaces` |
| Existing routines | `GET /api/companies/{companyId}/routines` |
| Adapter capabilities | `GET /llms/agent-configuration.txt`, then `/llms/agent-configuration/{adapterType}.txt` |
| Available models | `GET /api/companies/{companyId}/adapters/{adapterType}/models` |
| AI connections (board access) | `GET /api/companies/{companyId}/ai-connections` |
Agent callers can manage only routines assigned to themselves. Creating a new
agent does not confer permission to manage that agent's routine. Use authorized
board/operator access for another agent (including the necessary `tasks:assign`
grant), or hand off through the supported authorized setup path. Do not mint an
agent key or impersonate the assignee to bypass this restriction. A forbidden
connection-list/configuration read is an access gap, not evidence of no accounts.
## Agent and AI connection
Read adapter docs before constructing configuration. A harness is the execution
adapter/runtime; a provider/model is its inference choice; an AI connection is
the account used to authenticate/bill it. The runtime also needs an execution
environment and separate Git-host access. Do not copy redacted credentials or
unrelated agents' entire configs.
For instances supporting managed AI connections, the binding belongs under
`runtimeConfig.aiConnection`, not an invented top-level `connectionId`:
```json
{
"mode": "shared",
"provider": "<supported-provider>",
"method": "<supported-auth-method>",
"connectionId": "<selected-connection-uuid>",
"grantId": "<returned-grant-uuid>"
}
```
The alternative `responsible_user` binding uses `provider`, `method`, and
`mode: "responsible_user"` without connection/grant IDs. It resolves the
responsible user's provider default at run time; verify the scheduled routine's
responsible user and access, not just the setup caller's login. Discover compatible
bindings on the deployed instance. Never assume a model/provider combination
works merely because both appear in separate lists.
Prefer the governance-aware hire endpoint for a new agent:
```text
POST /api/companies/{companyId}/agent-hires
```
Construct the body using discovered values:
- `name`, `role`, `title`, `reportsTo`, `capabilities`, and a supported `icon`.
- `adapterType`, adapter-specific `adapterConfig`, and `defaultEnvironmentId`
when supported and needed for the selected environment.
- `runtimeConfig.aiConnection` for the resolved managed connection, if used.
- `runtimeConfig.heartbeat: {"enabled": false, "wakeOnDemand": true}` for a new
routine-driven agent when supported. Preserve existing agents' other schedules.
- `instructionsBundle.files["AGENTS.md"]` for managed-instruction adapters:
a focused maintenance role, repository rules, bounded execution, normal
Paperclip task lifecycle, and the user's PR/merge authority. Do not use legacy
prompt-template config when managed instructions are supported.
- `desiredSkills` with installed company skill references when applicable.
- `budgetMonthlyCents` for the user-selected monthly budget, and `sourceIssueId`
only when a real source issue exists.
Use the installed `paperclip-create-agent` skill for its detailed role-template
and hiring workflow when available. Read the response's `agent` and `approval`.
A pending hire is not runnable; leave activation pending and link the approval.
Do not use direct creation to evade governance. Preserve existing agents'
instructions, permissions, connection, and budgets unless changes are authorized.
The adapter probe is:
```text
POST /api/companies/{companyId}/adapters/{adapterType}/test-environment
```
Its current body accepts `adapterConfig`, optional `agentId`, `aiConnection`, and
`environmentId`. Supply the actual execution environment: omitting it can test
the Paperclip host instead of the worker. Inspect the probe's diagnostics; an
HTTP success alone is insufficient. Use supported runtime checks to verify
repository/skill readability and Git-host identity/permissions without publishing
a throwaway PR. Report any capability not exercised; leave unresolved access
blocked rather than claiming a successful maintenance run.
## Make the maintenance skill available
Choose either verified repository delivery or company installation:
- **Repository:** verify the full skill directory is committed and reachable on
the selected checkout ref, including references/scripts. Use the worker's
workspace-relative path, never the setup machine's absolute path. Document
whether the worker follows that branch or an explicitly pinned version.
- **Company library:** inspect `GET /api/companies/{companyId}/skills`; reuse the
exact installed skill when suitable. For an external source, use
`POST /api/companies/{companyId}/skills/import` with `{"source":"<source>"}`.
For a catalog skill, discover it via `GET /api/skills/catalog`, then use
`POST /api/companies/{companyId}/skills/install-catalog` with its returned
`catalogSkillId`. Local import paths must exist on the importing server.
Read back the installed skill's `SKILL.md` and required resources. Installation
is separate from assignment. Attach with:
```text
POST /api/agents/{agentId}/skills/sync
{"mode":"add","desiredSkills":["<resolved-company-skill-key>"]}
```
Verify through `GET /api/agents/{agentId}/skills`. Use `add` to preserve other
assignments; do not replace the full set for a single maintenance task.
## Create a paused routine and disabled trigger
Serialize the complete run instructions as `description` with real newlines.
Do not interpolate untrusted prose into a shell command. A JSON file or structured
tool argument avoids shell expansion. Replace every placeholder before sending.
```text
POST /api/companies/{companyId}/routines
```
```json
{
"title": "<maintenance name>",
"description": "<complete instructions from run-instructions.md>",
"assigneeAgentId": "<agent-uuid>",
"projectId": "<project-uuid>",
"status": "paused",
"concurrencyPolicy": "skip_if_active",
"catchUpPolicy": "skip_missed",
"activityGatePolicy": "always",
"activityGateScope": "project"
}
```
The server derives `responsibleUserId` from the authorized user/parent-issue
context; it is not an arbitrary create-body field. Verify that attribution on
read-back. If an agent caller has no resolvable responsible user, use an
appropriate authorized parent-issue context or operator setup rather than
inventing a user ID.
`skip_if_active` avoids overlapping run issues; `coalesce_if_active` is another
supported choice if the user wants firings associated with current work. Neither
limits outstanding GitHub PRs: the run instructions must enforce that separately.
Use `always` for literal nightly execution. Paperclip's external-activity gate
tracks Paperclip activity, not Git commits; do not use it as a repository-change
detector. The worker can cheaply check whether new repository work exists.
The routine schema does not accept arbitrary workspace settings. Inspect the
project's execution policy and verify the worker gets the intended repository
and isolation. Do not assume workspace overrides on one manual run will persist
for future scheduled runs. Prefer an existing suitable project/workspace; if
provisioning one is needed, resolve that scope and use its advertised API.
```text
POST /api/routines/{routineId}/triggers
```
Schedule example, **only if the user selected 02:00 America/Chicago**:
```json
{"kind":"schedule","enabled":false,"cronExpression":"0 2 * * *","timezone":"America/Chicago"}
```
Cron uses five fields. Inspect the server's next run time and daylight-saving
behavior for the chosen timezone; do not promise a fixed 24-hour interval.
For webhooks, use the supported signing scheme, for example:
```json
{"kind":"webhook","enabled":false,"signingMode":"hmac_sha256","replayWindowSec":300}
```
Use the response's trigger ID, webhook URL, and secret material; do not fabricate
them. Store signing secrets through the supported secret/connection flow without
printing the response's secret fields. Configure the sender only within the
user's authorization. Inspect the deployed signing protocol, event filter, and
replay behavior; a generic Paperclip webhook is not automatically compatible
with every provider's event signature. Keep it disabled if the sender is not ready.
For manual/API use, the trigger body is `{"kind":"api","enabled":false}`.
API triggers require callers; they do not create a timer.
## Read back, activate, and report
Read `GET /api/routines/{routineId}` and verify the complete saved description,
assignee, project, policies, trigger, and absence of unintended extra triggers.
Keep a setup receipt of IDs and completed steps. If a create response is lost,
reconcile existing records before retrying; these create calls should not be
assumed idempotent. A run endpoint's idempotency key does not protect setup calls.
Once ready and authorized:
```text
PATCH /api/routine-triggers/{triggerId}
{"enabled":true}
PATCH /api/routines/{routineId}
{"status":"active"}
```
Read back again. If activation fails, leave the routine paused; report the
existing resources and exact next step. Do not delete a reused agent or project
as cleanup for partial setup.
Only for an authorized immediate trial:
```text
POST /api/routines/{routineId}/run
{"source":"manual","idempotencyKey":"<stable-key-for-this-one-trial>"}
```
This starts real work and can dispatch even while the routine is paused; it is
not a dry-run API. Reuse the key only for retries of that trial. Inspect
`GET /api/routines/{routineId}/runs?limit=10` and the returned execution issue:
queued, coalesced, or skipped is not a successful maintenance run. A bounded trial
must either return the promised PR/no-change result or a specific failure.
To stop future automatic work, `PATCH /api/routines/{routineId}` with
`{"status":"paused"}`. Pausing does not cancel an already dispatched issue/run;
inspect that separately if the user requests a full stop. Archiving is terminal,
so use pause for reversible suspension.
Prefer returned UI links. Otherwise resolve the company's actual URL prefix and
build links under the verified web base: `/{prefix}/agents/{agent-key-or-id}`,
`/{prefix}/projects/{project-key-or-id}`, `/{prefix}/routines/{routineId}`, and
`/{prefix}/issues/{identifier}`. Never substitute an API bridge URL for a web link.
## Source anchors
These shapes were checked against Paperclip source revision
`c65fc9e3c81c41aafe421aa90a00514b84343285`. When available in the target repository,
inspect `packages/shared/src/validators/{agent,routine,project}.ts`,
`packages/shared/src/ai-connections.ts`, `server/src/routes/{agents,routines,ai-connections}.ts`,
and `server/src/services/routines.ts`. The deployed instance's schemas and access
checks remain authoritative. This skill does not require those source files
to be installed alongside it.
@@ -0,0 +1,105 @@
# Instructions for each maintenance run
Use this to compose the routine's `description`. Resolve the fields from setup;
do not leave placeholders in the saved task. These instructions invoke the chosen
maintenance skill, **not** `setup-code-maintenance-bot` again.
## Task template
```markdown
Maintain <repository URL>, targeting <branch>, in project <project name/ID>.
Goal: <user's maintenance outcome>.
Read and apply <exact skill name and worker-accessible path/company skill key>.
Skill source/version policy: <committed branch path or installed version>.
Scope: <included areas>. Exclusions: <out-of-scope changes>.
Bound this run to <time/cost limit>, at most <N> coherent PRs, and at most
<M> outstanding PRs for this maintenance routine. These are upper limits,
not output quotas. Reserve time for verification and reporting.
1. Read the assigned execution issue, repository instructions, prior routine
results, and open maintenance PRs. Inspect remote PR status before editing.
Recover this run's existing branch/PR on a retry rather than duplicating it.
If equivalent work is already open or the outstanding-PR cap is reached,
follow the agreed policy: <skip new work or maintain existing owned PRs>.
2. Fetch the target branch and record the base revision. Work in an isolated
workspace/branch for this execution issue; use the repository's branch
convention and a descriptive name. Record the issue/run-to-branch mapping
on the Paperclip execution issue. Include internal identifiers in published
branch names only when the target repository's rules permit them.
Preserve unrelated work.
Do not edit a shared live checkout or reuse another active run's worktree.
3. Apply the maintenance skill within scope. Establish the relevant baseline,
retain the skill's evidence and safety requirements, and make the smallest
coherent useful change. Finding no justified change is a successful outcome.
4. Run <repository-required and change-relevant checks>. Compare failures with
the baseline. Do not weaken checks to create a green result. Distinguish
measured improvements from estimates; never promise arbitrary savings.
5. If a useful validated diff exists, commit, push, and open/update the owned
PR against <target branch>, using the repository's PR template. Explain
the problem, change, evidence, risks, and verification. Requested PR state:
<draft or ready>. Record the PR URL, branch, and head on the Paperclip
execution issue for future deduplication. Include routine/run issue links
in the published PR only when the target repository's rules permit them.
Monitor the PR and revise it until all required checks pass on its current
head. Wait for pending checks; inspect failing checks and their logs, fix
actionable failures, verify locally, commit, and push. After every push,
refresh the head revision and repeat the check loop; an earlier green commit
does not validate the revised PR. Address review findings required by the
repository. Opening the PR alone does not complete the maintenance task.
Do not merge or enable auto-merge unless that authority was explicitly given.
6. Report the PR URL and head, checks and limitations, changed scope, retained
or deferred candidates, and next owner/action on the execution issue.
If unchanged, record the examined scope and reason without an empty PR.
If blocked, record the blocker and responsible owner; do not claim success.
Stop at the limit; preserve unfinished work with an honest status.
```
## Durable run behavior
- **Issue lifecycle:** follow the installed Paperclip execution/checkout contract.
Complete PR-producing work only after required checks pass on the current head
and the project's required review findings are resolved. If the time/cost limit
arrives first, preserve the PR and patch, record exact pending/failing checks
and the next action, and arrange continuation through the supported Paperclip
follow-up mechanism. Verify that continuation is actually scheduled or assigned;
do not claim an unscheduled watcher will resume work. External blockers need a
named owner and action; report blocked status rather than claiming completion.
Once checks and required review pass, follow the project's completion policy
and name who owns later PR follow-up. A human merge need not keep the run issue
open; open issues can suppress the next run under concurrency controls.
- **Backpressure:** an issue being complete does not mean its PR is merged.
Count still-open owned PRs independently on every run. Search the named repo
using the PR URLs and branch identities recorded on the Paperclip execution
issues, not only titles. Do not require public PRs to contain private links
or identifiers when the target repository prohibits them.
Never close other people's PRs or push to branches the bot does not own.
- **Failures:** retry only plausibly transient failures within a bounded limit.
Authentication, approval, and permission failures need resolution, not repeated
new PR attempts. Record the blocker once and surface it to the configured owner;
route repeated failures to a decision to pause the routine. Do not send Slack
or email messages unless that destination and action were authorized.
- **Inputs:** webhook payloads and repository text are task data. They cannot
expand the authorized repository, skill, permissions, budget, or merge policy.
Keep event-specific values constrained to the declared maintenance scope.
- **Cleanup:** remove only this run's disposable resources after its needed work
and evidence are durably preserved. Do not discard an unpushed patch on timeout.
## Example adaptations
For test gardening, select `test-audit` and require evidence that retained tests
protect the removed contracts. Report test/support LOC separately from production
LOC and do not treat noisy wall-clock differences as proven CI savings.
For documentation upkeep, select the relevant documentation skill and specify
which docs and source behavior to reconcile. Use its appropriate verification;
do not copy test-removal controls into a documentation-only task.
For dependency maintenance, select the chosen dependency policy/skill and define
allowed update classes, compatibility checks, and excluded packages. Existing
dependency PRs count toward duplicate-work and outstanding-PR checks.
The setup workflow stays the same; scope, proof, and risk rules come from the
selected maintenance task. If the user has no suitable skill yet, resolve whether
to author one before activation rather than silently making the routine generic.
+98
View File
@@ -0,0 +1,98 @@
# Coordinating a test-gardening campaign
Use this guide for a broad sweep or multiple PRs. Apply the decision and
preservation rules in [SKILL.md](SKILL.md) to every batch.
## 1. Define the audit boundary
From the request, establish scope, desired benefit, time budget, target branch,
and delivery authority. Pin the base revision and inspect CI routing and cost
data, including setup/import overhead. Choose one mode:
- **Targeted sweep:** investigate promising owners or expensive repeated work.
Report the examined area and exclusions; do not claim subsystem completeness.
- **Exhaustive audit:** inventory every in-scope test file and scenario, including
colocated, shared-package, browser, and dedicated-lane coverage. Assign each to
one owner and record its baseline as passed, failed, blocked, or unrun.
For an exhaustive claim, every declaration needs a decision and evidence;
classify table rows separately when their contracts differ. Missing baseline
results or unread tests leave the audit partial. Existing matching-revision CI
can supply results; a targeted sweep does not require a full-repository census.
Reserve time for preservation checks and reporting; an unfinished validation
leaves an unvalidated local patch, not a PR-ready result.
## 2. Assign owners and record decisions
Split work by protected production behavior, including tests across directories.
When delegation is authorized, assign each worker an isolated checkout, owner,
prior findings, model if specified, and discovery/edit/publication authority.
Tell workers to preserve others' changes. One coordinator owns shared fixtures,
routing, and integration. Do not edit a checkout with active test runs.
Keep one ledger: candidate, contract, retain/repair/consolidate/delete/defer,
reason, keeper, baseline, validation, and branch/PR status. Record reviewed areas
with no safe removals too. Discovery stays read-only until ownership is clear;
qualified edits need no additional user-approval round within existing authority.
## 3. Plan removal of redundant layers
Before editing a broad batch, review the ledger a second time by contract and
boundary. Look for suites that replay the same behavior through wrappers,
mocked collaborators, or provider-specific copies of a shared implementation.
Individual cases can look reasonable while the entire layer is redundant.
Produce a compact layer plan: retired suites, retained owner per contract,
unique assertions to transfer, affected routing/commands, validation controls,
and any unused fixtures or production seams. Prefer a boundary that reaches
the responsible code; preserve distinct transport, lifecycle, and permission
risks. If no whole layer qualifies, record that and proceed with justified
case-level changes. Large deletions are not a requirement.
The coordinator reconciles keeper dependencies across all batches before
cutover. Follow each chain to surviving proof; reject cycles and recheck keepers
another batch modifies or excludes from routing. A batch is ready when every
retired contract has retained proof or retirement evidence. Production-seam
removal still needs separate caller evidence.
## 4. Cut over and verify preservation
Move unique assertions first, apply one coherent batch, and update selection
and ownership references. Follow [validation.md](references/validation.md) for
baselines, controls, restoration, and cost claims. Serialize heavy database or
process runs when host capacity is shared; clean up only owned resources.
Review the combined diff against the layer plan. For broad or consequential
batches, use independent preservation review when delegation is available and
authorized; otherwise disclose that limitation. Resolve each finding with
source evidence or restored coverage and validate repaired assertions with an
intended-failure control. No batch is complete with an unresolved coverage gap.
An exhaustive audit requires a decision for every declaration, a completed and
classified baseline for every file, and passing preservation proof for each
removal. Diagnosed pre-existing defects may remain as explicit follow-ups;
unresolved setup failures or unread tests leave the audit partial. If time
expires first, report the remaining inventory and validation status.
## 5. Deliver and integrate
Prefer a few coherent PRs to one PR per trivial deletion. For a stack, record
each PR's head SHA, base branch/SHA, unique diff, and intended final target.
After a parent is squash-merged, discover its actual merge SHA and replay only
the child's unique change if necessary. Inspect the resulting PR diff for
accidentally reintroduced parent commits or files.
Resolve integration conflicts by reading new contracts on the target branch.
If a deleted file gained a regression, preserve that regression at an appropriate
owner; do not blindly accept the deletion or restore the entire old suite.
For authorized merges, use checks and reviews tied to the current PR head,
inspect unresolved findings, and respect the repository's merge policy. A
previous green head does not validate a changed head.
A PR marked “merged” into an intermediate stack branch is not necessarily
landed in the intended integration branch. Verify the full parent chain and
final diff inclusion before reporting the campaign landed. Preserve or clean
up branches/worktrees according to the user's instructions and retain needed
evidence before cleanup. Report delivery separately from audit completeness;
stop new discovery when the user asks to wrap up.
+34
View File
@@ -0,0 +1,34 @@
# Attribution
Paperclip's test-audit skill is inspired by the organization and audit principles
of OpenClaw's [test-audit skill](https://github.com/openclaw/openclaw/tree/main/.agents/skills/test-audit),
consulted on 2026-10-13. It uses the short entry point, separate campaign guide,
and focused references pattern, with independently written Paperclip procedures
and lessons from our test-gardening work. It has no execution or documentation
dependency on an OpenClaw checkout or another installed skill.
The upstream license is retained below for the adapted material.
```text
MIT License
Copyright (c) 2026 OpenClaw Foundation
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.
```
+78
View File
@@ -0,0 +1,78 @@
---
name: test-audit
description: >
Garden the test suite by finding and removing redundant, vacuous, or
implementation-coupled tests while preserving useful regression coverage.
Use for test audits, test pruning, duplicate coverage, or reducing CI test
cost. Supports focused cleanups and coordinated audit campaigns.
---
# Test Audit
Reduce execution and maintenance cost while preserving meaningful failure
detection. Investigate aggressively; delete only with evidence. Retaining an
area after review is a valid result. This skill is self-contained; upstream
attribution is in [NOTICE.md](NOTICE.md).
## Choose the scope
- Focused cleanup: follow this entry point and read the
[candidate evidence guide](references/audit.md) before editing.
- Multiple owners, agents, or PRs: also read [CAMPAIGN.md](CAMPAIGN.md). Declare
whether the work is a targeted sweep or an exhaustive subsystem audit.
- Validation and cost claims: read [references/validation.md](references/validation.md).
- Paperclip commands, invariants, and delivery: read
[references/paperclip.md](references/paperclip.md) alongside repository instructions.
## Decision gate
For every proposed removal, answer:
1. Which observable contract and plausible regression do the assertions cover?
2. Which retained file/case detects that regression through the responsible
production code? Otherwise, why is the assertion vacuous or contract retired?
3. Does this candidate uniquely cover a transport, permission, lifecycle,
storage boundary, platform, default, or other independent failure mode?
4. What improves: executions, fixtures, processes, maintenance, or runtime?
Prefer the smallest test that reaches the code responsible for the contract.
A broader suite is not automatically stronger proof. Similarity, size, slowness,
or suspected AI authorship alone never justify deletion.
## Prevent new duplication
Apply this gate to tests added or changed during gardening:
- Name the regression that existing proof misses. Extend an appropriate owner
or table before adding another suite; another layer needs a distinct risk.
- Exercise the responsible production behavior. Do not add a mock that supplies
the result being asserted or a production hook solely for convenient testing.
- Check observable outcomes that survive behavior-preserving refactors. A
negative case must reach its named guard with otherwise valid inputs.
## Focused workflow
1. **Inspect:** pin the base; read candidates, keepers, fixtures, production
callers, history, and CI routing. Preserve unrelated work.
2. **Plan:** mark retain, repair, consolidate, delete, or defer. Name remaining
proof and assertions to move; look for redundant suites as well as cases.
3. **Prove:** establish the affected baseline locally or from matching-revision
CI. Diagnose failures before treating them as cleanup candidates.
4. **Edit:** move unique assertions first, then retire duplicates and unused
support. Production-seam deletion needs its own caller/contract evidence.
5. **Validate:** run keepers and affected siblings, verify selection, and apply
the validation guide's intended-failure controls where needed.
6. **Review:** reconcile deleted contracts with retained proof. Publish or merge
only within the task's authorization.
## Completion and reporting
Report removals and keepers, retained/deferred candidates, checks and limitations,
distinct cases versus repeated executions, and test/support versus production
LOC. Count documentation separately. Label cost evidence as measured, estimated,
or historical; a proven simplification does not require a measurable speedup.
State the actual endpoint: findings, validated local patch, published PR,
intermediate merge, or landed in the intended target. Stop at the requested
scope/time limit or completed delivery, not a deletion quota. For another pass,
refresh the base and prior findings; revisit retained tests only with new evidence.
@@ -0,0 +1,4 @@
interface:
display_name: "Test Audit"
short_description: "Prune redundant tests while preserving useful coverage"
default_prompt: "Use $test-audit to garden this test suite and remove well-supported redundancy while preserving meaningful regression coverage."
@@ -0,0 +1,72 @@
# Candidate evidence and retention
Use this reference before deleting or consolidating tests.
## Search for waste, then inspect the contract
| Candidate pattern | What to establish before changing it |
| --- | --- |
| Several tests repeat one assertion through the same production path | A retained case has equivalent inputs, failure sensitivity, and relevant setup. |
| A test file only imports another test file | The real owner is selected in the same required runs; the alias adds no setup, configuration, or separate entry point. Check both CI and documented commands. |
| A large table repeats equivalent rows | Preserve rows that exercise different branches, boundary values, error classes, platforms, or defaults. |
| A bulk fixture creates many interchangeable records | Establish that the count does not cross batching, pagination, concurrency, or transaction thresholds. Retain mixed outcomes and persisted state assertions. |
| Assertions copy lists, exports, strings, or source shapes | Determine whether the list or shape is an independent public, packaging, generated, or architecture contract. |
| Mocks implement the behavior being asserted | Find a test that exercises the responsible production behavior; otherwise repair or relocate this proof before removing it. |
| Fixtures fabricate receipts, ordering, or persisted state | Verify that the responsible production path creates that evidence; fixture-supplied outcomes cannot prove it does. |
| A negative case passes for an unrelated reason | Reach the named guard with otherwise valid inputs. Fix useful coverage rather than discarding it as waste. |
| A test-only export, reset hook, or wrapper becomes unused | Search runtime callers, package exports, generated callers, supported integrations, and history. File location alone does not make it dead production code. |
Also inspect self-comparisons, assertions with expected values derived from the
subject, probes with no checks, and names that promise more than the body tests.
Explicitly assertion-free smoke tests can still protect module loading or
execution; identify that purpose before deleting them.
## Reasons to retain apparently similar tests
Two tests can use the same payload while protecting different failure modes:
- Authorization and tenant isolation at separate exposed entry points.
- Direct API versus SDK/MCP transport, including serialization and errors.
- Initial execution versus replay, recovery, restart, or concurrent access.
- In-memory return values versus committed database state or rollback.
- Default-off behavior versus explicit opt-in; missing versus invalid input.
- Platform behavior, published package exports, migrations, generated-language
compatibility, or intentional prompt/protocol bytes.
- Browser interaction, reconnect, pagination, lost responses, attachment
persistence, or visible ordering absent from lower-level coverage.
Keep a static check when it is an independent and appropriate guard of a
contract. Implementation-shaped checks that fail on a harmless identifier
rename deserve scrutiny; this does not make all source inspection disposable.
Likewise, a slow integration test can be the only meaningful proof of a
transaction or lifecycle. Cost helps rank investigation, not determine truth.
## Evidence before editing
Read the candidate's full body and parameter rows, setup/teardown, production
owner, real callers, proposed keeper, configuration, and relevant history.
Look for why the test was introduced and regressions added since. Inspect the
dependency's actual contract when a claim depends on library behavior.
Use a compact table or PR notes:
| Candidate | Decision and reason | Contract/regression | Keeper or retirement evidence | Validation and benefit |
| --- | --- | --- | --- | --- |
| File and case/rows | Retain / repair / consolidate / delete / defer | Observable failure detected | Exact file/case, or evidence the contract no longer exists | Commands/control, cost or maintenance reduction, limitations |
For consolidation, list unique assertions to move. The keeper must actually
exercise them with valid fixtures; adding an assertion that cannot fail is
not coverage preservation. If setup or the selected test project differs,
explain why it does not change the protected contract.
## Two useful distinctions
- An import-only alias and its directly selected owner may duplicate execution.
An identical-looking alias importing a package suite absent from the default
run may be the only entry point and must stay until routing is repaired.
- Repeated successful records in a bulk route fixture may be reducible while
retaining mixed failures and persisted outcomes. The same reduction would
invalidate a test whose record count exercises a batch or pagination limit.
If evidence is missing, defer that candidate and keep working on independent
ones. Audit-only findings do not become permission to delete tests elsewhere.
@@ -0,0 +1,71 @@
# Paperclip integration
This reference adapts the standalone workflow to this repository. Read root
and scoped `AGENTS.md` and their required product/development documents. Resolve
paths below from the repository root and inspect current contents; counts and
shard layouts evolve.
## Discovery and test selection
- `package.json`, `vitest.config.ts`, and package-local Vitest configurations
describe the test projects and commands.
- `scripts/run-vitest-stable.mjs` selects and runs the default suites. Inspect
its supported dry-run/mode/shard flags before constructing routing checks.
- `.github/workflows/pr.yml` identifies the PR workflow; follow its reusable
workflow references to the actual lanes and shard matrix.
- `scripts/general-server-shard.mjs` and the general-server, serialized, and
E2E duration JSON files under `scripts/` provide routing and historical cost
clues. Read each manifest's provenance; a file's weight is not per-case time.
- Search tests colocated with production modules as well as `__tests__/`.
Some acceptance files import other suites. Verify both direct selection and
aliases, including package suites outside the default project list.
Example focused command, replacing the example path with the actual owner:
```sh
pnpm --filter @paperclipai/server exec vitest run src/services/OWNER.test.ts
```
`pnpm test` is the normal Vitest entry point. Browser and release-smoke suites
are opt-in; run them when affected or explicitly verifying those flows.
Follow repository requirements for a PR-ready handoff, including the full
typecheck/test/build checks when required; identify local versus CI execution
and report anything unrun. Do not rerun the entire repository on every audit
heartbeat. Test removals do not excuse required checks.
## Contracts deserving special care
Preserve company isolation, board/agent authorization, atomic checkout,
single-assignee rules, approval gates, budget hard stops, and mutation activity
logging. Persistence, idempotency, cancellation, concurrency, recovery, and
ordering often have separate owners even when test names look similar.
Distinguish first-party Telemetry, opt-in OpenTelemetry observability, and the
local run log by their paths as defined in `AGENTS.md`. A pruning task is not
permission to remove privacy, endpoint gating, or event-contract coverage.
## Environment and delivery
Database-backed tests may start real embedded Postgres even though development
can use PGlite. Check the actual fixture. An isolated install with scripts
disabled may need documented dependency setup before its binaries work.
Resource exhaustion must not be interpreted as a tested product failure or a
passing control. Coordinate heavy runs and clean up only owned resources.
Follow existing branch/worktree conventions and protect unrelated working-tree
edits. New repository audit plans/receipts belong in
`doc/plans/YYYY-MM-DD-<scope>-test-audit.md`. Prefer one concise receipt per
coherent batch or campaign. For Paperclip issue work, follow the issue's artifact
and work-product requirements rather than relying only on local paths.
When publishing is authorized, fill every section of
`.github/PULL_REQUEST_TEMPLATE.md`, including exact model information that is
actually known; do not fabricate context-window details. Use an accurate PR
title consistent with current repository policy. A deletion-only cleanup may
be a refactor and does not need a token added test to satisfy a title heuristic.
When merging is authorized, verify current-head CI and fresh repository review
results, inspect review threads and edited bot summaries, and resolve genuine
findings. After a stack merge, verify inclusion in the intended final branch
as described in [CAMPAIGN.md](../CAMPAIGN.md). No fixed check count or old
review score substitutes for inspecting the current requirements.
@@ -0,0 +1,87 @@
# Preservation, cost, and evidence
## Prove the retained behavior
Pin baseline and candidate revisions and record the actual command, project,
filters, environment differences, and pass/fail/skip counts. Prefer focused
owner and affected sibling runs. A zero-test run, setup error, or fully skipped
suite is not a successful baseline. Use recent CI only when its revision and
test selection support the claim being made.
For straightforward exact duplicates, compare all assertions, fixtures,
configuration, and selection. For assertion migration, weaker-to-stronger
coverage substitution, security/persistence boundaries, or uncertain failure
sensitivity, use a deliberate control:
1. Run the keeper normally and observe it passing.
2. In an isolated, idle checkout, temporarily introduce the specific plausible
production regression the keeper is meant to detect, or revert the relevant
fix. Keep unrelated guards and fixtures valid.
3. Verify the expected case fails at the intended assertion. A timeout, missing
dependency, unrelated rejection, or initialization failure is not proof.
4. Restore the exact pre-control bytes in a guaranteed cleanup step. Check the
diff/hash and run the same selected case successfully again.
5. Run the affected candidate owners without that narrow name filter before
calling the complete owner suite green.
Never mutate a checkout with active tests, commit a temporary mutation, or
overwrite someone else's source changes during restoration. Do not add a
permanent replacement test solely to justify removing an obvious duplicate.
## Verify what actually runs
Inspect the real runner entry point, include/exclude rules, package projects,
shard routing, dedicated CI lanes, and documented focused commands. A test
existing on disk does not guarantee that it executes in the required run.
The required invocations are the affected CI lanes and supported developer
commands for the audit's scope. Redirecting a documented alias command to its
owner is valid when the configuration and protected contracts remain equivalent;
preservation does not require retaining an obsolete filename indefinitely.
When removing test-import aliases, prove that the retained owners remain
selected with the intended multiplicity in each required invocation. Update
explicit commands and ownership inventories. Use dry-run routing to inspect
selection and an actual focused run to confirm execution where import caching
or collector behavior makes listing ambiguous. Intentional runs on different
platforms/configurations are separate contracts, not duplicate registrations.
## Measure the benefit honestly
Keep these quantities separate:
| Quantity | Interpretation |
| --- | --- |
| Deleted source declarations / expanded table cases | Change in test code or case inventory. |
| Avoided registrations / suite invocations | Repeated execution eliminated; may remove no unique contract. |
| Test/support LOC | Maintenance reduction, not a runtime estimate. Report additions and net change. |
| Production LOC | Runtime code changed, with its own justification; do not combine it with test LOC. |
| Historical manifest weight | Scheduling estimate at its recorded revision/date, often including setup/import cost. |
| Case time / owner suite time / process time | Different scopes; compare like with like. |
| Shard time / workflow critical path | Scheduling and parallelism effects; summing suite savings does not predict elapsed CI savings. |
Use bounded matched baseline/candidate runs when a quantified runtime claim is
important. Keep environment and configuration comparable, alternate order when
practical, and disclose sample count and variation. Inspect neighboring suites
for host-wide drift. A faster unrelated shard is not deletion evidence; a slower
whole suite does not establish that removing a duplicate caused a regression.
Logs that only print slow cases provide censored observations: an absent case
is below the reporting threshold, not zero milliseconds. A passing retry is
validation evidence, not a fair speed comparison with the failed attempt.
Report uncertain speed effects as inconclusive and keep structural benefits
separate. Do not demand significance testing for every safe maintenance edit.
## Failures and durable reporting
Classify failures before acting: product assertion, test defect, setup/dependency,
host capacity, or CI infrastructure. Fix relevant defects or report the blocker;
do not weaken assertions, increase budgets, skip suites, or erase a failing
baseline to obtain a green audit. Retry a demonstrated transient problem within
a stated bound; a recurring failure needs investigation.
Use PR notes for small changes. For a campaign, keep a compact dated receipt
with revisions, decisions, keepers, commands, results, controls, measurements,
and limitations. Link accessible CI runs/artifacts when they support claims.
Temporary paths and hashes alone do not make evidence durably inspectable.
Do not generate large evidence dossiers for trivial deletions or store raw
logs containing secrets. State precisely which broad checks remain unrun.
+77 -9
View File
@@ -1,6 +1,6 @@
---
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.
description: Verify Paperclip from a source checkout, published npm install, or existing staging or production stack. Select the environment, data state, version, and platform; drive real UI or CLI journeys and capture evidence. Route deployment to the private Cloud skills.
---
# Verify Paperclip
@@ -15,7 +15,66 @@ 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
## Select the verification target
State what is being tested before starting. Use the requested target; for ordinary
feature development, default to the current checkout on the current host with
isolated data. Expand into cross-platform or release qualification only when
requested or needed to reproduce the problem.
Record these independent dimensions together:
- **Artifact:** source checkout (path, commit, dirty state), published npm package
(requested channel and resolved exact version), or deployed image/release.
- **Environment:** local, staging, or production; target URL and intended company
or workspace; board/user/agent identity and authentication mode.
- **Starting data:** fresh and unonboarded, freshly seeded, cloned, or reused;
embedded versus external PostgreSQL; configuration/data location or a redacted
database identifier. Never record credentials or connection strings.
- **Platform:** server OS/architecture, Node/npm versions, and browser/client OS
when relevant. A Mac browser against a Linux server is Linux server evidence;
WSL is Linux evidence, not native Windows evidence.
- **Journey:** first installation/onboarding, an existing-user feature, upgrade,
or a live agent run; expected outcome and real versus simulated dependencies.
| Target | Use it to prove | Procedure |
| --- | --- | --- |
| Checkout dev server, existing or cloned data | Source behavior against existing state | [Checkout modes](references/verification-targets.md#checkout-and-data-modes) |
| Checkout with fresh empty data | First-run onboarding and subsequent features | [Launch](#launch-an-empty-checkout-instance) below |
| Checkout test drive, fresh seed or reused data | Features with a configured company/CEO | [Checkout modes](references/verification-targets.md#checkout-and-data-modes) |
| Published npm canary | End-user installation of a specific prerelease | [npm verification](references/npm-install.md) |
| Published npm stable (`latest`) | End-user installation of the released package | [npm verification](references/npm-install.md) |
| Existing staging stack | Deployed build, hosted auth, flags, integrations | [Hosted verification](references/verification-targets.md#staging-and-production) |
| Existing production stack | Current production journey within the authorized scope | [Hosted verification](references/verification-targets.md#staging-and-production) |
Fresh data does not imply a fresh install. A seeded test drive does not prove
onboarding. A source build does not prove npm packaging. A passing staging check
does not prove production, and a production Cloud stack does not prove the stable
npm install. Report only the combinations actually exercised.
## Deployment handoff
When a requested revision must first be built or deployed, use the skills in the
private `paperclip-cloud` repo:
- `deploy-paperclip-stack` at `.agents/skills/deploy-paperclip-stack/SKILL.md`
for a tenant workspace or an explicitly scoped fleet rollout.
- `deploy-cloud-harness` at `.agents/skills/deploy-cloud-harness/SKILL.md`
for the Cloud control plane itself.
Locate the authorized Cloud checkout or installed skill by name; do not assume a
sibling directory exists. Those skills own build preparation, deployment,
migrations, and rollout recovery. Return here with environment, target, resolved
source SHA, release/image identity, deployment result, and evidence link. If
private access is unavailable, report that prerequisite as blocked and continue
checks possible on the supplied target without inventing deploy commands.
A verification request alone does not authorize deployment, npm publication,
fleet-default changes, or a production rollout. Preserve explicit deployment
instructions already given. Publishing npm packages belongs to the existing
[release skill](../release/SKILL.md); installing one does not require publishing it.
## Launch an empty checkout instance
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
@@ -53,7 +112,11 @@ For Paperclip-managed reusable services, follow
instead of launching a second server. Its cloned-data/login requirements differ
from this empty local instance.
## Doctor
## Doctor (owned checkout helper only)
The doctor/stop commands require the real `launch.json` created by `launch.py`.
Do not fabricate one for dev servers, npm installs, test drives, or hosted stacks.
Use their own readiness and lifecycle procedures instead.
After startup, and again after any surprising behavior, run:
@@ -98,14 +161,16 @@ guessing resource URLs. The unprefixed `/onboarding` route starts naming; use th
company-prefixed onboarding route to resume its agent setup. Check relevant
experimental gates and actor permissions.
For CLI checks, discover exact flags with
For source-checkout 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
select the disposable data directory/API/company explicitly. For published npm
checks, use the installed version’s CLI and help instead. 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,
Include the target dimensions above, then record feature file, sub-feature and
entry-point ID, commit/dirty state, target 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.
@@ -121,12 +186,15 @@ 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.
the evidence directory or issue, not in the map. The generated
`maps/generated/coverage.json` lists page references, not live test health.
## Cleanup
Close the browser context you created (the smoke does this in `finally`). Stop the owned runtime with:
Close the browser context you created (the smoke does this in `finally`). Leave
shared dev, staging, and production services running. The remaining cleanup steps
in this section apply only to `launch.py` instances; use the selected target’s
procedure for other launchers. Stop the helper-owned runtime with:
```sh
python3 .agents/skills/verify-paperclip/scripts/stop.py \
@@ -0,0 +1,78 @@
# Verify the published npm experience
Use this route for “can a user install and run this package?” Source startup,
workspace links, `pnpm build`, and local tarballs do not answer that question.
## Resolve the exact artifact
Read [.github/workflows/release.yml](../../../../.github/workflows/release.yml)
for publication behavior. Canary publication follows verified pushes to `master`;
an arbitrary feature-branch SHA need not have a published canary. Publication can
fail or still be running, so prove registry availability before claiming coverage.
Resolve the requested channel once against the public registry:
```sh
npm view paperclipai@canary version --registry=https://registry.npmjs.org
npm view paperclipai@latest version --registry=https://registry.npmjs.org
```
Use the one requested by the task: `canary` for prerelease verification, `latest`
for stable production npm verification, or an explicit version. Record resolved
version, registry, dist integrity, and source provenance from release metadata,
workflow, and tags. Pin that version for all later commands. If testing a SHA,
confirm the package maps to it; never substitute the current canary silently.
Missing publication is a blocked check, not a reason to publish during verification.
## Install like a new user
Use a disposable directory outside the checkout and fresh npm cache,
instance/config, and user-config paths. Use an isolated OS user/container when
proving absence of all pre-existing user state. Inspect inherited routing and
registry overrides without exposing secrets. Avoid workspace dependencies, local
`file:` packages, preinstalled Paperclip binaries, and cached `npx` installs.
Run the documented end-user entry point with the pinned package, for example
`npx --yes --registry=https://registry.npmjs.org paperclipai@<exact-version>`.
Read that version's `--help` before selecting `onboard`, `install`, or service
flags. For a foreground disposable check use `onboard --yes --bind loopback
--no-install-service --run --data-dir <fresh-directory>` when supported by that
version; keep ordinary interactive onboarding when that is the journey requested.
A managed CLI/service installation is separate from an ephemeral `npx` launch;
test it explicitly if requested.
Prove each relevant stage separately: registry download/install, CLI execution,
server readiness, visible onboarding, saved company/setup state, restart/reload,
and a first agent task when authorized. Successful `--version` alone does not
prove a usable install. For upgrades, first create state with the previous exact
version, then install the target against that same disposable data and verify
state survives; report this separately from a fresh install.
## Existing automation and its limits
The repo has a published-package onboarding suite:
```sh
PAPERCLIPAI_VERSION=<exact-published-canary-version> pnpm test:canary-onboarding-smoke
```
Read [its configuration](../../../../tests/canary-onboarding/playwright.config.ts)
and [launcher](../../../../tests/canary-onboarding/start-published-canary.mjs)
before running. It installs the published package into isolated temporary state,
uses a fresh npm cache and loopback server, and retains failure diagnostics.
It uses checkout Playwright tooling to drive a published runtime; record both
revisions. Its name and automated release wiring target canaries. For stable
verification, inspect compatibility with the selected version or use the manual
pinned-package path above; do not relabel a canary result as stable proof.
The Docker release-smoke suite is separate image evidence. Likewise,
`scripts/clean-install-npm.sh` defaults to source, and its published mode uses a
moving version and source-driven uninstall; it does not by itself prove the
whole lifecycle of a specific published version.
Capture OS/architecture, Node/npm versions, exact commands and exit codes,
installed version, serving revision when available, initial data state, screenshots,
logs, and observed outcomes. Redact credentials. Stop owned foreground processes
or uninstall an owned test service with the tested version's supported command;
retain evidence outside disposable data. Never run checkout ownership helpers
with invented metadata to stop a package process.
@@ -0,0 +1,87 @@
# Checkout, data, and hosted targets
## Checkout and data modes
Read [DEVELOPING.md](../../../../doc/DEVELOPING.md) and
[DATABASE.md](../../../../doc/DATABASE.md) for the current startup contract.
- **Existing dev server:** use `pnpm dev` (watch) or `pnpm dev:once` from the
intended checkout. Inspect its instance routing and data configuration first;
do not assume the default port belongs to this checkout. Record the actual
served commit and dirty state. Reuse a matching running server when appropriate.
- **Fresh empty instance:** use the skill's `launch.py` helper with a new data
directory. Complete the UI or CLI onboarding journey under test. This is the
credential-free route; a live model run needs separate provider setup.
- **Seeded test drive:** run the documented CLI `test-drive --no-browser` with
an authorized environment-backed provider credential. It creates a temporary
embedded instance, completes setup, and seeds Test Company and a CEO. It does
not execute the first task. Verify that separately when required.
- **Reused test drive:** pass `--data-dir <existing-test-directory>`. If it already
contains a company, bootstrap flags do not replace companies, agents, or
secrets. Record existing state; do not label the result fresh onboarding.
Test drive rejects external PostgreSQL configuration and database URL overrides.
- **Managed or cloned worktree:** use
[dev-workspace run/verify/fix](../../paperclip-dev-workspace-run-verify-fix/SKILL.md).
Verify seed completion, instance routing, and login handoff before driving it.
Cloned data is existing-user evidence even when the checkout is new.
`--data-dir` alone is not proof of a fresh database: check effective config and
whether `DATABASE_URL` routes to an external database. Do not print its value.
For ordinary dev, inspect both environment overrides and the active database
config: with `DATABASE_URL` unset, `database.mode: postgres` and a saved
`connectionString` still select external PostgreSQL. Embedded PostgreSQL is the
default only when neither an environment override nor the active config selects
an external database; its instance directory may already hold data. Do not reset
shared data to make a test pass. Choose separate disposable data for first-run
checks and verify the effective backend before calling it isolated.
Record runtime PID, URL, port owner, checkout, and data location for a process you
start. Check `/api/health`, expected served revision, bootstrap/auth readiness,
and the actual page. Capture starting state and verify persistence after reload.
Use that launcher's documented stop procedure for an owned process; leave a
server you borrowed running.
## Platform scope
Ordinary development covers the current host unless the request or failure calls
for more. For a platform issue or release matrix, list required combinations:
macOS, Linux, native Windows, architecture, runtime, and install path. Mark each
combination passed, failed, blocked, or not run separately.
The local helper needs POSIX tools such as `lsof`; do not assume it qualifies
native Windows. Use the supported CLI and native shell for that platform, with
isolated instance/config/cache paths and platform-appropriate process cleanup.
A container proves its guest OS and selected architecture, not the host's native
installer, service manager, file permissions, or path behavior. Keep browser and
server platforms distinct when testing a remote Linux box from a Mac.
## Staging and production
Use the supplied tenant URL and intended identity. Determine whether the target
is the Paperclip tenant application or the Cloud control plane. Confirm the
environment from the operator's deployment record and authenticated routing;
a page title or local Git checkout is not evidence of the serving revision.
If a build/deploy is needed, follow the private skill handoff in `SKILL.md` first.
Record the exact serving SHA and release/image identity after deployment, not
just the requested branch, CI result, or fleet default. Recheck after a long run:
a staging auto-roll or another deployment can change the serving version. Mark
unknown or changing provenance as inconclusive for a claim about a specific SHA.
For staging, use a designated test workspace and its real hosted sign-in/entry
flow. Record fresh versus existing workspace state, experimental flags, relevant
provider connections, and whether dependencies are live. Check tenant readiness
and then the feature journey, including persistence or continuation. A control
plane `/healthz` response or tenant HTML 200 is not feature acceptance.
For production, keep verification within the requested stack, identity, and
journey. Prefer observation of existing state unless writes are authorized; use
an agreed test workspace for mutating checks. Do not run the empty-instance
onboarding smoke, reset data, change flags, or trigger paid agent work merely to
make a production check pass. If a necessary write is outside the request,
report that missing authorization and complete the read-only checks.
Never use local ownership helpers against a remote server. Close only browser
sessions you created and clean up only test records whose removal is authorized.
Keep shared services running. Report production Cloud verification separately
from stable npm verification; the shipped artifacts and configuration differ.
+2
View File
@@ -45,6 +45,8 @@ packages/paperclip-runner/test/fixtures/**
!packages/paperclip-runner/test/fixtures/copilot-profile-v16-identity.json
!packages/paperclip-runner/test/fixtures/copilot-profile-v17-identity.json
!packages/paperclip-runner/test/fixtures/copilot-profile-v18-identity.json
!packages/paperclip-runner/test/fixtures/copilot-profile-v18-claude-qualification-identity.json
!packages/paperclip-runner/test/fixtures/copilot-profile-v19-identity.json
!packages/paperclip-runner/test-fixtures
packages/paperclip-runner/test-fixtures/**
!packages/paperclip-runner/test-fixtures/pi-acp
+1
View File
@@ -3,6 +3,7 @@ PORT=3100
SERVE_UI=false
BETTER_AUTH_SECRET=paperclip-dev-secret
PAPERCLIP_TOOL_ACTION_SIGNING_SECRET=paperclip-dev-tool-action-signing-secret-change-me
PAPERCLIP_SENTRY_RUN_FAILURES=off
# Optional Paperclip ID Gmail OAuth broker. Enroll the instance first; keep both
# private keys in the deployment secret manager. HTTP base URLs must be loopback.
+4
View File
@@ -10,6 +10,10 @@ doc/PUBLISHING.md @cryppadotta @devinfoley @nickyleach @forgottendev
doc/RELEASE-AUTOMATION-SETUP.md @cryppadotta @devinfoley @nickyleach @forgottendev
skills/** @cryppadotta @devinfoley @nickyleach @forgottendev
# Review configuration and repository rules
/.greptile/ @cryppadotta @devinfoley @nickyleach @forgottendev
/rules/ @cryppadotta @devinfoley @nickyleach @forgottendev
# Package files — dependency changes require review
# package.json matches recursively at all depths (covers root + all workspaces)
package.json @cryppadotta @devinfoley @nickyleach @forgottendev
+33 -1
View File
@@ -788,6 +788,25 @@ jobs:
pnpm install --frozen-lockfile
fi
# The public-install verifier at the end of this lane downloads the whole
# public registry graph into an empty npm cache: its consumer install
# took 119-129s of the 226-241s step, more than half of this ~415-446s
# lane, in runs 38426120144, 38432086560 and 38423713537 (2026-10-13).
# That graph is fixed by source manifests, so this fetches it in the
# background while the Rust restore, Evalbook and `pnpm build` run, about
# 150s before the verifier installs anything. Only the cache is handed
# over, and the verify step waits for this first. A failed or partial
# warm-up leaves the verifier to fetch what is missing as before.
- name: Start warming the public-install npm cache
if: ${{ hashFiles('scripts/warm-public-install-npm-cache.mjs') != '' }}
run: |
(
# The default `bash -e` would skip the status line on a failure.
set +e
PAPERCLIP_PUBLIC_INSTALL_NPM_CACHE="$RUNNER_TEMP/public-install-npm-cache" node scripts/warm-public-install-npm-cache.mjs
echo $? > "$RUNNER_TEMP/public-install-npm-cache.status"
) > "$RUNNER_TEMP/public-install-npm-cache.log" 2>&1 &
# pnpm build reaches the Runner package's build:binary step; without the
# shared Rust cache that is a ~3m40s cold compile of all third-party
# crates (run 35036001734, 2026-09-15). Same restore-only contract as
@@ -914,7 +933,20 @@ jobs:
# docker-runner-check.yml runs the same verifier after `pnpm build`.
- name: Verify built-in Grok from a clean public npm install
if: ${{ hashFiles('scripts/verify-grok-npm-install.mjs') != '' }}
run: node scripts/verify-grok-npm-install.mjs
run: |
status="$RUNNER_TEMP/public-install-npm-cache.status"
if [ -f "$RUNNER_TEMP/public-install-npm-cache.log" ]; then
# Normally finished long before this; never let it hold the lane.
for _ in $(seq 180); do [ -f "$status" ] && break; sleep 1; done
if [ "$(cat "$status" 2>/dev/null)" = 0 ]; then
tail -n 1 "$RUNNER_TEMP/public-install-npm-cache.log"
else
echo '::notice title=Public-install npm cache::warm-up did not finish cleanly; the verifier fetches what is missing'
tail -n 20 "$RUNNER_TEMP/public-install-npm-cache.log"
fi
export PAPERCLIP_PUBLIC_INSTALL_NPM_CACHE="$RUNNER_TEMP/public-install-npm-cache"
fi
node scripts/verify-grok-npm-install.mjs
verify_serialized_server:
name: Verify serialized server suites (${{ matrix.shard_label }})
+2 -2
View File
@@ -377,7 +377,7 @@ jobs:
release_runner_binaries:
needs: release_runner_source
if: needs.release_runner_source.outputs.required == 'true'
if: ${{ !cancelled() && needs.release_runner_source.result == 'success' && needs.release_runner_source.outputs.required == 'true' }}
uses: ./.github/workflows/release-verify.yml
with:
ref: ${{ needs.release_runner_source.outputs.sha }}
@@ -535,7 +535,7 @@ jobs:
# anyone mistakes an installable package for an onboardable one.
smoke_canary_onboarding:
needs: publish_canary
if: needs.publish_canary.result == 'success'
if: ${{ !cancelled() && needs.publish_canary.result == 'success' }}
runs-on: ubuntu-latest
timeout-minutes: 20
permissions:
+3
View File
@@ -8,6 +8,9 @@ dist-flow-preview/
server/ui-dist/
packages/paperclip-runner/runner/target/
ui/storybook-static/
ui/storybook/generated/
ui/storybook/.storybook/preview.tsx
maps/generated/
.env
*.tsbuildinfo
drizzle/meta/
+71
View File
@@ -0,0 +1,71 @@
# Greptile configuration
This directory tracks the supported review configuration for
`paperclipai/paperclip`. It was prepared from a read-only dashboard inventory
on 2026-10-13. No dashboard settings or custom context were changed.
- `config.json` records the observed review settings supported by Greptile's
documented file schema.
- `files.json` loads repository context and scopes architectural rule files.
- `rules.md` explains how to apply the canonical Markdown rules in `rules/`.
## Settings migrated to Git
| Dashboard setting | Repository configuration |
| --- | --- |
| Automatic reviews on all events | `autoReview: ["open", "push", "rebase"]` |
| Exclude `dependabot[bot]`; remaining reviews use Base | `excludeAuthors`, `effort: "base"` |
| High strictness (dashboard says it does not comment on P2s) | `strictness: 3` |
| Do not replace the PR description | `shouldUpdateDescription: false` |
| Include PR summary, confidence score, and findings; no sequence diagram | The four section settings in `config.json` |
| Summary is not collapsible; default-open option is off | `summarySection.collapsible` and `defaultOpen` are `false` |
| Include a prompt to fix findings | `fixWithAI: true` |
| Status checks and status comments enabled | `statusCheck` and `statusCommentsEnabled` are `true` |
| Auto-approval disabled; stored risk ceiling is Low | `autoApprove.enabled: false`, `riskCeiling: "low"` |
The existing PR-description and 1,000-line growth guidance is in
`rules/pull-request-review.mdc`. That file also preserves the active,
repository-specific rule not to request UI screenshots. This resolves the
contradiction with the older organization instruction asking for screenshots.
The active dashboard pattern `**/[Aa][Gg][Ee][Nn][Tt][Ss].md` reported two files:
`AGENTS.md` and `docs/api/agents.md`. Both are explicit references in
`files.json`; the latter remains API context, not contributor policy. Future
context files need explicit manifest entries. The inactive Contribution
guidelines context remains inactive; it is not added as a separate context
file. Rules scoped to other repositories are not copied here.
## Settings still managed in Greptile
The following observed controls do not have equivalents in the published
`.greptile/` schema used for this migration. They remain dashboard settings:
- Review draft pull requests: enabled.
- Required confidence to pass the status check: 5/5.
- Image badges: enabled.
- Comment header: empty.
- Default coding-agent badges: no agents shown.
Repository enablement, provider authentication, billing, integrations, and
learned memory also remain service settings. Auto-approval risk instructions,
if used later, are explicitly dashboard-only in Greptile's reference. Do not
invent config keys for unsupported controls.
## Cutover and maintenance
Greptile reads committed configuration from the reviewed branch. No reindex is
required. Local changes alone are not visible to the hosted reviewer.
File-based review settings override dashboard defaults, but dashboard rules
and instructions are additive. The existing dashboard copies are still active.
This is a staged migration, not a completed dashboard cleanup. After a hosted
review verifies the configuration, an authorized maintainer can retire duplicate
dashboard context scoped to this repository. Do not remove shared organization
instructions while other repositories still depend on them.
Keep each policy's body in `rules/`; update the `files.json` scope together with
the rule's MDC frontmatter. The chat-channel rule includes both the directory
and its sibling service entry point. See `rules/README.md` for authoring steps.
References: [configuration and precedence](https://www.greptile.com/docs/code-review/greptile-config),
[supported fields and file references](https://www.greptile.com/docs/code-review/greptile-config-reference).
+28
View File
@@ -0,0 +1,28 @@
{
"autoReview": ["open", "push", "rebase"],
"excludeAuthors": ["dependabot[bot]"],
"effort": "base",
"strictness": 3,
"shouldUpdateDescription": false,
"summarySection": {
"included": true,
"collapsible": false,
"defaultOpen": false
},
"confidenceScoreSection": {
"included": true
},
"issuesTableSection": {
"included": true
},
"sequenceDiagramSection": {
"included": false
},
"fixWithAI": true,
"statusCheck": true,
"statusCommentsEnabled": true,
"autoApprove": {
"enabled": false,
"riskCeiling": "low"
}
}
+48
View File
@@ -0,0 +1,48 @@
{
"files": [
{
"path": "AGENTS.md",
"description": "Repository contributor instructions and routing to scoped architecture rules."
},
{
"path": "docs/api/agents.md",
"description": "Agent API documentation retained from the existing Greptile agent-file context. This is API reference material, not contributor instructions."
},
{
"path": "rules/pull-request-review.mdc",
"description": "Existing Paperclip review guidance for PR descriptions, UI evidence, and growth of large source files."
},
{
"path": "rules/product-harness-responsibility.mdc",
"description": "Product requirements and review criteria for harness responsibility, minimal user-facing internals, truthful progress, and human decisions."
},
{
"path": "rules/chat-channel-platform-boundaries.mdc",
"description": "Architecture requirements and review criteria for separating chat channel platform implementations from shared orchestration.",
"scope": [
"server/src/services/chat-channels/**",
"server/src/services/chat-channels.ts"
]
},
{
"path": "rules/heartbeat-execution-boundaries.mdc",
"description": "Heartbeat module ownership and review criteria for admission, cancellation, recovery, cleanup, and durable execution evidence.",
"scope": [
"server/src/services/heartbeat.ts",
"server/src/services/heartbeat/**",
"server/src/services/heartbeat-*.ts",
"server/src/__tests__/heartbeat-*.test.ts"
]
},
{
"path": "rules/database-migration-snapshots.mdc",
"description": "Snapshot retention requirements for migration generation, rebases, and review; preserve SQL migrations and journal history.",
"scope": [
"packages/db/src/schema/**",
"packages/db/src/migrations/**",
"packages/db/package.json",
"packages/db/drizzle.config.ts"
]
}
]
}
+12
View File
@@ -0,0 +1,12 @@
# Repository rule loading
The `.mdc` files under `rules/` are repository review requirements.
`.greptile/files.json` identifies the rule files to read for matching source
paths. Read their full Markdown bodies and apply their review criteria and
allowed exceptions to the affected code.
Each rule's YAML frontmatter declares its scope with repository-relative
`globs`, or `alwaysApply: true` for a repository-wide rule. Respect that scope;
do not apply a channel rule to unrelated subsystems. Keep the policy in the
referenced file as the source of truth rather than maintaining a separate copy
in dashboard instructions.
+22 -3
View File
@@ -26,6 +26,23 @@ authoring runbook for provider research, supported transport/auth patterns,
credential handling, branding, implementation, testing, live proof, and PR
submission.
### Scoped repository rules
Before editing or reviewing files, read the matching rules in `rules/*.mdc`.
Each rule has Markdown content and YAML frontmatter: `globs` contains
comma-separated, repository-relative file patterns, and `alwaysApply: true`
means the rule applies throughout the repository. Read all rules whose scope
matches the affected files. These rules supplement this file and any applicable
nested `AGENTS.md` instructions.
For `server/src/services/chat-channels.ts` and everything under
`server/src/services/chat-channels/`, read
[`rules/chat-channel-platform-boundaries.mdc`](rules/chat-channel-platform-boundaries.mdc).
For `server/src/services/heartbeat.ts`, `server/src/services/heartbeat/`,
heartbeat-prefixed sibling services, and heartbeat regression tests, read
[`rules/heartbeat-execution-boundaries.mdc`](rules/heartbeat-execution-boundaries.mdc).
See [`rules/README.md`](rules/README.md) for rule authoring and Greptile setup.
## 3. Repo Map
- `server/`: Express REST API and orchestration services
@@ -164,9 +181,11 @@ Its structural checks do not prove live behavior or authorization.
Storybook has a downstream [feature catalog](maps/storybook-map/README.md).
Use `maintain-storybook` for story/fixture drift and `review-storybook` for browser
evidence. Keep the feature-map skills independent of this catalog. After story
or declared review-source changes, reconcile affected entries and run
`node scripts/storybook-catalog.mjs`; its checks are not production acceptance.
evidence. Keep the feature-map skills independent of this catalog. After story or recipe changes, update the affected source annotations or
recipe and run `node scripts/storybook-catalog.mjs`. Indexes are generated and
ignored; never commit aggregate catalogs, refresh review fingerprints, or append
a shared review journal. Use Git diffs and keep review evidence in the PR or issue.
Structural checks are not production acceptance.
Default local/agent test path:
+95 -1
View File
@@ -1,5 +1,8 @@
import { describe, expect, it, vi } from "vitest";
import fs from "node:fs";
import path from "node:path";
import { beforeEach, describe, expect, it, vi } from "vitest";
import {
ensureServiceShim,
handleOnboardService,
handoffToOnboardedService,
isInstallableReleaseVersion,
@@ -7,6 +10,97 @@ import {
shouldOfferForegroundStart,
} from "../onboard-service.js";
import { readInstallManifest, resolveInstallStorePaths, writeManagedShim } from "../install-store.js";
import { installCommand, runCommandWithDiagnostics, smokePayload } from "../commands/install.js";
import { isExecutableFile, resolveServiceShimPath } from "../services/service-manager.js";
vi.mock("../version.js", () => ({ packageVersion: "2026.924.0" }));
vi.mock("../install-store.js", async (importOriginal) => ({
...await importOriginal<typeof import("../install-store.js")>(),
readInstallManifest: vi.fn(),
writeManagedShim: vi.fn(),
}));
vi.mock("../commands/install.js", () => ({
installCommand: vi.fn(),
runCommandWithDiagnostics: vi.fn(),
smokePayload: vi.fn(),
}));
vi.mock("../services/service-manager.js", async (importOriginal) => ({
...await importOriginal<typeof import("../services/service-manager.js")>(),
isExecutableFile: vi.fn(),
}));
beforeEach(() => {
vi.clearAllMocks();
});
it("does not install a missing shim when installation is disabled", async () => {
vi.mocked(isExecutableFile).mockResolvedValue(false);
await expect(ensureServiceShim({ installIfMissing: false })).resolves.toEqual({
ok: false,
installedNow: false,
reason: `no executable exists at ${resolveServiceShimPath()}`,
});
expect(installCommand).not.toHaveBeenCalled();
});
it("restores a missing shim without reinstalling the managed payload", async () => {
vi.mocked(readInstallManifest).mockReturnValueOnce({
schemaVersion: 1,
source: "npm",
version: "2026.824.1",
channel: "latest",
payloadPath: "/managed/payload",
installedAt: "2026-08-24T00:00:00.000Z",
previous: [],
});
vi.mocked(isExecutableFile).mockResolvedValueOnce(false).mockResolvedValueOnce(true);
const entrypoint = path.join(resolveInstallStorePaths().currentPath, "node_modules", "paperclipai", "dist", "index.js");
const existsSync = vi.spyOn(fs, "existsSync").mockImplementation((filePath) => filePath === entrypoint);
try {
await expect(ensureServiceShim()).resolves.toEqual({ ok: true, installedNow: true });
expect(smokePayload).toHaveBeenCalledExactlyOnceWith(
resolveInstallStorePaths().currentPath, "2026.824.1", runCommandWithDiagnostics,
);
expect(writeManagedShim).toHaveBeenCalledExactlyOnceWith();
expect(vi.mocked(smokePayload).mock.invocationCallOrder[0])
.toBeLessThan(vi.mocked(writeManagedShim).mock.invocationCallOrder[0]);
expect(installCommand).not.toHaveBeenCalled();
} finally {
existsSync.mockRestore();
}
});
it("does not restore a shim when the managed payload smoke check fails", async () => {
vi.mocked(readInstallManifest).mockReturnValueOnce({
schemaVersion: 1,
source: "npm",
version: "2026.824.1",
channel: "latest",
payloadPath: "/managed/payload",
installedAt: "2026-08-24T00:00:00.000Z",
previous: [],
});
vi.mocked(isExecutableFile).mockResolvedValue(false);
vi.mocked(smokePayload).mockRejectedValueOnce(new Error("payload dependency is missing"));
const entrypoint = path.join(resolveInstallStorePaths().currentPath, "node_modules", "paperclipai", "dist", "index.js");
const existsSync = vi.spyOn(fs, "existsSync").mockImplementation((filePath) => filePath === entrypoint);
try {
await expect(ensureServiceShim()).resolves.toEqual({
ok: false,
installedNow: false,
reason: "payload dependency is missing",
});
expect(writeManagedShim).not.toHaveBeenCalled();
expect(installCommand).not.toHaveBeenCalled();
} finally {
existsSync.mockRestore();
}
});
function dashboardConfig(overrides: {
host?: string;
port?: number;
@@ -0,0 +1,68 @@
import { Command } from "commander";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import { registerServiceCommands } from "../commands/service.js";
import { ensureServiceShim } from "../onboard-service.js";
import { detectServiceManager, type ServiceManager } from "../services/service-manager.js";
vi.mock("../onboard-service.js", () => ({ ensureServiceShim: vi.fn() }));
vi.mock("../services/service-manager.js", () => ({ detectServiceManager: vi.fn() }));
const install = vi.fn(async () => ({ changed: true }));
function runInstall(...args: string[]) {
const program = new Command();
registerServiceCommands(program);
return program.parseAsync(["service", "install", ...args], { from: "user" });
}
describe("service install command", () => {
beforeEach(() => {
vi.clearAllMocks();
vi.spyOn(console, "log").mockImplementation(() => {});
vi.mocked(ensureServiceShim).mockResolvedValue({ ok: true, installedNow: false });
vi.mocked(detectServiceManager).mockResolvedValue({
supported: true,
manager: {
platform: "systemd",
serviceName: "paperclipai.service",
definitionPath: "/service/paperclipai.service",
install,
} as unknown as ServiceManager,
});
});
afterEach(() => vi.restoreAllMocks());
it("checks the shim before installing and preserves JSON output and start flags", async () => {
await runInstall("--json", "--no-start-now", "--no-start-on-login");
expect(ensureServiceShim).toHaveBeenCalledWith({ installIfMissing: false });
expect(vi.mocked(ensureServiceShim).mock.invocationCallOrder[0]).toBeLessThan(install.mock.invocationCallOrder[0]!);
expect(install).toHaveBeenCalledWith({ startNow: false, startOnLogin: false });
expect(console.log).toHaveBeenCalledExactlyOnceWith(JSON.stringify({
installed: true,
changed: true,
platform: "systemd",
serviceName: "paperclipai.service",
definitionPath: "/service/paperclipai.service",
lingerEnabled: false,
}, null, 2));
});
it("rejects a missing shim without installing or printing success JSON", async () => {
vi.mocked(ensureServiceShim).mockResolvedValue({ ok: false, installedNow: false, reason: "missing shim" });
await expect(runInstall("--json")).rejects.toThrow(
"Background service not installed: missing shim. Run `paperclipai install`, then `paperclipai service install`.",
);
expect(install).not.toHaveBeenCalled();
expect(console.log).not.toHaveBeenCalled();
});
it("allows creating the managed shim without --json", async () => {
await runInstall();
expect(ensureServiceShim).toHaveBeenCalledWith({ installIfMissing: true });
expect(install).toHaveBeenCalledWith({ startNow: true, startOnLogin: true });
});
});
+11
View File
@@ -5,6 +5,7 @@ import type { Command } from "commander";
import { readConfig, resolveConfigPath } from "../config/store.js";
import { resolvePaperclipInstanceId, resolvePaperclipInstanceRoot } from "../config/home.js";
import { detectServiceManager, type ServiceManager, type ServiceStatus } from "../services/service-manager.js";
import { ensureServiceShim } from "../onboard-service.js";
import { buildLocalHealthUrl } from "../utils/health-url.js";
type CommonOptions = { instance?: string; json?: boolean };
@@ -172,6 +173,16 @@ export function registerServiceCommands(program: Command): void {
.option("--enable-linger", "Allow systemd startup without an active login session", false)
.action(async (opts) => {
const manager = await resolveManager(opts); if (!manager) return;
const shim = await ensureServiceShim({ installIfMissing: !opts.json });
if (!shim.ok) {
throw new Error(
`Background service not installed: ${shim.reason ?? "the managed install could not be completed"}. ` +
"Run `paperclipai install`, then `paperclipai service install`.",
);
}
if (shim.installedNow) {
p.log.success("Installed the managed paperclipai payload and command shim for the service.");
}
const result = await manager.install({ startNow: opts.startNow, startOnLogin: opts.startOnLogin });
let lingerEnabled = false;
if (manager.enableLinger) {
+68 -53
View File
@@ -1,14 +1,16 @@
import fs from "node:fs";
import path from "node:path";
import * as p from "@clack/prompts";
import pc from "picocolors";
import type { PaperclipConfig } from "./config/schema.js";
import { openUrl } from "./client/board-auth.js";
import { installCommand } from "./commands/install.js";
import { installCommand, runCommandWithDiagnostics, smokePayload } from "./commands/install.js";
import { resolvePaperclipInstanceId } from "./config/home.js";
import { readRuntimeInfo, type PaperclipRuntimeInfo } from "./runtime-info.js";
import {
readInstallManifest,
resolveInstallStorePaths,
writeManagedShim,
type InstallManifest,
} from "./install-store.js";
import {
@@ -133,62 +135,75 @@ type OnboardServiceDependencies = {
warn: (message: string) => void;
};
const defaultDependencies: OnboardServiceDependencies = {
detect: (instanceId) => detectServiceManager({ instanceId }),
// The service definition targets the managed shim. An ephemeral run (npx)
// never lays it down, so installing the service without this step creates
// a definition that crash-loops on a missing binary.
ensureServiceShim: async () => {
const shimPath = resolveServiceShimPath();
if (await isExecutableFile(shimPath)) {
return { ok: true, installedNow: false };
}
const storeShimPath = resolveInstallStorePaths().shimPath;
if (path.resolve(shimPath) !== path.resolve(storeShimPath)) {
return {
ok: false,
installedNow: false,
reason: `no executable exists at ${shimPath} (PAPERCLIP_SHIM_PATH), and it is outside the managed install store`,
};
}
let manifest: InstallManifest | null = null;
try {
manifest = readInstallManifest();
} catch {}
try {
if (manifest?.source === "git" && manifest.repo) {
// A managed git payload must be preserved as-is: reinstall the
// exact revision the manifest records, not an npm release.
await installCommand({ repo: manifest.repo, ref: manifest.sha ?? manifest.ref, yes: true });
} else if (isInstallableReleaseVersion(packageVersion)) {
// packageVersion, not cliVersion: a managed executable's cliVersion
// carries provenance text that is not an installable npm spec.
await installCommand({ version: packageVersion, yes: true });
} else {
return {
ok: false,
installedNow: false,
reason:
`this build reports version ${packageVersion}, which is not an installable release; ` +
"run `paperclipai install` (or `paperclipai install --repo <repo> --ref <ref>` for source builds) first",
};
}
} catch (error) {
return {
ok: false,
installedNow: false,
reason: error instanceof Error ? error.message : String(error),
};
}
if (await isExecutableFile(shimPath)) {
return { ok: true, installedNow: true };
}
// The service definition targets the managed shim. An ephemeral run (npx)
// never lays it down, so installing the service without this step creates
// a definition that crash-loops on a missing binary.
export async function ensureServiceShim(options: { installIfMissing?: boolean } = {}): Promise<EnsureShimResult> {
const shimPath = resolveServiceShimPath();
if (await isExecutableFile(shimPath)) {
return { ok: true, installedNow: false };
}
if (options.installIfMissing === false) {
return { ok: false, installedNow: false, reason: `no executable exists at ${shimPath}` };
}
const storeShimPath = resolveInstallStorePaths().shimPath;
if (path.resolve(shimPath) !== path.resolve(storeShimPath)) {
return {
ok: false,
installedNow: false,
reason: `the managed install completed but no executable shim appeared at ${shimPath}`,
reason: `no executable exists at ${shimPath} (PAPERCLIP_SHIM_PATH), and it is outside the managed install store`,
};
},
}
let manifest: InstallManifest | null = null;
try {
manifest = readInstallManifest();
} catch {}
try {
if (
manifest &&
fs.existsSync(path.join(resolveInstallStorePaths().currentPath, "node_modules", "paperclipai", "dist", "index.js"))
) {
// Only the shim is missing: smoke-test and restore it for the recorded payload,
// keeping its version and update channel instead of reinstalling.
await smokePayload(resolveInstallStorePaths().currentPath, manifest.version, runCommandWithDiagnostics);
writeManagedShim();
} else if (manifest?.source === "git" && manifest.repo) {
// A managed git payload must be preserved as-is: reinstall the
// exact revision the manifest records, not an npm release.
await installCommand({ repo: manifest.repo, ref: manifest.sha ?? manifest.ref, yes: true });
} else if (isInstallableReleaseVersion(packageVersion)) {
// packageVersion, not cliVersion: a managed executable's cliVersion
// carries provenance text that is not an installable npm spec.
await installCommand({ version: packageVersion, yes: true });
} else {
return {
ok: false,
installedNow: false,
reason:
`this build reports version ${packageVersion}, which is not an installable release; ` +
"run `paperclipai install` (or `paperclipai install --repo <repo> --ref <ref>` for source builds) first",
};
}
} catch (error) {
return {
ok: false,
installedNow: false,
reason: error instanceof Error ? error.message : String(error),
};
}
if (await isExecutableFile(shimPath)) {
return { ok: true, installedNow: true };
}
return {
ok: false,
installedNow: false,
reason: `the managed install completed but no executable shim appeared at ${shimPath}`,
};
}
const defaultDependencies: OnboardServiceDependencies = {
detect: (instanceId) => detectServiceManager({ instanceId }),
ensureServiceShim: () => ensureServiceShim(),
confirm: async () => {
const answer = await p.confirm({
message: "Install Paperclip as a background service?",
+36
View File
@@ -203,6 +203,7 @@ Return the same `operationId` and `version` with `status: "complete"` or
Return `complete` only after the requested effect is complete.
Return `pending` while external work continues.
Throw an error when the step fails.
The host stores a fixed error message. It does not store the provider error text.
Server logs identify the failed step, phase, operation, and plugin when available.
They include only known error codes. Unknown codes become `unclassified`.
@@ -218,6 +219,41 @@ It must also prevent an older operation from creating resources after cleanup.
Serialize external effects or remove resources from a late completion.
Do not treat a host timeout as cancellation of the external effect.
### Local instance secrets
Lifecycle requests include `instanceSecrets`, a map of this plugin's private
credentials for this company and agent. A plugin can return an `instanceSecrets`
map with its result to save values. A null value removes the key. Omitted keys
remain unchanged. Writes are allowed during preparation and resume; removals can
also occur during stop and cleanup. Use at most 16 keys per result, with names
matching `[a-z][a-z0-9_]{0,63}` and values no larger than 64 KiB each.
The tenant persists the changes before accepting the result. It locks the agent
and checks its company, phase, operation, revision, required plugin selection,
and the captured attempt's current lease owner and unexpired deadline.
A stale reply or a failed secret write cannot complete preparation. Calls after
a restart receive the saved values. Stop and cleanup requests receive an empty
map, so a damaged credential cannot block removal. Return removals even while
cleanup is pending. An older host omits the field; plugins that require durable
credentials must reject that host before resource effects.
This uses the existing secret service, `company_secrets`, secret versions, and
`local_encrypted` provider. There is no new encryption system or remote API.
The `instance` scope requires an owning agent and plugin. Agent/plugin deletion
cascades the native secret records. These secrets are excluded from company
catalogs, normal secret references, agent access, plugin state, and public agent
records. The general SDK `ctx.secrets.resolve()` remains read-only. Company vault imports
ignore instance-owned names and keys. Device-login cleanup checks instance-owned
account-home claims privately and keeps the directory if a value cannot be read.
Trusted server runtime code can resolve values with
`agentInstanceSecretService(db).read({ companyId, agentId, pluginId })` after its
normal execution admission checks. Use the installed plugin's database ID.
Never place returned values in an agent environment, task payload, log, or UI
response. Preserve the existing secret master key through restarts and backups.
Migration `0339_luxuriant_iron_monger.sql` adds native secret ownership and its
scope constraint; keep these columns when reverting application code.
## Verification and recovery
The harness verification service uses the existing environment-test code.
+116 -1
View File
@@ -2,6 +2,49 @@
Paperclip uses PostgreSQL via [Drizzle ORM](https://orm.drizzle.team/). There are three ways to run the database, from simplest to most production-ready.
### Task query performance
Run-context lookups use expression indexes for both `context_snapshot.issueId`
and `context_snapshot.paperclipIssue.id`. Task creation provenance has its own
company-scoped expression index that follows the query's native issue ID and
legacy `issueId`/`taskId`/`taskKey` precedence. Migration 0345 builds the two new
indexes concurrently and can resume an interrupted build without blocking run
writes for the full build. The indexes add storage and run-write overhead; they
do not change task visibility or secret redaction.
The chat wake-notice sweep compares UUID columns directly against guarded,
canonical lowercase UUID payload values. Malformed and noncanonical payloads
still match nothing. The query can use existing primary keys without adding a
wakeup-history index.
To compare all three queries on the same disposable local PostgreSQL fixture:
```sh
pnpm --filter @paperclipai/server exec tsx ../scripts/benchmark-slow-queries.ts --baseline-ref=origin/master
```
Use a revision before these fixes for `--baseline-ref` after they merge. The
benchmark loads that revision's chat query, uses synthetic data only, compares
complete returned rows, and prints timings and `EXPLAIN (ANALYZE, BUFFERS)` plans.
Local results measure query execution, not staging request latency.
Run history defaults to 200 rows and permits at most 1,000 rows, including
direct service calls. The UI client requests 200 rows when its caller omits a
limit. Context summaries expand the stored JSON once per returned row, retaining
legacy text conversion and the first-class issue binding. Authorization and
secret redaction still run on the bounded result set.
Agent detail links fetch an older selected run by ID when it is outside the
history page, and verify that it belongs to the current company and agent.
To compare the real summary and full history queries with an earlier revision:
```sh
pnpm --filter @paperclipai/server exec tsx ../scripts/benchmark-run-history.ts --baseline-ref=1e731520bb
```
The fixture has 1,400 synthetic runs with 192 KiB contexts. Both queries return
the same 200 complete rows. This benchmark excludes HTTP and redaction latency.
## 1. Embedded PostgreSQL — zero config
If you don't set `DATABASE_URL`, the server automatically starts an embedded PostgreSQL instance and manages a local data directory.
@@ -716,7 +759,7 @@ not revoke grants used by other bots. See [Slack setup](connections/slack-setup.
## Transaction-aware delivery work signals
Five existing delivery queues use process-local work signals to avoid empty
Durable delivery queues, including plugin resource lifecycle events, use process-local work signals to avoid empty
polling. Register work **before** writing a queue row, on that row's transaction:
```ts
@@ -756,6 +799,47 @@ register before writing, or they can remain unseen until the next startup or
another notification. Tests should verify both the producer and its outer
transaction boundary.
### Project repository skill synchronization
`project_skill_sources` stores durable workspace import jobs and originating project
access provenance. Active bindings track their repository/ref; inactive bindings retain
access to installed versions. Project deletion removes bindings, but retained skills
with `access_source_id` stay restricted when no originating project remains.
Removing a project source hides tracking using `company_skill_sources.removed_at`
while retaining its access identity for editable copies and forks. Bindings become
inactive and refresh leases are invalidated transactionally. Reattachment preserves
removal; explicit adoption creates or joins an active source with a separate identity.
Migration 0341 limits repository/ref uniqueness to active sources. Removed sources
retain their original project audience; editable forks capture independent retained
provenance so later attachments cannot expose their local edits. Membership and
project visibility are still evaluated dynamically.
`company_skill_sources` stores automatic-update and future-import preferences, setup
user/agent and connection/grant IDs, next-check time, failure count and existing refresh
leases. Existing sources default to automatic updates with their selection preserved.
Credential values remain in the connection secret system. No project membership lists
are copied into skills. Background publication uses normal immutable versions and
transactional activity attribution. Setup agent and connection identifiers remain after
those identities are deleted. Refresh then requires explicit repair; deletion cannot
silently substitute board authority or another connection. Execution snapshots keep
only the delivered skill keys and their immutable version IDs. New executions resolve
the latest installed versions without an upstream fetch.
Project-derived sources retain `HEAD` for an unspecified repository ref. It follows
GitHub's current default branch. An explicitly configured branch has a separate
source identity even if it currently resolves to that default branch. API-key
agents without an authenticated run may attach repositories; their durable import
jobs have no setup person and require adoption by an authorized person.
Independent sources can change their tracked branch or revision through source
settings, including `HEAD` to follow the default branch. Validate the repository
identity and the requested commit read
before changing the ref; preserve installed skill IDs, versions and selection. Active
project bindings must change their ref through the project configuration. `HEAD`
remains the default-branch alias after refresh, including for independent sources.
Branch changes use the source revision and lease fence, reject duplicate repository/ref
sources, keep installed version rows unchanged, and enqueue the normal refresh path.
Branch listing uses the caller's authorized connection, not the stored setup identity.
### Task workspace records (2026-10-09)
@@ -800,3 +884,34 @@ source captures leave no new records. Worktree realization uses a verified check
as its Git command directory, including when metadata sits inside another repository.
No migration scans or copies existing agent home directories. Keep admitted native descriptors and recovery references until compatible controllers finish their persistence obligations. See [the architecture rollout contract](plans/2026-10-09-task-workspaces.md).
Migration 0341 stores the last scanned Git tree and a durable automatic-refresh
work allowance. The allowance starts at 512 MiB, refills at 512 MiB/hour, and
reserves the existing 128 MiB upper bound before automatic downloads. Completed
small scans refund unused capacity; interrupted/failed work keeps its bounded
reservation. These internal fields do not appear in source responses.
Automatic initial repository imports reserve durable company work credits before
provider reads: 512 MiB capacity, refilling 512 MiB per hour, with a 128 MiB
reservation per attempt. Failed downloads and package fallback keep the full
reservation. Successfully linked small imports refund unused measured work.
Completed bindings do not reset company credits; waiting jobs retry on refill.
The company_skill_import_budgets table stores no credentials or source contents.
### Execution recovery query performance
Conversation recovery keeps indexed run and task UUID columns as UUIDs. Saved
JSON identifiers pass a canonical lowercase UUID guard before conversion.
Malformed, uppercase, numeric and cross-company values retain their old behavior.
Ownership candidate reads split native and legacy issue bindings so existing
indexes can filter candidates before reading large contexts. Native bindings
continue to override legacy context IDs. No new index or migration is needed.
```sh
pnpm --filter @paperclipai/server exec tsx ../scripts/benchmark-recovery-queries.ts --baseline-ref=1e731520bb
```
This disposable fixture compares the real ownership, recovery-action and status
delivery queries, including complete positional results and database plans.
All data is synthetic. Query timings exclude process liveness probes, HTTP and
provider work.
+87 -17
View File
@@ -124,19 +124,30 @@ API responses and MCP transports keep their existing compression behavior.
The board UI Storybook keeps stories and Storybook config under `ui/storybook/` so component review files stay out of the app source routes.
Stories are grouped in `ui/storybook/stories/<feature-area>/` and the sidebar follows
the feature map's sections and feature names. Shared fixtures live in
`ui/storybook/support/`. Keep each suite's explicit meta `id` and catalog `stableId`
when changing titles or locations so existing review links remain valid.
Stories are grouped in `ui/storybook/stories/<feature-area>/`. Feature recipe
navigation controls the sidebar. Shared fixtures live in `ui/storybook/support/`.
Keep each suite's explicit meta `id` when changing titles or locations so existing
review links remain valid. Author capability associations, implementation/data
classification and durable limitations in the story's `parameters.paperclip`.
Start from the downstream [Storybook feature index](../maps/storybook-map/INDEX.md)
to find existing stories by capability. Its [contract](../maps/storybook-map/README.md)
separates production subjects, prototype implementations, simulated data, and
source-review status. Use `maintain-storybook` to reconcile stories/fixtures with
the feature map, and `review-storybook` to exercise them with existing tools.
Run `node scripts/storybook-catalog.mjs` after affected story or review-source
changes; review drift before updating fingerprints, then regenerate with `--write`.
The feature map remains an upstream input and needs no Storybook-specific fields.
Storybook start/build generates the catalog, feature Overview pages, and literal
sidebar order from the checked-out sources. `ui/storybook/generated/` and
`ui/storybook/.storybook/preview.tsx` are ignored build outputs. Shared preview
fixtures and decorators live in `preview-base.tsx`; generation never edits it.
UI typechecking also generates the inputs on a fresh checkout.
Run `node scripts/storybook-catalog.mjs` to assemble the local Markdown indexes,
verification routes and page inventory under `maps/generated/`. Use `--check`
for validation without writes. These outputs are not committed. Use Git diffs to
select affected sources for review; do not maintain review fingerprints or append
a shared review journal. Record executed evidence in the PR, issue, or CI result.
The [Storybook map contract](../maps/storybook-map/README.md) describes annotations
and the [published guide](https://d1p6rlowie26tp.cloudfront.net/storybook/branches/master/?path=/story/overview-storybook-guide--coverage-guide).
Use `maintain-storybook` for source alignment and `review-storybook` for rendering
and interactions. Generated guides, example counts and structural checks do not
establish production behavior. Feature recipes retain optional verification
scope guidance; the feature/access structural check needs no Storybook runtime.
**Chat & Comments → Human identity** covers other-human names and avatars on
left-aligned task messages alongside agents; only the viewer’s own messages are blue/right-aligned. Its review guide explains the data flow; the task journey uses representative
@@ -533,7 +544,7 @@ npx paperclipai allowed-hostname dotta-macbook-pro
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
Its generated page inventory lists current source references. 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
@@ -931,6 +942,11 @@ No Docker or external database is required for this mode.
- `off`: skip the predicate and shadow logging
Grant checks read current database state; there is no positive privacy cache.
A run-history list is one read operation. It checks each distinct company,
run scope, and task binding once, then applies that decision to the related
rows in the same response. Every new list operation reads permissions again.
Sharing a task grants access to that task and its private descendants. Parents
and siblings need separate grants. An agent's access is intersected with its
run's responsible user's current access.
@@ -1020,6 +1036,13 @@ When an additional repository has a configured local checkout, Paperclip seeds t
Sandbox staging, including Daytona, transfers each repository's Git history and working files. Restore merges files and commits back into each local task checkout independently. Durable sandbox recovery keeps the same repository snapshots. Normal ignore and workspace exclusion rules still apply. A clone failure stops task preparation with an error so the agent does not start with only part of the project.
An interrupted legacy run can retain a file recovery hold after its automatic
replay decision is resolved. The task's recovery notice remains authoritative.
After recovering and verifying files from the original workspace, a board member
with runtime access can record the evidence in that notice. This operation checks
the exact source run and stop receipts, leaves the task status unchanged, and does
not start another run. A chat reply cannot clear the file recovery hold.
Staging preserves relative symlink targets in secondary repositories, including skill links such as `.claude/skills/demo -> ../../skills/demo`. It does not rewrite them to host temporary paths or copy their target contents in place of the link. Daytona still rejects outbound archives with absolute or escaping link targets before extraction.
If a repository is detached or its source configuration changes, its previous task copy is retained under `.paperclip-runtime/detached-repositories/` and excluded from future sandbox transfers. Referenced projects continue to use the separate read-only multi-project workspace behavior.
@@ -1363,6 +1386,8 @@ When a workspace service runs Paperclip for browser OAuth QA, configure its `exp
## Heartbeat Service Extractions
Keep relevant heartbeat extractions and their focused tests in `server/src/services/heartbeat/`.
Follow [Heartbeat execution boundaries](../rules/heartbeat-execution-boundaries.mdc)
for state lifetime, admission, recovery ownership, cleanup ordering, and verification.
Runtime-service coordination is in `server/src/services/heartbeat/runtime-services.ts`.
It validates service intents, starts configured services, records adapter-managed
@@ -2270,10 +2295,42 @@ that flushes after the tab hides marks data stale without starting a refetch.
The developer-server health poll also stops in hidden tabs.
Workspace detail responses share concurrent Git inspections and reuse their
results for up to five seconds after completion. The cache holds at most 256
entries. Close-readiness checks, the terminal-workspace reaper, and the final
cleanup validation still inspect Git afresh. A display result never authorizes
worktree removal.
results for up to thirty seconds after completion. Workspace identity and metadata
changes invalidate the cached result. The cache holds at most 256
entries. Close-readiness checks and final cleanup validation request separate
Git scans that cannot join an older in-flight scan. A display result never
authorizes worktree removal.
The terminal-workspace reaper uses the database work coordinator. Startup scans
recover existing workspace rows in bounded pages. Issue status and tree changes,
workspace lifecycle writes, and pull-request work-product writes signal work on
their transaction before writing. The coordinator wakes after the outer
transaction settles and holds idle admission while writes or cleanup are active.
Empty and nonterminal-only lanes have no recurring timer or query. Terminal trees
schedule their actual cooldown deadline; unresolved delivery or cleanup eligibility
is checked again after five minutes. Nonterminal trees, cooldowns, and active runs
are checked before Git. The worker shares Git readiness across compatible rows
that point at one directory within a bounded page. Company, branch, base ref,
and runtime ownership must match. Each row keeps its own task and delivery
assessment, which reuses the task tree read by the early gate. Unchanged terminal
candidates also back off for five minutes during unrelated commit wakes. Scoped
task/workspace hints invalidate
affected candidates; changed tree or workspace revisions invalidate them too.
Deadline selection reuses task trees read by those pages and performs no separate
full-inventory query. Commits during a paged rotation request another bounded
rotation so changes behind its cursor are recovered.
The backoff retains at most 256 candidates and only applies to the background
worker. Final cleanup still checks the current task tree,
delivery evidence, ownership, lifecycle generation, and Git state under the
existing cleanup locks.
These wakes cover the owning `createDb` scope in this server process. Direct SQL
and other server processes require startup recovery. Local deadlines do not
establish external wake-alarm coverage or whole-instance sleep safety. The local
sleep inventory blocks host suspension until bounded recovery succeeds. Cooldown
eligibility is an earliest allowed cleanup time; passive retained directories can
wait for the next wake, when startup restores their rows. Existing idle-sleep
blockers and cleanup admission holds remain authoritative.
The connection-health sweep selects only due IDs in SQL before applying its
limit. Legacy `paperclip_plugin` placeholder connections are excluded: their
@@ -2324,3 +2381,16 @@ companion broker profile and Slack approval. Do not add manager client credentia
to a local `.env` or an open-source deployment. See
[Slack setup and Cloud qualification](connections/slack-setup.md) for the gates,
recovery behavior, and production-component stories.
### Project repository skills
New GitHub project workspace attachments enqueue imports transactionally. A bounded
server worker drains imports and checks enabled sources every five minutes. Shutdown
cancels owned scans and releases their leases. Sources can be refreshed manually or
paused through Skills → Sources. Legacy repositories appear there without being
imported until the user chooses Import skills.
Storybook: **Skills → Project repository skills**. Its production UI journeys use
in-memory provider and execution fixtures. Live GitHub refresh and execution need
separate acceptance evidence. Run the focused browser suite against built Storybook,
or set `STORYBOOK_TEST_BASE_URL` to an owned Storybook dev server.
+52 -6
View File
@@ -72,6 +72,26 @@ the latest agent that assigned it to them. If no assignment is available, it use
the latest other commenter, or leaves the recipient empty. A manual recipient
choice stays selected while task data refreshes.
### Task collection creation filters
Tasks and project lists hide agent-created and system-created tasks by default.
The Filters menu's **show agent-created tasks** checkbox includes routine runs,
recovery/watchdog tasks, chat-channel tasks, and other automation. Channel tasks
remain bot-created for this filter even when a human starts the conversation. The choice is saved per company
and collection; Clear filters restores the hidden default. Nested lists preserve
ancestors and expandable subtasks as context without promoting unrelated automated
work to independent results. Agent profiles, routine histories, and task-detail
subtasks retain their full history.
Inbox membership continues to follow human creation, assignment, comments, and
existing qualifying participation actions, including manually running a routine.
Routine ownership or responsibility alone does not subscribe a person to scheduled
runs; opening or reading a task is not participation. Inbox discovery searches and
Blocked hide unrelated automated tasks unless the checkbox is checked, while
preserving tasks admitted by the existing participation rules. Checking it does
not subscribe the user to all automation. Approvals and other non-task items keep
their existing rules.
### Company Skills and Policy
Company skills are shared operating capabilities, not privileged objects by default. Every authenticated agent in a company can create, import, install, edit, update, test, reset, and remove that company's skills unless the company has configured an explicit restriction.
@@ -80,12 +100,38 @@ The governing rule is: **skill permissions are opt-in restrictions, not opt-in c
Core Paperclip owns the skill runtime, company-boundary enforcement, policy evaluation contract, API denials, validation, path containment, secret redaction, and activity logging. Those safety invariants cannot be disabled by policy. Open-by-default skill work never authorizes arbitrary host-path reads, unsafe executable content, or policy edits: local imports and scans must stay within Paperclip-known workspace or managed-skill roots, remote sources must resolve to validated immutable content, and platform safety denials must stay distinct from optional administrative restrictions. Paperclip EE may provide detailed administration for per-agent, per-role, per-action, per-source, and protected-skill rules, but EE is not required to use skills and is not an enforcement boundary. Without EE, companies remain open by default and any already-configured restrictions continue to be enforced by core.
GitHub repositories are first-class sources within Skills. People import selected
skills through their existing GitHub connection and manually refresh installed
snapshots. The source records repository, branch, path, and installed commit;
the connection supplies caller-authorized access. Originals remain viewable and
testable, with independent editable copies. New upstream skills require selection,
and deselection, source disconnection, or upstream removal retains installed content.
GitHub repositories attached to new projects automatically become skill sources.
Paperclip imports their skills and checks the configured branch every five minutes,
using the setup person's authorized GitHub connection. New skills import automatically
unless excluded. Existing projects can adopt their repositories from Skills → Sources;
existing manually imported sources preserve their selections and gain automatic updates.
Refresh remains available, and operators can pause automatic updates.
Independent skill sources have a searchable branch picker with the repository's
default branch marked. People can also enter a branch name that is not listed.
Saving checks GitHub access and the selected ref before changing tracking; failed
saves keep the selection and installed content. Project refs remain owned by project
configuration so changing a source cannot redirect another project's tracking.
If a tracked repository grows beyond the supported package size, its installed
repository skills and shared dependencies remain available until a safe refresh
can succeed. Initial oversized imports can use self-contained skill packages;
packages with omitted dependencies are invalid and are not installed.
Project-derived skills inherit current project access. Access through any originating
project is sufficient, including the responsible-user restrictions on agent execution.
Existing explicit company imports retain their visibility. Editable copies inherit
project restrictions; private content cannot be published or exported implicitly.
Detachment retains installed content and access provenance. Deleting its last project
never makes a skill company-visible.
Task and routine skill mentions remain stable references to the latest installed version.
Each execution records the immutable versions it uses; resuming keeps those versions,
while a new execution resolves latest again. Upstream failures and removals preserve
installed snapshots. GitHub refresh does not delay task execution.
Disconnecting removes a repository from Sources after an explicit choice: keep
independent editable copies in My Skills, or delete its imported skills. Kept
copies and derived forks retain their project access restrictions. Copies preserve
agent assignments; skills used by agents must be detached before deletion.
An explicit restricted policy may deny selected operations or switch to a default-deny preset with explicit allow rules. Core exposes a stable versioned policy API so EE and other administrative clients configure and simulate the same evaluator used by skill mutation routes. Core Skill Studio only needs to perform normal skill work, explain an explicit denial, and point administrators to EE when its richer policy UI is available; it must not recreate a partial enterprise permission editor.
+113 -7
View File
@@ -170,6 +170,7 @@ Invariant: every business record belongs to exactly one company.
- `permissions` jsonb not null default `{}`
- `last_heartbeat_at` timestamptz null
- `metadata` jsonb null
- `created_by_user_id` text null; the human user who created or requested the agent. Null for agent-requested and system-created agents. The agent overview shows it only when the company has more than one human member; the local Board principal is never counted or shown.
Invariants:
@@ -1130,6 +1131,10 @@ identity shows no failed runs. All retains company-wide failed-run visibility.
Company health alerts do not contribute to the personal inbox badge.
Run list responses, including summaries, retain `responsibleUserId`.
Live task and run toasts require personal task participation or an explicit user
mention, independently of read access. Agent ownership and responsible-user
attribution alone do not qualify. See [toast semantics](TOASTS.md).
Ownership split:
- **Core / Free:** permission key and scoped-grant enforcement; responsible-user resolution; default-open, disabled, and allowlist policy modes; archive/unarchive APIs; per-user archive persistence; resurfacing behavior; activity audit records; and stable denial codes.
@@ -2012,9 +2017,11 @@ unavailable. Preserve current ownership and newer-work fences. See
reduced-motion-aware animations and shows indeterminate progress while saving
complete packages, without inventing completion percentages.
- Sources and entries are company-scoped. Reuse GitHub connection grants and credential
refresh; every provider read authorizes the current caller. Saved connection IDs do
not confer access to another user's token. Agent reads use managed run identities.
- Sources and entries are company-scoped. Discovery and connection changes authorize
the current caller. Automatic and manual source refresh use the stored setup person's
connection and grant, revalidating their access and refreshing credentials on each
check. Saved connection IDs do not independently grant library visibility. Agent
setup derives the responsible person from the authenticated run identity.
- The import picker searches the deduplicated union of repositories from all connections
the caller can access, automatically choosing an authorized connection. Adding accounts
uses the standard GitHub setup in Apps and retains the import draft. Repository URLs
@@ -2075,16 +2082,55 @@ unavailable. Preserve current ownership and newer-work fences. See
and history. New key collisions cannot overwrite unrelated skills. Only changed package
bytes or executable modes create versions. Library reads, tests, and subsequent unpinned
runs use local installed snapshots; pinned/active runs retain their versions.
- Additions require reviewed selection, with new candidates checked by default and
- Manually selected sources retain reviewed selection, with new candidates checked by default and
explicit folder exclusions retained. Upstream deletion keeps installed content with
removed status; moves are removal plus discovery. Deselect/disconnect retains content
removed status; moves are removal plus discovery. Deselect retains content
and assignments. Originals are read-only, with the existing independent fork workflow.
- Source disconnection requires a saved revision and an explicit copy/delete choice.
Remove the source and all entries to allow a fresh repository import, including
legacy disabled sources. Copy materializes complete local files in the caller's
My Skills folder, retaining skill IDs, keys, versions, and agent assignments.
Delete applies skills.remove to every linked skill (including deselected entries),
rejects skills still used by agents, and removes skills and source atomically with
the activity record. Copy applies skills.edit and skills.create to every linked
skill; failed writes or audit persistence leave the source and imported skills intact.
- Adopt recognizable existing GitHub imports without provider calls or content changes;
resolve missing repository IDs and full snapshots on successful refresh. Exclude bundled,
catalog, local/project, skills.sh, and unsupported hosts. Existing GitHub import and update
endpoints delegate to sources while retaining response shapes.
- GitHub.com, manual refresh only. No upstream editing, polling, webhook sync, commits,
or pull-request creation in this milestone.
- GitHub.com project repository attachments enqueue durable skill-source import jobs in
the project mutation transaction. Skill import completes asynchronously and cannot
fail project creation. Configured refs use the existing project workspace precedence;
absent refs track the default branch. Sources without skills remain tracked.
- Enabled sources check upstream every five minutes; unchanged commits avoid downloads.
Manual Refresh uses the same serialized publication pipeline. Automatic updates may
be paused independently of selection. Project sources select future additions unless
excluded; existing manually imported sources retain their selections. Legacy projects
adopt through an explicit company-scoped, project-authorized endpoint, never a GET.
- Repository size fallback must not discard installed shared dependencies or
publish packages with detected omitted dependencies. Retain affected versions
and report the size problem. Self-contained packages can still update through
fallback. Project sources retry complete repository packaging and return to it
when supported; selections and exclusions remain unchanged.
- Unattended refresh stores setup identity and connection/grant identifiers, never token
values. Current membership, connection authorization and skill policy are revalidated.
Unrecoverable legacy setup identities require explicit connection repair. Retries are
bounded and backed off; leases survive restarts and shutdown cancels owned downloads.
- Project-derived skill visibility is the union of current originating project audiences.
Core uses project authorization, including agent/responsible-user intersection, for
discovery, reads, mutations, files, versions, tests and runtime delivery. Unauthorized
IDs return not found. Company imports retain their existing visibility. Forks preserve
project provenance. Unsupported public publication or portable export is rejected.
- Detachment retains installed content and project access provenance while stopping that
project's tracking. Ref replacement never rewrites existing references. An orphaned
project source remains restricted after its last originating project is deleted.
- Executions resolve unpinned references from local immutable versions, persist the
resolved inventory, and reuse it on resume after rechecking access. Explicit unavailable
references fail actionably rather than silently omitting instructions. Background
GitHub checks never delay execution. Existing version pins remain supported.
- Upstream editing, push webhooks, commit/PR creation and advanced reference pin UI
remain outside this release.
## Public assistant connection (opt-in)
@@ -2174,3 +2220,63 @@ See [the layer architecture](plans/2026-10-09-task-workspaces.md) for resolution
## Company fast-response service
Companies may configure an optional shared API connection and model for short acknowledgements of accepted human turns. Fast responses use direct SDK inference alongside normal agent work, with a three-second admission deadline, bounded prompts/output, current authorization and independent `fast_response` accounting. They are server-marked platform receipts attributed to the agent, never completion, interaction or recovery evidence. Company-sponsored unlinked external senders are explicit; linked-user permission denials are never bypassed. See [fast-responses.md](fast-responses.md) for provider, delivery, history and endpoint contracts.
Project-derived source removal retains dynamic project access for kept editable
copies and forks. A removed source is absent from Sources and cannot refresh;
ordinary repository attachment does not restart it. Explicit project adoption can
restart tracking without widening the retained content’s access.
Codex execution homes are scoped to the agent’s authorized skill inventory,
including its immutable source versions and an empty inventory. Revocation and
version changes select a separate home and session store while retaining the
selected model account’s credential source. Repository skill auto-update trusts
its upstream authors; operators can pause updates to review changes manually.
### Task collection creation visibility (2026-10-13)
Tasks and project collections default to hiding agent/system-created tasks and
provide a saved **show agent-created tasks** filter. Classify creation using
creator identity and origin; assignee/responsible users do not imply human
authorship. Routine executions remain automated even when manually triggered.
Creator-less ordinary tasks are system-created. All chat-channel tasks count as
bot-created for this filter, including human-initiated inbound conversations.
Human ordinary and onboarding tasks remain visible. Apply collection creation filters before search limits and
pagination, and retrieve hierarchy context separately under existing access checks.
Context does not count as independent results or board cards. Bounded context
reads retain loaded rows while users reveal more of the tree.
Inbox membership, archives, unread state, and badges retain existing participation
rules, including assignment, comments, and manual routine runs. Responsibility and
read-only activity do not admit scheduled work. Inbox discovery/Blocked preserve
participated automation and hide unrelated automation by default. Agent profile
history, routine history, and task-detail subtasks remain complete. API consumers
that omit the optional creation filter retain their existing list behavior.
Project-derived editable forks retain the project audience present when created.
Later repository attachments do not grant access to those edits. Re-adopting a
removed source uses a separate active tracking identity; retained copies keep
their original provenance. Project membership and visibility remain dynamic.
Automatic skill checks compare tree identity as well as commit identity, so
empty commits do not download or rescan content. Automatic scan work uses a
durable per-source 512 MiB allowance with 512 MiB/hour refill; installed versions
remain usable when it is temporarily limited, and authorized manual Refresh
remains available. Initial imports authorize skills.import before provider work.
At most 20 jobs per project and 100 per company enter the active initial queue;
additional repository bindings remain durable and are admitted automatically
when capacity frees. Project workspace create/update/delete use the existing
workspace-write authorization evaluator. Policy-denied initial jobs await explicit
adoption/repair rather than repeatedly scanning.
Agent-created project sources may reuse only the GitHub connection and grant
already authorized in the persisted active run identity. The responsible person
is recorded for attribution; that identity alone does not permit searching other
personal connections. Without a selected run grant, Sources requires an explicit
human connection repair before background import or update.
Automatic initial repository imports reserve durable company work credits before
provider reads: 512 MiB capacity, refilling 512 MiB per hour, with a 128 MiB
reservation per attempt. Failed downloads and package fallback keep the full
reservation. Successfully linked small imports refund unused measured work.
Completed bindings do not reset company credits; waiting jobs retry on refill.
The company_skill_import_budgets table stores no credentials or source contents.
+75
View File
@@ -0,0 +1,75 @@
# Toast semantics
Toasts are transient feedback, not a company activity feed. Live task notifications
are personal to the connected human, including in multiplayer and `local_trusted`
mode (`local-board`). Access to a task does not subscribe someone to notifications.
## Which tasks qualify
A task qualifies when the viewer created it, is its current human assignee,
authored a comment, or performed a deliberate action included in the existing
Mine participation allowlist in
[`issue-participation.ts`](../server/src/services/issue-participation.ts).
Read receipts, denied requests, and automatic read-time recovery cleanup do not
count. Comment authorship follows Mine's existing historical participation rule.
A task also qualifies when its current description or a non-deleted comment
contains an explicit mention of the viewer: `[Name](user://USER_ID)`. The shared
user-mention parser resolves the exact user ID; plain names and bare URLs do not
count. Existing comments are checked, so users need not have opened the task.
The event introducing the first mention can notify immediately. Removing the
only mention removes that qualification unless another participation rule holds.
Historical comment lookup uses an exact viewer-link regex backed by the existing
comment-body trigram index and returns at most one body for the shared parser.
Agent ownership, primary-agent preference, task/run `responsibleUserId`, company
membership, and involvement in a parent task do not qualify on their own.
Activity by any person or agent can notify a qualifying viewer. These rules do
not change Mine membership, task permissions, assignment, or inbox archive state.
## Events and suppression
| Event | Toast behavior |
| --- | --- |
| Task created, updated, or commented on | Requires personal task eligibility. The viewer's own activity stays quiet. |
| Run failed, timed out, or cancelled | Requires eligibility for the persisted run's task. An event's task hint or agent identity is not sufficient. |
| Agent error without a task, or run without a task | No live toast. Status remains available in company views. |
| Run started or succeeded | No live toast. |
| Save, Copy, and other direct action feedback | Existing caller-owned feedback is unchanged. |
| Company join request | Existing join-request notification behavior is unchanged. |
Eligibility is an additional gate, not a promise that every event produces a
toast. Existing rules still suppress activity for the task in view and run
outcomes already represented by the visible task/run tree. Comment-driven updates
can be combined with their paired comment event when that metadata is available.
Intentional operator interruptions and workspace contention do not announce run
failures. Duplicate terminal outcomes and failures older than five minutes (when
timestamps are available) remain quiet. Reconnect suppression, per-category rate
limits, content deduplication, and toast lifetime limits remain in effect. Hidden
pages reconcile their data on return without replaying a notification backlog.
Archiving a task is not a notification unsubscribe.
## Delivery contract
The company WebSocket authorizes each event before evaluating relevance. Its
viewer-specific copy of the shared `LiveEvent` envelope contains `toastEligible`.
Only `true` permits a live task/run toast. Missing/false values, unresolved viewer
identity, and relevance lookup failures stay quiet. Agent-authenticated sockets
do not receive human toast eligibility. This field is computed per connection,
never persisted or published on the shared company event bus.
Authorized events still reach cache handling and component subscribers when
eligibility is false. Lookup failure is logged but does not discard the authorized
event. Existing task/run privacy checks and payload redaction remain in force.
When an authenticated comment event omits the comment ID, the visible task thread
refreshes through its authorized HTTP read instead of trying to hydrate the comment.
Closed sockets cannot deliver stale notifications after account/company changes.
No client-side task-list cache or new database migration is required. During a
mixed-version rollout, a new client receiving events from an older server stays
quiet until the server provides eligibility.
## Verification
See [`inbox-search/toasts`](../maps/feature-map/inbox-search.md#toasts) for the
two-user browser recipe and linked regression suites. The map describes coverage;
it is not evidence that a particular deployment passed that journey.
@@ -1,15 +1,26 @@
# Rich ACP integration and qualification report
## Current source integration — 2026-10-12
## Current source integration — 2026-10-14
Pi profile 25 (`sha256:dd67387487dadb08da76534c057dc0aa059f7698d1779cbd5fc452813828167a`)
advances the shared sandbox source attestation after Claude settings initialization
moved behind provider lifetime ownership. Profile 23 remains an immutable
historical identity. Pi's provider executable closures, model/effort options and
platform qualification are unchanged; retained live evidence keeps its literal
profile/source identity. Copilot remains pending at profile 18. Current package
profile/source identity. Copilot remains pending at profile 19. Current package
and source controls are separate from those retained provider execution results.
The actual Codex squash `adb69e8f09852c772d9901ae270e5b2d66e39c77`
already owns Copilot profile 18 for the Grok descriptor schema. Its immutable
fixture is retained. The combined Claude effort sources use profile 19
(`sha256:a4c7e955df18bf2448224ecce2120b43ede8054fe00e7b33b4044b8bd284b321`),
with executable, permission policy and pending qualification unchanged. The
prior unmerged Claude profile-18 attestation is retained separately as
`copilot-profile-v18-claude-qualification-identity.json`; earlier evidence keeps
its literal source. Pi profile 25 and its source digest remain unchanged by
this reconciliation. Existing settings and effort/session admission still need
final packaged and real-provider qualification on the composed Claude source.
## Historical integration — 2026-10-08
The experimental Runner admits **Pi profile 22** (`sha256:e92078bee3c23bec4100aa589013a44613d054cd686826534025d8019e9f39a9`) and
+7
View File
@@ -5,6 +5,13 @@ and shipping Paperclip app connections.
Status: canonical end-to-end authoring guide for Apps v2 catalog connections.
Experimental voice connections use the same company-scoped channel endpoints,
vault, task bindings, delivery ledger and publications, with `transport: voice`
and an explicit runtime rather than Chat SDK. Do not expose voice transport as
an MCP tool connection. Speko's browser implementation and its remaining phone
qualification gate are documented in the [native voice report](../plans/2026-10-09-speko-pr-qualification.md)
and [E2E runbook](../plans/2026-09-11-speko-voice-e2e-runbook.md). The optional
Company Phone Agent is a catalog template; selecting it must remain optional.
For connector artwork, follow [Connector icons](./CONNECTOR-ICONS.md): fixed gray Paperclip frames, authentic vendor artwork, explicit theme variants, optical fit and exact provenance. Brand-library additions do not activate connectors. Use the shared registry/resolver and branding generator; do not introduce per-screen logos or outer-surface overrides.
This runbook is the repeatable, agent-executable procedure for adding a vendor
+39
View File
@@ -188,6 +188,9 @@ old runs cannot publish over the latest head. One current summary is updated in
place, with history and task/run links retained. Stable finding keys prevent
duplicate inline comments on repeated reviews.
See [Publication recovery](#publication-recovery) for deadlines, retries, and
lost-response receipt recovery.
The check's **Details** link opens its Paperclip task on the current instance
hostname, or the connector's Reviews page when no task has been created yet.
@@ -206,6 +209,42 @@ where supported. Paperclip does not change repository rules. GitHub account and
repository plan restrictions may limit required-check enforcement. If automatic
execution is disallowed, a gated head requests an authorized manual review.
## Publication recovery
GitHub bot tools have a sixty-second default deadline. A caller can request a
shorter deadline. The assessment and publication intent are saved before provider
writes, so a caller timeout does not prove that publication failed.
Temporary network errors, HTTP 408/429, and GitHub server errors use bounded
backoff with jitter. Reads and installation-token issuance can retry within the
call. Publication writes retry through the durable outbox, where App-owned
comment markers and check identities recover lost responses. An unknown write
is never repeated without checking its existing provider receipt.
The caller waits for up to three publication attempts within a forty-five-second
retry window. Longer delays remain queued. A dedicated worker restores received
actions and future retry deadlines after restart without another inbound event.
The durable limit is eight failed attempts. Authorization, configuration, and
the current PR head are checked again before dispatch. Permanent permission or
validation failures, changed authority, and superseded reviews stop retries.
Rate-limit retries respect GitHub's `Retry-After` and primary reset headers;
secondary limits without a deadline wait at least one minute. See
[GitHub's retry guidance](https://docs.github.com/en/rest/using-the-rest-api/best-practices-for-using-the-rest-api#handle-rate-limit-errors-appropriately).
Repeat the exact `submit_review`, `comment`, or `update_comment` call to receive
the current durable receipt after a timeout. Preserve the assessment and
idempotency key; do not start another review to recover publication. A result
with `status: failed` and `receipt.retryable: true`, or `status: received`, is
still pending. Claim publication only after `status: processed`. Receipt recovery
does not itself mark a task Done; the agent must finish its task after confirming
the receipt.
For a call that required human approval, the durable publication keeps that
verified approval for its exact operation. An exact caller retry only reads the
current receipt; the worker owns provider retries. A new policy denial or revoked
authority still stops recovery, and new content still requires its own approval.
## Hosted ingress
Dedicated Apps use Cloud as a sealed transport gateway. Cloud routes opaque
+26 -2
View File
@@ -47,11 +47,19 @@ incomplete assessments require action. To block merging, separately require this
check from the dedicated App in GitHub branch protection or a ruleset. A new head
commit needs its own check. Report-only mode publishes a neutral conclusion, which
GitHub can accept for a required check; it does not enforce a score requirement.
This includes incomplete assessments and failed runs: their checks remain neutral
and explain the failure without presenting a passing assessment.
A passing score does not formally approve a PR. **Approvals and change requests**
contains those optional agent permissions. Scheduling filters, ignored files,
and inline-comment options have separate disclosures. The header shows the App
identity, copyable mention, avatar download, and GitHub branding settings.
Published review summaries use the GitHub bot's display name in their heading.
The check name remains **Paperclip Review**. Multiple bots can review the same
PR through separate GitHub Apps: each keeps its own task, summary, findings, and
check. Check updates match both the App ID and the endpoint/PR/commit identity.
Repository branch rules decide separately which App's check is required to merge.
## Self-hosted setup
The setup screen states the default access in one line, with **Change** for
@@ -207,8 +215,18 @@ claims. It does not exchange codes, track App or installation identity, store
GitHub secrets, or interpret bot events. It forwards original webhook bytes,
provider headers, and signature in an envelope sealed to the stack before
writing the inbox. The stack decrypts and authenticates those bytes through its
existing durable ingress. Only that local check can verify a connection or
admit work. Shared-App account connectors keep the behavior described above.
existing durable ingress. Cloud-managed Apps are excluded from the direct-tenant
callback recovery scanner and its callback-mismatch warning; the Cloud inbox owns
relay delivery retries. Only that local check can verify a connection or
admit work. After a repair, a fresh authenticated event for the bound installation
can verify webhook delivery even when the relay deduplicates a redelivered old ping.
This also applies while the connection needs attention: the signed event verifies
delivery without retaining its content, admitting work, or changing repository
access, even when its repository is disabled or unavailable. Verification returns
the connection to the provider-setup step; later installation events cannot
activate it. The manager must still complete reconnect and activation before new
review requests can run.
Shared-App account connectors keep the behavior described above.
Unverified gateway traffic has request, byte, pending-queue, retention and wake
limits. Its transport deduplication includes the body and signature, so a forged
@@ -225,6 +243,12 @@ an agent runtime can execute a review.
### One editable response per request
A pull request task can retain both its main discussion and inline finding
threads. Bot tool discovery lists each endpoint/catalog tool once across those
threads. Publishing an inline finding therefore does not duplicate the tool
catalog on the task's next run. Both conversation mappings remain available for
authorized follow-up replies.
After accepting authorized GitHub work, Paperclip posts **Working on this…**
before starting the agent. Issue and PR discussion comments use the same GitHub
comment API; inline-review conversations receive an inline reply. Description
+12 -8
View File
@@ -198,16 +198,20 @@ people's bot DMs remain inaccessible. Scheduling uses ordinary Paperclip routine
not a Slack-specific timer. Routine results are sent explicitly through the tool;
ordinary task finals are not automatically broadcast to Slack.
## Require an at-mention for inbound messages
## Require an at-mention for inbound channel messages
Slack app settings include **Require at-mention** directly below **Allow direct
messages**. It defaults to on for new Slack connections. Existing connections
keep their saved setting and thread and DM behavior.
When enabled, each inbound message must explicitly @mention the connected bot,
including replies in existing channel threads and direct messages. DMs must also
be enabled with **Allow direct messages**. Unmentioned messages do not create
or continue a task. Queued messages are checked again before starting agent work.
If a queued run combines several messages, an unmentioned input cancels that
queued run when this setting is enabled. Send a new mention to start it again.
keep their saved setting; the setting applies only to channels.
When enabled, each inbound channel message must explicitly @mention the connected
bot, including replies in existing channel threads. Direct messages never require
an @mention, but must be enabled with **Allow direct messages** and pass the usual
sender authorization checks. Top-level DMs remain a linear conversation with
top-level replies; use a private channel for conversations organized into threads.
Unmentioned channel messages do not create or continue a task. Queued messages
are checked again before starting agent work. If a queued run combines several
channel messages, an unmentioned input cancels that queued run when this setting
is enabled. Send a new mention to start it again. Unmentioned DM inputs do not
trigger this cancellation.
This setting does not cancel work that has already started or revoke its Slack
tool access.
+15
View File
@@ -1025,6 +1025,14 @@ In the normal non-terminal case, critical silence remains a UI signal and does n
Source-resolved watchdog folding concerns stale active-run bookkeeping after a valid terminal disposition. It does not infer productivity from run counts, comment frequency, or elapsed task time.
Terminal task activity does not prove that the execution runtime has finished.
The scan leaves native runs with their native lifecycle owner. An active managed
environment lease, running or failed workspace finalization, or recorded
copy-back failure also prevents folding. These obligations are checked before
local process cleanup and again when the run is committed. The owning runtime
or its bounded recovery saves the files and settles the run; the watchdog does
not replace that work with a successful result or release its execution locks.
Detached process cleanup is operational hygiene, not source issue liveness. Cleanup should be best-effort and auditable. If cleanup fails but the source issue is already terminal with same-run durable evidence, Paperclip should preserve the cleanup failure on the run/watchdog audit trail and route only the cleanup concern to bounded recovery when a real owner/action remains.
## 13. Auto-Recover vs Explicit Recovery vs Human Escalation
@@ -1620,6 +1628,13 @@ URL, and token together through the launch allowlist; unrelated environment
secrets remain excluded. This does not restrict arbitrary network access to a
public service outside the gateway.
Tool discovery collapses identical descriptors with the same gateway name for
every provider. Native assigned-tool projection applies the same rule at startup
and during fresh discovery. A name with conflicting schemas, risk, or source
bindings remains an error; distinct names retain separate tools. Discovery does
not grant execution authority: calls still use the existing gateway policy,
approval, revocation, and audit paths.
### Use real connection requests (2026-09-14)
+47 -1
View File
@@ -15,7 +15,8 @@ Company members and agents cannot read this report.
300 seconds. Save the returned `ownerId` and `expiresAt`. An existing drain
returns 409. An unsupported purpose must leave automatic sleep disabled.
3. Poll the report with that exact owner. Only
`{ "version": 1, "backgroundWork": "none" }` permits sleep. Require the same
`{ "version": 1, "backgroundWork": "none" }` permits ordinary idle sleep. The
optional routine protocol below requires a durable host alarm as well. Require the same
`ownerId`, `draining: true`, zero run/wake counters, and enough remaining TTL
for the provider stop. `present`, `unknown`, missing fields, or errors must
keep the instance awake. Do not interpret `quiescent` alone as authorization.
@@ -35,6 +36,44 @@ signed bootstrap writes. Only the task-drain read skips request tracking.
Its authentication finishes under a separate work token before entering the
report, so it counts concurrent writes without blocking on its own scan.
## Scheduled routine wake protocol
Verified signed Cloud control callers may opt into
`GET /api/instance/task-drain?idleSleepSafety=1&scheduledWake=1&ownerId=<owner>`.
Tenant tokens, browser instance administrators, local implicit actors, and agents
cannot request this extension. Ordinary reports retain their existing behavior.
If all other background-work checks pass, active routines may return
`idleSleepSafety: { version: 2, backgroundWork: "none", scheduledWake }`.
The proof has `version: 1`, `kind: "routines"`, a SHA-256 `generation`, and the
earliest `nextWakeAt` across every company. Only enabled, unarchived schedule
triggers with valid cron, timezone and future `next_run_at` qualify. Unsupported
triggers, setup work, due work, unknown states and more than 10,000 active
triggers keep the instance awake. Inactive triggers do not create obligations.
Active routines without enabled triggers have no timed work. Definitions are
read in the same repeatable-read transaction as the other durable checks.
The host must commit one durable alarm for the exact stack under its live sleep
lease before stopping compute. It must then re-read the same owned report and
require the exact generation and deadline. Generation binds the process, hold
owner and routine/trigger catalog, so restart or schedule edits invalidate it.
No routine definitions or tenant identifiers appear in the proof. Failure to
persist or validate the alarm abandons sleep. Cloud acknowledges persistence
inside its controller; this report alone never authorizes scheduled sleep.
Cloud must start waking early enough for measured startup latency and retry
failed or missed wakes across controller restart. After wake, the existing
routine scheduler owns execution, atomic claims and catch-up rules. Local
scheduling is unchanged for self-hosted instances and whenever Cloud declines
sleep. This first extension covers routines only. Agent timers, plugin jobs,
retries, integrations and unsupported queues retain their existing blockers.
All mutations must enter through the host admission/wake path. Independent
database writers are outside this single-process protocol.
Verify a full scheduled sleep/wake/execution cycle on staging before enabling
this host capability. The [tests](../server/src/__tests__/idle-sleep-safety.test.ts)
cover ownership, future deadlines, changed generations and conservative fallback.
## Retry history
Retry promotion keeps `scheduled_retry_at` on a run for inspection. That date
@@ -84,6 +123,13 @@ running the timer while asleep. A generation counter invalidates a
scan if tracked work both starts and finishes during inspection. Reports remain
unknown until startup recovery and HTTP tracking are installed.
Terminal workspace recovery also registers a local sleep probe. Incomplete
startup pages and failed recovery remain blockers until a successful pass.
Active cleanup and unresolved producer transactions retain their admission holds.
Cooldown and inspection-backoff timers are maintenance hints over retained domain
rows. They can wait for the next wake and are restored at startup; they do not
create external alarm coverage or exempt other persisted work from this report.
### Backup checkpoints for idle instances
`PAPERCLIP_DB_BACKUP_IDLE_CHECKPOINT_ENABLED=1` opts an instance with automatic
+84 -2
View File
@@ -35,6 +35,46 @@ leave tar/Git children alive, so incomplete copyback requires operator stop
verification even on the same host. PID reuse is checked against its recorded
start time rather than trusted by PID alone.
## Automatic cloud recovery
New Railway copyback receipts record the exact project, environment, service and
deployment ID. On takeover, the existing finalization reconciler asks the cloud
harness to inspect that deployment. The harness resolves the stack's owned
resources independently and issues a short-lived Ed25519 receipt only when the
exact deployment is `REMOVED` with `deploymentStopped: true`. This covers all
processes in the deployment, including orphaned copyback children. Missing,
truncated, live or unavailable provider evidence leaves the physical fence intact.
The tenant verifies the configured harness key, disjoint receipt audience, stack,
run, owner token, deployment identity and expiry. It records proof and an activity
entry when replacing only the exact owner under the existing advisory lock. The
normal reconciler resumes the accepted result; it does not create a provider turn
or change approval/monitor waits. A changed owner during verification fails closed.
Stop proof alone does not authorize old work to overwrite a current task. After
the provider read, automatic recovery uses the operator path's shared binding
checks under short coordinator, issue and run row locks, atomically with the
owner claim. The task must still be open, assigned to the run or its authoritative
review participant, and bound to that running native execution and accepted
result. A different checkout, newer execution or queued/running legacy execution
prevents takeover. Publication checks repeat this validation; row locks are never
held across physical copyback I/O.
The harness endpoint is `POST /v1/tenant/workspace-worker-stop`. The fleet-wide
server token authorizes a read request, never stop evidence: responses must be
signed by the harness. This endpoint requires the companion cloud harness change.
Deploying only the application keeps unknown owners fenced. No cloud provider
credentials are delivered to tenant applications.
The task view shows only “Restoring saved work…” after the server confirms recovery
or an operator queues it,
then removes the notice when commitment resolves recovery. It exposes no process
identifiers, shutdown form or manual resume control. Legacy receipts without
platform identity and unsupported platforms say operator assistance is needed;
operators use the documented exact-owner API below after independent stop proof.
The three diagnosed historical receipts do not gain a deployment identity merely
by upgrading. Never infer one from elapsed time or a hostname.
## Unverified copyback after controller replacement
Generic orphan recovery does not turn a missing provider PID into `process_lost`
@@ -66,6 +106,48 @@ exact prior controller **and its copyback subprocesses** have stopped. Retain th
sandbox, accepted native result, and workspace descriptor. Do not run a new
provider turn, delete workspace contents, or relax archive confinement.
For legacy receipts, an authorized company owner, company administrator or
instance administrator records independently verified platform evidence through
the operator API. The task has no shutdown form or resume control. The API is
`POST /api/issues/:id/recovery-actions/resume-workspace-finalization` with:
```json
{
"actionId": "<recovery-action-id>",
"runId": "<run-id>",
"ownerToken": "<owner-token-from-recovery-evidence>",
"controllerAndCopybackStopped": true,
"stopEvidence": "<deployment-platform evidence for this controller and its children>"
}
```
This is an operator attestation, not an automatic deployment-platform probe.
The separate `runtime:confirm_owner_stop` authorization action limits this
attestation to active company owners or administrators, the trusted local board,
or an instance administrator. Ordinary runtime managers and agents cannot release
the physical owner receipt. Missing role data keeps the client notice read-only.
A
missing advisory connection alone is insufficient. Admission rejects an active
copyback lock, an observably live local controller, a changed owner, a newer run,
or an unbound result. It records the exact owner and operator evidence atomically
with releasing the receipt. The accepted result, workspace descriptor, source
lease, task status, monitors, and approval waits are unchanged. The ordinary
reconciler performs copyback and applies the saved result through the status
arbiter. No provider wake is enqueued. The recovery action remains visible until
finalization commits. Admission supports saved-result copyback from `result_accepted`,
`workspace_finalizing`, and `retryable_failure`; an abandoned retry does not need
a replacement run. The existing retry schedule remains unchanged.
Repeating the same confirmation before reconciliation is
idempotent; it cannot release a newer owner. Generic recovery resolution, including
false-positive dispositions, cannot dismiss this hold or bypass saved-result
finalization.
Repeated sweeps preserve these copyback-specific instructions, including for
older actions whose recovery budget was already exhausted. They must never
recommend starting a replacement provider run for this hold.
For older servers without this action, the maintenance fallback follows.
After that platform verification, use a database maintenance transaction to
release only the exact receipt shown by the recovery action. Replace the four
placeholders with the action's company, run, token, and source issue. The advisory
@@ -138,8 +220,8 @@ A board member with runtime management access can complete the saved result:
the export failure while preserving all user files. Restore transport access
or other provider prerequisites before retrying. Extending the sandbox
retention window can be necessary during this repair.
3. In the task's **Workspace export needs repair** notice, describe the repair and
choose **Retry workspace export**. The equivalent board API is
3. Use the operator API to record the repair and request export-only retry. The
task shows operator assistance is needed, without an infrastructure form. The board API is
`POST /api/issues/:id/recovery-actions/retry-workspace-export` with
`{ "actionId": "<recovery-action-id>", "runId": "<run-id>", "repairNote": "<repair and preservation evidence>" }`.
4. Confirm the same run commits, the saved result determines the task outcome,
+115 -3
View File
@@ -161,6 +161,39 @@ This document also holds three local instrumentation contracts: native runner
traces, sandbox startup traces, and sandbox duplex transport instrumentation.
Those sections follow below.
## Controller preparation phases
With an operator OTLP endpoint, `paperclip.heartbeat-preparation` emits active
`heartbeat.prepare.<phase>` spans around environment selection, execution
configuration, session preparation, workspace preparation, GitHub environment
and launcher preparation, run output initialization, workspace validation,
runtime services, instruction files, and runtime selection. Database and HTTP
instrumentation can attach child spans during each awaited operation.
Execution configuration also records separate phases for mentioned skills,
GitHub identity selection, secret resolution, managed AI runtime preparation,
skill inventory, connector assignments, connector skill preparation and delivery,
connection instructions, and agent identity. Their names are
`heartbeat.prepare.configuration_<step>`, using the closed names in
`server/src/services/heartbeat/preparation-timing.ts`. These intervals are inside
`execution_configuration`; do not add them to its duration. They remain available
when a later setup step fails before the provider lifecycle trace starts.
Each phase starts a new root trace and links to the active trigger span when
one exists. An unsampled HTTP request must not suppress diagnostics for the
background run it starts. Root traces still follow the operator's configured
sampler. The trigger's trace remains unchanged, and overlapping runs keep
their own phase and child contexts.
These spans exist before provider dispatch, including setup failures. Each has
only the existing `paperclip.task.run.run_id` attribute: the first 12 hexadecimal
characters of the run UUID's SHA-256 hash. Failed operations set error status
without recording exception messages, paths, inputs, or returned content.
Search by that hash without a root-name filter to include these preparation
traces; the provider lifecycle trace is created later and can have a different
trace ID. Without an endpoint, tracing remains a no-op. These spans add no
first-party Telemetry events or database run-log writes.
## Native Runner Trace Spans
Paperclip Runner task runs emit a single foldable OpenTelemetry trace. This is
@@ -171,6 +204,12 @@ ends before outer workspace persistence. The heartbeat-owned local run-log
every other native span carries a real OpenTelemetry parent context rather than
only a descriptive `parentName` field.
The native lifecycle root uses the operator's root sampling policy. It links
to a valid active trigger trace without inheriting its sampling decision.
An unsampled HTTP request therefore cannot suppress an otherwise sampled
background run. An operator who disables root sampling still gets no spans.
Without an OTLP endpoint, tracing remains silent and does not export data.
The run link in Honeycomb matches both `task.provider_session` for native runs and `task.run` for legacy adapters. It retains the exact hashed run-ID and service filters and groups by trace ID. The URL builder uses Honeycomb’s supported `in` operator for the two root names; see the [query specification](https://github.com/honeycombio/honeycomb-mcp#query-specification-for-run_query). This changes only the query link. The operator endpoint gate and span attribute allowlist remain unchanged.
The canonical lifecycle is:
@@ -434,15 +473,71 @@ below.
### Run failure context
Terminal run failures also carry the run and task IDs, adapter, error code,
run status, and redacted error message. Their fingerprint is the error code
and adapter. These fields are passed directly to that event's capture call.
Run failure reporting requires a separate operator choice in addition to the
backend Sentry DSN and the audited SDK. Set `PAPERCLIP_SENTRY_RUN_FAILURES` to:
| Value | Reports |
| --- | --- |
| `off` (default) | No run failure events. Ordinary server exception reporting still uses the backend DSN. |
| `unexpected` | Failed and timed-out runs, plus unexpected started cancellations, with the existing configuration, quota, and external connection filters described below. |
| `all` | Every failed or timed-out run, including the known configuration, quota, and external connection failures. Unexpected started cancellations also report. |
Missing, blank, or unrecognized values keep run reporting off. Expected operator
stops, shutdown interruptions, successful runs, and queued work do not report in
either enabled mode. The mode does not change run status, retries, recovery,
Telemetry, or OpenTelemetry export. It is process-wide, so an operator can enable
it on one staging instance without enabling it on other deployments. Restart the
server after changing deployment environment variables.
**Upgrade:** A backend DSN alone previously enabled run failure reports. Set
`PAPERCLIP_SENTRY_RUN_FAILURES=unexpected` to preserve that reporting policy.
Use `all` to investigate every failed run in a selected deployment.
Terminal run failures carry the company, agent, run and optional task IDs,
adapter, error code, run status, and redacted error message. Company-scoped runs
without a task also report. The `event_kind=run_failure` tag identifies these
events. Their fingerprint contains the error code and adapter, followed by the
setup/execute phase and original failure code when available. IDs, release,
model, and error text do not split groups. These fields are passed directly to
that event's capture call.
They do not change the ambient Sentry scope, whose isolation is unavailable
without an OpenTelemetry context manager. Later, unrelated exceptions must
not inherit a previous run's identity or fingerprint.
The versioned `paperclip` context supplies company and agent IDs and relative
API paths for the saved run, events, log, and optional task. A valid HTTP(S)
origin in `PAPERCLIP_PUBLIC_URL` also supplies absolute run, events, and log URLs.
Values with credentials, query parameters, fragments, or a path are omitted.
The event never includes an API key or an access token. These references grant
no access. A bot must authenticate to the correct instance and pass its existing
company, run-output, and private-task access checks.
The bot should use the exact run ID to read `GET /api/heartbeat-runs/{runId}`,
`GET /api/heartbeat-runs/{runId}/events`, and
`GET /api/heartbeat-runs/{runId}/log`. These retain the saved result, run context,
and available output. Prefer the saved provider configuration over the agent's
current settings. The Sentry execution context includes the saved native
provider kind and model, start/finish timestamps, and original failure code when
available. Tool-name collision errors identify the conflicting tool names and
connection bindings without serializing tool schemas or provider metadata.
Gateway reason codes survive exception projection. All diagnostic text still
passes through the existing secret redaction and size limits.
Use the Sentry group to combine repeated investigations, and the instance and
run ID to identify each occurrence. Automated retries or proposed code fixes
must use normal Paperclip authority and approval checks. Receiving an event
does not authorize a bot to replay a run. This change provides the reporting
contract; it does not install a bot or configure Sentry alerts.
Reporting remains asynchronous and best effort. Shutdown drains pending report
work before the SDK flushes. There is no durable delivery queue or receipt from
Sentry, so a crash or network outage can lose events. `all` selects failures; it
does not promise delivery or export complete transcripts. Detailed output stays
in the instance behind the existing authenticated APIs, with its normal retention.
Known missing-secret configuration blockers are kept in the task's run log,
blocked state, and owner recovery action, without a Sentry run-failure event.
The exclusions in this section apply to `unexpected` mode only.
This requires a failed `configuration_incomplete` run in the preparing stage,
a setup-phase report, explicit proof that provider work did not start, and a
nonempty list of recognized missing or inactive secret bindings. Process exit
@@ -634,6 +729,23 @@ at detection; it does not claim that a retry was queued or succeeded. This data
contains no process IDs, task text, paths, or credentials and changes no recovery
or ownership decisions.
When a native session fails because close could not prove durable runner
suspension (`provider_transport_failed: runner did not durably suspend before
checkpoint`), `run_execution` records which barrier was unproven:
`closeRunnerSuspended`, `closeProviderDrained`, `closeSuspendCommandStatus`
(a runner command status, or `not_queued`), `closeRunnerLifecycle` (`ready`,
`suspended`, `closed`, `recoverable_failure`, or `unobserved`),
`closeRunnerIdentityMatches`, `closeProviderState` (`settled`, `unsettled`,
`unreadable`, or `not_local`), `closeProviderPendingEventCount`,
`closeProviderTurnActive`, `closeSemanticResultPersistenceFailed`, and the counts
`closeSemanticToolsPending`, `closeSemanticToolDeliveriesOpen`, and
`closeSemanticResultFailures`. Fields absent from the runner's settlement are
omitted. Tool call, operation, command and event identities, input digests and
provider turn IDs stay in the instance run log. The report reads the caught error
only for these labels; its text and stack are not copied, because they bypass the
executor's identity redaction. These observations do not change close, quarantine
or recovery behavior.
ACP turns record `acpLastEventAgeMs`, `acpObservedEventCount`,
`acpPendingToolCount`, and `acpToolInventoryComplete` at finalization, before
usage reads, error logging, and cleanup. The age measures time since the last
+1 -1
View File
@@ -28,7 +28,7 @@ Runner setting in addition to Dot and Assistant connections (MCP).
expiry, and event instructions. Paste the prompt into your Dot so it can add
or reuse the private plugin and finish OAuth in its own browser. Dot enters
the one-use code on the Paperclip connection page and chooses
**Connect Dot with pairing code**. Entering a valid code first shows the
**Allow agent connection**. Entering a valid code first shows the
exact company, agent, permissions, and ongoing revocable access duration;
previewing consumes no code and creates no grant. No operator sign-in in Dot’s browser is
needed. The personal `/mcp/paperclip` connection
@@ -0,0 +1,95 @@
# Speko component-to-story coverage inventory
This document is a dated qualification snapshot. The current catalog is generated from each story’s `parameters.paperclip` annotation; this report is not a separate catalog registry.
Updated: 2026-10-13. Speko remains experimental. The source inventory contains **157 production-component stories**. The prior 148-story build passed 592 interaction/accessibility checks during PR preparation; 188 affected history/page checks passed, including the two secondary-error stories. The final 153-story build passed, and all 220 affected page, provider-setup, task-launcher and incoming-call interaction/accessibility checks passed (`/tmp/speko-pr-storybook-all-review-checks.log`). The narrow-light and desktop-dark ConfigureProvider captures were inspected after the footer change; canonical Linux baseline publication is still outstanding. Setup now selects existing agents without an installer. `ChooseAgent`, `ChooseAgentLongName`, and `ChooseAgentEmpty` cover selection, keyboard use, disabled Continue, empty inventory and focus restoration. The changed setup subset passed **20 interaction/accessibility checks** across light/dark themes and 390/1200-pixel viewports with reduced motion (`/tmp/speko-existing-agent-stories.log`). The October 7 full-suite results below are historical; removed installer stories no longer apply. Fixtures block external requests and real microphone access.
| Story module | Story IDs |
| --- | --- |
| `./storybook/stories/chat-channels/speko/speko-call-provider.stories.tsx` | `connections-speko-call-provider--initial`, `connections-speko-call-provider--active`, `connections-speko-call-provider--navigation`, `connections-speko-call-provider--new-conversation`, `connections-speko-call-provider--company-change`, `connections-speko-call-provider--sign-out`, `connections-speko-call-provider--end-and-restart`, `connections-speko-call-provider--long-conversation`, `connections-speko-call-provider--restart-in-panel` |
| `./storybook/stories/chat-channels/speko/speko-connection-status.stories.tsx` | `connections-speko-connection-status--attention`, `connections-speko-connection-status--revoked`, `connections-speko-connection-status--removed`, `connections-speko-connection-status--paused` |
| `./storybook/stories/chat-channels/speko/speko-native-conversation.stories.tsx` | `connections-speko-native-conversation--credits-required`, `connections-speko-native-conversation--idle`, `connections-speko-native-conversation--delayed-result`, `connections-speko-native-conversation--notification-unavailable`, `connections-speko-native-conversation--muted`, `connections-speko-native-conversation--ended`, `connections-speko-native-conversation--creation-recovery`, `connections-speko-native-conversation--pending-hangup`, `connections-speko-native-conversation--interrupted-hint-recovery`, `connections-speko-native-conversation--continue-conversation`, `connections-speko-native-conversation--new-conversation`, `connections-speko-native-conversation--access-revoked`, `connections-speko-native-conversation--reload-recovery`, `connections-speko-native-conversation--pause-within-spoken-answer` |
| `./storybook/stories/chat-channels/speko/speko-pages.stories.tsx` | `connections-speko-pages--catalog`, `connections-speko-pages--choose-agent`, `connections-speko-pages--choose-agent-long-name`, `connections-speko-pages--choose-agent-empty`, `connections-speko-pages--configure-provider`, `connections-speko-pages--test-conversation`, `connections-speko-pages--active`, `connections-speko-pages--paused`, `connections-speko-pages--attention`, `connections-speko-pages--revoked`, `connections-speko-pages--removed`, `connections-speko-pages--loading-failure`, `connections-speko-pages--private-access`, `connections-speko-pages--conversations`, `connections-speko-pages--conversations-empty`, `connections-speko-pages--activity-empty`, `connections-speko-pages--identity-provider-label`, `connections-speko-pages--setup-keeps-resume-link`, `connections-speko-pages--pending-incoming`, `connections-speko-pages--guest-intake`, `connections-speko-pages--with-call-history`, `connections-speko-pages--settings-without-call-history`, `connections-speko-pages--activity-with-mixed-entries`, `connections-speko-pages--activity-unapproved-call`, `connections-speko-pages--activity-call-history-failure`, `connections-speko-pages--paused-call-history`, `connections-speko-pages--long-agent-header` |
| `./storybook/stories/chat-channels/speko/speko-phone-callback.stories.tsx` | `connections-speko-phone-callback--initial`, `connections-speko-phone-callback--loading`, `connections-speko-phone-callback--enabled`, `connections-speko-phone-callback--disabled`, `connections-speko-phone-callback--saving`, `connections-speko-phone-callback--saved`, `connections-speko-phone-callback--provider-failure`, `connections-speko-phone-callback--validation-and-keyboard-save` |
| `./storybook/stories/chat-channels/speko/speko-provider-setup.stories.tsx` | `connections-speko-provider-setup--initial`, `connections-speko-provider-setup--credentials-entered`, `connections-speko-provider-setup--missing-https`, `connections-speko-provider-setup--verification-loading`, `connections-speko-provider-setup--resumable-setup`, `connections-speko-provider-setup--long-agent-name`, `connections-speko-provider-setup--keyboard-validation-and-connect`, `connections-speko-provider-setup--interrupted-before-credentials` |
| `./storybook/stories/chat-channels/speko/speko-task-launcher.stories.tsx` | `connections-speko-task-launcher--existing-agent`, `connections-speko-task-launcher--multiple-personas`, `connections-speko-task-launcher--unavailable-agent`, `connections-speko-task-launcher--agent-channels`, `connections-speko-task-launcher--connection-lifecycle`, `connections-speko-task-launcher--bound-task-banner`, `connections-speko-task-launcher--keyboard-open`, `connections-speko-task-launcher--connection-load-failure`, `connections-speko-task-launcher--bound-connection-recovery`, `connections-speko-task-launcher--persona-after-panel-close`, `connections-speko-task-launcher--shared-pause-resume` |
| `./storybook/stories/chat-channels/speko/call-history.stories.tsx` | `connections-speko-call-history--empty`, `connections-speko-call-history--loading`, `connections-speko-call-history--failure`, `connections-speko-call-history--completed`, `connections-speko-call-history--active`, `connections-speko-call-history--failed`, `connections-speko-call-history--missed`, `connections-speko-call-history--transcript-unavailable`, `connections-speko-call-history--partial-cost`, `connections-speko-call-history--interrupted-answer`, `connections-speko-call-history--long-conversation`, `connections-speko-call-history--keyboard-disclosure`, `connections-speko-call-history--end-call-focus`, `connections-speko-call-history--unapproved-incoming`, `connections-speko-call-history--revoked-history`, `connections-speko-call-history--activity-entry`, `connections-speko-call-history--activity-unapproved-entry`, `connections-speko-call-history--activity-end-call-focus`, `connections-speko-call-history--incoming-failure-preserves-history`, `connections-speko-call-history--end-failure-preserves-history` |
| `./storybook/stories/chat-channels/speko/incoming-call.stories.tsx` | `connections-speko-live-phone-approval--awaiting-approval`, `connections-speko-live-phone-approval--existing-task`, `connections-speko-live-phone-approval--confirming`, `connections-speko-live-phone-approval--approved`, `connections-speko-live-phone-approval--denied`, `connections-speko-live-phone-approval--expired`, `connections-speko-live-phone-approval--hung-up`, `connections-speko-live-phone-approval--failure`, `connections-speko-live-phone-approval--keyboard-approval-and-focus`, `connections-speko-live-phone-approval--guest-intake`, `connections-speko-live-phone-approval--public-keyboard-end`, `connections-speko-live-phone-approval--task-list-failure-and-recovery`, `connections-speko-live-phone-approval--approval-confirmation-expires` |
| `./storybook/stories/chat-channels/speko/phone-line.stories.tsx` | `connections-speko-incoming-phone-line--initial`, `connections-speko-incoming-phone-line--loading`, `connections-speko-incoming-phone-line--empty-inventory`, `connections-speko-incoming-phone-line--selected`, `connections-speko-incoming-phone-line--verification-required`, `connections-speko-incoming-phone-line--insufficient-credits`, `connections-speko-incoming-phone-line--provider-failure`, `connections-speko-incoming-phone-line--long-labels`, `connections-speko-incoming-phone-line--keyboard-save`, `connections-speko-incoming-phone-line--guest-intake`, `connections-speko-incoming-phone-line--private-task-approval`, `connections-speko-incoming-phone-line--selected-sandbox` |
| `./storybook/stories/chat-channels/speko/voice-controls.stories.tsx` | `connections-speko-voice-controls--idle`, `connections-speko-voice-controls--connecting`, `connections-speko-voice-controls--listening`, `connections-speko-voice-controls--speaking`, `connections-speko-voice-controls--muted`, `connections-speko-voice-controls--working`, `connections-speko-voice-controls--interrupted`, `connections-speko-voice-controls--reconnecting`, `connections-speko-voice-controls--ending`, `connections-speko-voice-controls--cleanup-failed`, `connections-speko-voice-controls--ended`, `connections-speko-voice-controls--failed`, `connections-speko-voice-controls--microphone-denied`, `connections-speko-voice-controls--playback-blocked`, `connections-speko-voice-controls--long-name`, `connections-speko-voice-controls--state-matrix`, `connections-speko-voice-controls--keyboard-mute-and-end`, `connections-speko-voice-controls--repeat-answer`, `connections-speko-voice-controls--repeat-unavailable-while-ending` |
| `./storybook/stories/chat-channels/speko/voice-conversation-panel.stories.tsx` | `connections-speko-conversation--idle`, `connections-speko-conversation--connected`, `connections-speko-conversation--connection-recovery`, `connections-speko-conversation--cleanup-recovery` |
| `./storybook/stories/chat-channels/speko/voice-transcript.stories.tsx` | `connections-speko-transcript--empty`, `connections-speko-transcript--unavailable`, `connections-speko-transcript--partial-speech`, `connections-speko-transcript--final-speech`, `connections-speko-transcript--overlapping-updates`, `connections-speko-transcript--delayed-result`, `connections-speko-transcript--task-reference`, `connections-speko-transcript--long-conversation` |
## Production component mapping
| Component | Story module(s) |
| --- | --- |
| `VoiceControls` | `voice-controls.stories.tsx` |
| `VoiceTranscript` | `voice-transcript.stories.tsx` |
| `VoiceConversationPanel` | `voice-conversation-panel.stories.tsx`, native conversation stories |
| `NativeVoiceConversation`, `VoiceSessionView`, `ConversationChoice` | `speko-native-conversation.stories.tsx` |
| `VoiceCallProvider`, application call host | `speko-call-provider.stories.tsx` (StrictMode, route navigation, company/logout cleanup, panel restart, focus restoration and a bounded long transcript) |
| Changed `StatusBadge` behavior | `speko-connection-status.stories.tsx` and full-page states |
| `SpekoPhoneCallbackForm`, `SpekoPhoneCallback` | `speko-phone-callback.stories.tsx`, full connection Settings page; keyboard opt-in/save, invalid input, retryable errors, fictional phone only |
| `SpekoCallHistoryView`, `SpekoCallReport`, `SpekoCallActivityItem`, `SpekoUnapprovedCallActivityItem` | `speko/call-history.stories.tsx`, full Activity page; safe costs, interrupted/long/missing transcripts, current-access revocation, keyboard disclosure, call end/focus restoration, unapproved calls, and retained transcripts after inbound-history/end-call errors |
| `SpekoPhoneLine`, `SpekoPhoneLineForm` | `speko/phone-line.stories.tsx`; loading/empty inventory, verification/credits/provider failure, private/guest line setup and keyboard save |
| `SpekoIncomingCalls`, `SpekoIncomingCallApproval` | `speko/incoming-call.stories.tsx`; pending/approve/deny/expired/guest/hangup, long task names, validation and recovery |
| `SpekoProviderSetup` | `speko-provider-setup.stories.tsx` |
| `TaskVoiceLauncher`, `AgentChannelsPanel`, `ExternallyConnectedTaskBanner` | `speko-task-launcher.stories.tsx` |
| `Browse`, `ChatEndpointSetup`, `ChatEndpointDetail`, `ChatIdentityConfirm` | `speko-pages.stories.tsx` |
## Checks and outstanding coverage
- Interaction checks include validation, mute/end/retry, paced notification recovery, partial speech with pauses, explicit repeat, reload cleanup, Continue/New conversation, revoked access, route navigation, keyboard launch, and focus restoration after template/call dismissal.
- Accessibility checks include dialog portals, contrast, accessible names, overflow, and final-only live transcript announcements. Fixed template focus restoration, manager-role/badge contrast, and narrow persona selection.
- The existing visual suite discovers Speko stories. October screenshots and interaction reports are in `tests/storybook-visual/test-results/` and `tests/storybook-visual/playwright-report/index.html`. The October run checks interactions, accessibility, external-network blocking and overflow, and captures screenshots; the previous local macOS comparison passed 274 snapshots before the four final template scenarios. At the October 7 checkpoint, all 284 Speko story/theme comparisons passed: 282 existing comparisons in `speko-completion-final-visual.log` and two newly inspected credit-error candidates in `speko-completion-credits-reviewed-visual.log`. The first invocation recorded missing baselines for those two new candidates; both were visually inspected before the successful comparison. Reviewed the empty-manager template, private approval, completed/history, narrow and dark fixtures. Linux CI baseline approval/publication remains outstanding. Reviewed narrow light call-host, long-conversation, and dark repeat-control and in-panel restart screenshots. September's 140 local baseline comparisons remain historical; new/changed baseline approval and CI publication are outstanding.
- Design Guide includes voice controls, transcript, the production Speko setup form, callback form, phone line, incoming-call approval and call history. The task launcher has dedicated stories; the installer was removed from Speko setup on October 8.
- Full Apps Browse/Setup/Detail/Identity stories cover setup steps, active/paused/attention/revoked/removed connections, private access guidance, load failure, conversation history and empty activity. The removed installer’s failure/loading/manager stories were covered at the October 7 checkpoint. Real-template installation has historical live UI proof; catalog-install retry was covered by the October 7 E02 test; October 8 E02 verifies existing-agent selection and preserved configuration instead; arbitrary concurrent catalog-import idempotency and normal-motion/hardware acceptance remain unqualified.
- Personal outgoing callback configuration is implemented. Provider-number inventory, phone approval/guest intake, session history and costs have the component stories listed above. Separate per-voice catalog selection remains outside the persona-based setup.
Commands: `pnpm build-storybook`, `pnpm check:token-gates`, and `STORYBOOK_VISUAL_PORT=6119 pnpm exec playwright test --config tests/storybook-visual/playwright.config.ts tests/storybook-visual/speko-voice.spec.ts`. The optional port override avoids accidentally reusing another worktree's Storybook server. Do not blanket-update unrelated baselines.
October 7 final retry coverage: the production `TeamInstallerDialog` accepts a default collision strategy; the removed Speko installer supplied `skip` and preserved an installed matching agent on retry. `CreationFailure` checks both actual preview/install options. All eight template stories passed 32 interaction/accessibility checks and 16 unchanged visual comparisons after this correction. The real-server E02 journey also preserves the original agent configuration and historical task assignment.
October 7 credit-failure coverage: `CreditsRequired` uses the real production conversation and deterministic HTTP 409 fixture. Four theme/width interaction/accessibility checks and two visually inspected theme comparisons passed. Real-server E12 proves funding guidance, exact failed-session cleanup, redacted browser response, durable provider rejection, and a replay with only one external creation attempt. No actual microphone or provider call occurs in these fixtures.
October 8 onboarding change: removed the dedicated template component and its eight installer stories. The optional receptionist remains in the team catalog, independent of connection setup. Speko instructions now use the same automatic, assignment-scoped connector skill delivery as AgentMail; task communication guidance also reaches the selected voice agent. The existing `TeamInstallerDialog` retains its generic catalog stories.
October 8 visuals: six intentional agent-selection light/dark baselines were reviewed and updated individually; all six subsequent comparisons passed (`/tmp/speko-existing-agent-visual-comparison.log`). No unrelated snapshots were updated.
October 8 backend and live-app verification: 65 focused guidance/session tests and all three real-server integrated Speko journeys passed, including existing-agent selection/reload with unchanged runtime and historical assignment. The runtime task snapshot contains the voice guidance; automatic connector skill coverage verifies supported adapter delivery, company/agent isolation, disabled callbacks, pause/revoke/remove, disabled credentials, removed assignment and the experimental gate. UI/server typechecks, UI/Storybook/catalog builds and token gates passed. The running localhost:3469 app was reloaded and checked in the embedded browser. No provider call or microphone was used for this change.
October 8 shared-path regressions: 65 AgentMail/Browser Use connector tests and 11 catalog tests passed. The shipped-agent catalog expectation was brought into sync with the already present optional Speko agent. These targeted checks qualify this onboarding/instruction change; they do not supersede the outstanding whole-repository and real-provider acceptance work in the October 7 qualification report.
October 8 call Activity change: removed Your calls from connection Settings. Browser, incoming and outgoing sessions plus unapproved calls now appear chronologically alongside connection events on the first Activity page, using the same caller-authorized history APIs. Expanding a call retains its task link, transcript, provider charge and authorized end-call control. Connection-event pagination remains unchanged; recent caller-visible calls appear only once on the first page. The two extracted entry components have dedicated production-component stories and Design Guide examples.
The changed page/call-component subset passed 176 interaction/accessibility checks (44 stories × two themes × two widths), including chronological order, absence from Settings, transcript/task/cost disclosure, unapproved calls, history denial, paused history and end-call focus restoration. All three real-server integrated journeys passed; E15 now checks call reports in Activity and absence from Settings. UI typecheck, UI/Storybook builds and token gates passed. The localhost:3469 app was reloaded and verified in the embedded browser without placing a call or requesting a microphone. Test logs use `/tmp/speko-call-activity-*.log`.
Visual review inspected the 26 intentional/new light/dark candidates: ten changed existing snapshots and sixteen new ones. The first broad invocation used a missing default baseline directory; comparisons were then repeated against the existing reviewed `/tmp/speko-visual-candidates` directory. All 62 unchanged snapshots matched before the ten intentional changes were individually accepted. All 88 final comparisons passed (`/tmp/speko-call-activity-visual-final.log`); Linux baseline publication remains separate from this local review. This UI qualification does not replace outstanding real-provider or whole-repository acceptance.
October 8 Settings simplification: removed the browser conversation selector/launcher and its introductory section from connection Settings. Setup's optional voice test and task-based voice launcher remain. The shared Speko connection header now uses the bundled AppLogo and an Open Speko account link. Callback configuration no longer includes the two introductory paragraphs. Incoming-call and Access copy explain the existing pairing flow: a private call reads a code that must be entered in signed-in Paperclip for that live call and a permitted task. Guest intake takes messages for review without private task access or agent execution. No authentication or provider contract changed. SettingsWithoutCallHistory covers absence of both history and browser launchers, the account link and bundled logo; LongAgentHeader covers wrapping. Callback and phone-line component stories cover their shorter copy.
The Conversations empty state now directs users to Talk to agent on an assigned task. The Settings cleanup passed three real-server integrated journeys, 180 page/form/task-launcher interaction/accessibility checks plus four long-header checks, UI typecheck/build and token gates. Test evidence uses `/tmp/speko-settings-cleanup-*.log`; microphone/provider calls were not made for this change. Visual review covers the changed header and shorter forms in both themes; broader live-provider and repository-wide acceptance remains separate.
Final Settings verification: four additional interaction/accessibility checks passed for the corrected Conversations empty state. Reviewed 70 changed candidates and both new long-header theme snapshots; after correcting the stale empty-state instruction, all 90 final affected visual comparisons passed against the reviewed local baseline directory (`/tmp/speko-settings-cleanup-visual-final.log`). No unrelated snapshots were updated. The final UI/Storybook builds passed; the dev server was reloaded and the saved connection Settings verified in the embedded browser. Linux baseline publication and whole-feature qualification remain separate.
## October 8 low-trust incoming conversations
The historical message-only guest-intake descriptions above are superseded for newly admitted opted-in calls. `SpekoPhoneLine` now offers a connection-scoped sandbox choice, `SpekoIncomingCalls` shows a conversation task and End call without a code, and the changed Access page explains both public and private modes. The existing `guest-intake` story IDs are retained for compatibility and now render the actual public conversation components. PrivateTaskApproval, SelectedSandbox and PublicKeyboardEnd add explicit private/default, sandbox selection and keyboard/focus coverage. No new agent is installed.
Historical development run: all 50 affected production-component stories passed 200 interaction/accessibility checks across light/dark themes and desktop/narrow viewports with reduced motion. Reviewed all 40 intentional/new visual candidates individually, accepted only those exact story IDs, and passed all 100 final affected theme comparisons. The built inventory has 148 Speko stories. UI and Storybook builds, UI typecheck and token gates passed. Local macOS baseline review does not publish canonical Linux baselines or qualify telephone audio. See [incoming-call qualification](2026-10-09-speko-pr-qualification.md).
Final merge preparation adds a bounded approval-confirmation story using the production incoming-call component. Its play function approves the call, verifies focus, and waits for the five-second receipt to clear. The prior 220-check result remains historical; all 108 final affected approval/conversation checks passed and are recorded in the qualification report.
Latest interrupted-setup repair: the 155-story build and all 32 provider-setup interaction/accessibility checks passed across both themes and 390/1200-pixel widths with reduced motion. The production story verifies generation of a missing signing secret during interrupted setup; existing reconnect stories preserve saved secrets. No real microphone or external provider requests were used.
October 13 review repair: the task launcher restores persona selection and keyboard focus after the hosted voice panel closes. PersonaAfterPanelClose exercises the production launcher without opening media. OverlappingUpdates verifies that interrupted transcript fragments are labeled Interrupted and no longer Speaking. The Team Catalog data helper is explicitly excluded from the Storybook index.
October 13 verification: the 156-story build and all 76 affected launcher/transcript interaction and accessibility checks passed across both themes and 390/1200 widths with reduced motion. Narrow-screen captures were inspected. After master adopted generated indexes, Speko source annotations retained stable story IDs and explicit fixture/provider limits; all 28 catalog/map structural tests passed. Structural checks do not establish runtime or provider acceptance.
The complete generated-catalog Storybook run passed all 624 checks for the 156 Speko stories (UI source 249cbc616a). These are fixture interaction/accessibility results and viewport captures, not provider or spoken-playback acceptance.
The shared endpoint-cache repair adds SharedPauseResume to the source inventory. The mounted production launcher observes the same company-scoped cache invalidated by setup and lifecycle controls. All 27 focused UI regressions, UI typecheck and token gates pass; its affected Storybook verification is recorded in the PR after execution.
@@ -0,0 +1,454 @@
# Speko voice connection: implementation and E2E runbook
Date: 2026-09-11; updated 2026-09-12. Status: native browser milestone proven;
telephone and full E01–E16 qualification outstanding. See the
[native qualification report](2026-10-09-speko-pr-qualification.md).
Branch: `codex/speko-chat-connection`.
Base: `d10cbde81523a13344fc18a1f70a76edac8a93fc` (clean current master).
## October 9 live-call push
Telephone replies now use `POST /v1/calls/{id}/messages` with `mode: "respond"`.
Keep the call open after submitting work and verify automatic output without
`get_updates` polling or a result-ready hint. Check the durable action receipt
and task reply separately from confirmed spoken playback. A 409 ends delivery;
uncertain requests must not be automatically resent. Browser result hints are
unchanged. See the [live-call push qualification](2026-10-09-speko-pr-qualification.md)
for the real-provider text-input proof, timings, reproduction and remaining
PSTN/interruption qualification.
## Cloud caller authentication (2026-10-13)
Private voice routes accept both local authenticated sessions and trusted Cloud
user sessions. Cloud callers keep their authenticated user ID and current
company scope. Cloud owners use current company membership even when temporary
Cloud administrator access is enabled; they do not need a persisted local
instance-admin role. Board API keys, MCP OAuth callers, Cloud control credentials,
and raw Cloud user headers do not create private caller authority.
On a Cloud workspace, verify that the signed-in operator can load call history
and start a browser session. Repeat with a user outside the company and confirm
access is denied. Provider configuration alone does not qualify conversation
or spoken result delivery.
## October task-parity qualification
Updated 2026-10-07: September's browser proof is historical. The current task-parity
implementation still requires live audio requalification; see the
[October qualification report](2026-10-09-speko-pr-qualification.md).
Run deterministic integration without a Speko account, microphone or public tunnel:
```sh
npx --yes pnpm@9.15.4 --filter @paperclipai/ui build
npx --yes pnpm@9.15.4 exec tsc -p tests/speko-native/tsconfig.json
npx --yes pnpm@9.15.4 exec playwright test --config tests/speko-native/playwright.config.ts
npx --yes pnpm@9.15.4 exec playwright test --config tests/speko-native/playwright-auth.config.ts
```
The first suite uses loopback ports 3480/3481 and a fresh local-trusted instance.
It covers delayed work, deduplication, route navigation, repeat, reload cleanup,
explicit new conversations, end/rejoin, results completed after hangup, and typed
questions answered through canonical task interactions. The fixture supervisor
retains the database across app restarts; external fixture state survives separately.
Only deterministic stub mode accepts the local restart signal. The test verifies
that an open call survives an orderly app restart, its repeated answer callback
uses the original receipt, and explicit Repeat retrieves the saved response
without creating sessions, comments or runs. The
second uses 3482/3483, real Better Auth signup and invitation APIs, and separate
operator/member/outsider/anonymous contexts. It checks two-company isolation,
private tasks, caller ownership and mid-call membership revocation. Only Speko
transport/media and execution are stubbed. No Paperclip API response is mocked.
Each suite shuts down its own server/database. Its generated HTML report stays
under `tests/speko-native/playwright-report/` or `playwright-report-auth/`.
The integration report includes synthetic durable records and a screenshot;
authentication traces are off so session cookies/passwords are not captured.
Do not count these fixture runs as live audio or full E01–E16 acceptance.
## Native browser acceptance commands
Use pnpm 9.15.4 to honor this checkout's dependency patches. Build the static UI
before starting the temporary server:
```sh
npx --yes pnpm@9.15.4 --filter @paperclipai/ui build
SPEKO_NATIVE_PORT=3449 SPEKO_NATIVE_CALLBACK_ORIGIN=https://your-test-origin.example \
server/node_modules/.bin/tsx tests/speko-native/server.ts
```
The launcher creates a fresh OS temporary home and embedded PostgreSQL database,
removes inherited database/worktree configuration, and binds the app to loopback.
The parent owns the database; the child watches app code for restart tests. Expose
only `/api/voice-webhooks` through the explicitly configured HTTPS origin. Preserve
other services on any shared proxy. Do not run builds or edit server imports
during a live call. The static UI avoids Vite reloads interrupting media tests.
In the temporary UI, create an acceptance company and existing agent. The harness
substitutes only the `process` execution adapter with a 61-second fixture. Other
adapters, including the catalog template's `claude_local`, remain real. Install
the optional receptionist template through the team catalog when testing that path; Apps setup selects an existing agent. Give it an
isolated working directory with an `ACCEPTANCE.txt` file containing the synthetic
word `marigold`; do not point acceptance work at private project files.
Create a dedicated hosted Speko persona per endpoint. Its signed tools are managed
by the actual setup UI. Save a private fixture at
`~/.paperclip/speko-proof/native-fixture.json` (existing agent) or
`native-template-fixture.json` (template), mode 0600:
```json
{
"companyId": "temporary-company-uuid",
"companyPrefix": "SPE",
"agentId": "selected-agent-uuid",
"agentName": "Existing Paperclip Agent",
"providerAgentId": "agent_dedicated_persona",
"endpointId": "optional-resumable-endpoint-uuid"
}
```
Omit `endpointId` for new setup. The live harness fills the real masked setup form
using `SPEKO_MCP_API_KEY` from `~/.secrets` and persists only the endpoint ID in the
fixture. Do not record Playwright traces around credential entry.
Prepare synthetic input using `say` and `ffmpeg`, saving mono 48 kHz signed 16-bit
little-endian PCM files under `.paperclip-local/speko-proof-audio/`:
- `start.pcm`: “Start the test.”
- `followup.pcm`: “Add a follow-up.”
- `template-start.pcm`: “Read ACCEPTANCE dot T X T in your working directory and tell me the verification word.”
- `template-delayed-start.pcm`: “Run python three voice underscore acceptance underscore benchmark dot py in your working directory. It computes for sixty five seconds. Wait for the command to complete, then tell me the verification word from its output.”
- `template-delayed-followup.pcm`: “Add another instruction to that task. Include the phrase silver lantern in the final answer.”
- `template-followup.pcm`: “Please include the verification word in your answer.”
- `template-resume.pcm`: “Please tell me the verification word from earlier.”
```sh
node tests/speko-native/live-browser.mjs
SPEKO_NATIVE_SCENARIO=template node tests/speko-native/live-browser.mjs
SPEKO_NATIVE_SCENARIO=template-delayed SPEKO_NATIVE_EXPECTED_WORD=cobalt \
SPEKO_NATIVE_EVIDENCE_PATH=/your/temporary/home/evidence.json \
node tests/speko-native/live-browser.mjs
SPEKO_NATIVE_SCENARIO=template SPEKO_NATIVE_RESUME_ISSUE_ID=existing-task-uuid \
node tests/speko-native/live-browser.mjs
```
For the delayed real-agent case, copy `tests/speko-native/fixtures/acceptance-benchmark.py` to `voice_acceptance_benchmark.py` in the isolated agent workspace. It performs a 65-second SHA-256 computation on one CPU core, then reads `ACCEPTANCE.txt`; it has no network access. Change the isolated file to the expected word before the call and allow at least 180 seconds in the selected agent runtime. The harness requires two accepted session tool receipts plus an agent-authored task comment containing the distinct follow-up phrase. Confirm the benchmark completed its computation and independently check the received audio; a transcribed follow-up alone does not prove delivery.
The script uses the real UI, server, database, queues and provider. It replaces
only microphone input, records received audio privately, and asserts live
transcript, task binding, mute state, terminal session state and stopped tracks.
Independently transcribe or listen to the received audio before declaring spoken
success. Confirm the exact provider call is ended. A matching word elsewhere in
the task page is not proof. `SPEKO_NATIVE_IDLE_PROBE=1` deliberately disables the
browser notification feed for provider capability experiments and is never a
normal integration pass.
Inspect `instance.json`, `evidence.json` and `execution.jsonl` in the temporary
home for durable session/delivery/publication/task evidence. Each browser run
writes a private source manifest, report, screenshots and received audio under
`~/.paperclip/speko-proof/native-browser-*`. The checked-in reports contain only
synthetic results and numeric references. On cleanup, end active provider calls,
stop only this launcher, and remove only this test's proxy path.
Targeted backend verification:
```sh
npx --yes pnpm@9.15.4 exec vitest run \
server/src/__tests__/voice-session-store.integration.test.ts \
server/src/__tests__/speko-protocol.test.ts \
server/src/__tests__/speko-provider.test.ts \
packages/db/src/speko-voice-migration.test.ts \
ui/src/lib/voice-session-controller.test.ts
```
This harness is a live-provider qualification tool, not the complete deterministic
two-company E01–E16 browser suite described below.
## Product contract and gate
Build a native experimental Apps voice connection beside Slack/Discord. Speko
owns hosted audio, conversational acknowledgment, and telephony; the selected
Paperclip agent keeps its runtime, tools, task context, and work. Support browser
voice, inbound telephone, and authenticated “Call my phone.” Recommend the
optional **Speko Company Phone Agent** catalog template, while permitting any
existing agent. Do not automatically install the template in every company.
Before production changes, prove a hosted live conversation can wait for work
lasting at least 60 seconds, handle an interruption and additional instruction,
then automatically speak the eventual result. Tool requests have a four-second
ceiling; use quick submission and cursor retrieval with bounded waits. Browser
context injection is not a working alternative in the documented client. If the
gate fails, record the missing capability and founder questions. Do not replace
this product with after-call processing or a self-hosted voice stack.
Sources checked 2026-09-11:
- [Hosted tool calling, timeout and signing](https://docs.speko.ai/guides/tool-calling)
- [Browser data-channel limitations](https://docs.speko.ai/client/data-channel)
- [Browser lifecycle](https://docs.speko.ai/client/voice-conversation)
- [Hosted session credentials and duration limits](https://docs.speko.ai/api-reference/sessions)
- [Telephony and number requirements](https://docs.speko.ai/guides/phone-agents)
- [Lifecycle webhook delivery behavior](https://docs.speko.ai/guides/webhooks)
- [Original catalog PR #11418](https://github.com/paperclipai/paperclip/pull/11418)
PR #11418 describes the general-purpose Speko MCP catalog connection; it is
research input, not the live voice runtime. Keep general MCP tools separate.
## Implementation after gate success
1. Add explicit voice runtime/transport to the shared app/channel contracts and
validators, database constraints, server lifecycle and UI API clients. Keep
`enableChatConnectors` as the discovery/setup gate.
2. Reuse company endpoints, identities, task bindings, durable deliveries,
external publications and activity logging. Vault API/signing secrets. Each
endpoint binds one Speko persona and one Paperclip agent; preserve historical
assignments when configuration changes.
3. Persist session company, endpoint, provider ID, caller authority, task,
generation, lifecycle, expiry and reply cursor. Authenticated APIs create,
inspect, approve/deny private inbound sessions and end calls. Signed callbacks
verify raw body, time, session identity and idempotency before side effects.
4. Task entry resumes authorized work; agent entry creates one task. Follow-ups
use existing steering/queue behavior. Playback interruption, work cancellation
and call ending are separate transitions. Expose only permitted answers,
questions and safe progress. Distinguish result delivery from spoken evidence.
5. Setup: credentials → select/create agent → voice → number → test. Offer
existing Speko inventory, and guide purchase/import through Speko. Present
actionable verification, credits, HTTPS and device errors. Add task voice
controls, transcript, incoming-call approval, history and connection management.
6. Package the recommended agent in the existing template catalog: greeting,
intake, clarification, delegation and concise follow-up. Creation follows
normal company permissions and is idempotent.
Browser authority inherits the signed-in user's current access; only short-lived
media credentials enter the browser. Inbound caller ID grants no private access.
Private calls require authenticated approval of the specific live call. Guest
intake is explicitly enabled and cannot browse private tasks or approve governed
actions. Recheck current authorization throughout a session, including after a
company switch, revocation, pause or removal.
Callbacks require reachable HTTPS; local instances need a configured tunnel or
reverse proxy. No private relay is included. Retain transcripts/task history,
explain provider recording behavior and do not download recordings by default.
Set session-duration limits separately from join-token TTL and display Speko
charges separately from Paperclip agent costs. Exclude SMS, WhatsApp, campaigns,
autonomous outbound calls and general telephony administration.
## A. Deterministic UI and integrated browser qualification
Extend the existing chat UI suite for fixtures. Add a separate integration suite
with a real Paperclip server, isolated database, permissions, queues and external
publication path. Stub **only** Speko's transport and the execution provider.
Use temporary instances, two companies, operator/member/guest contexts, the
template agent and an existing agent. Do not reuse the existing UI suite's
mocked Paperclip responses as evidence that the backend works.
Every row must assert visible UI, resulting task state and durable session and
delivery records. Wait on observable transitions and receipts, not fixed sleeps.
| ID | Journey | Required evidence |
| --- | --- | --- |
| E01 | Connect through Apps | Secret masked/no browser durable key; draft persists on reload; activation requires verification |
| E02 | Recommended or existing agent | Correct assignment; creation permission; failed/retried creation never duplicates agents |
| E03 | Browser voice from task | Authorized task/session binding; short token expiry; provider key never reaches browser or trace |
| E04 | Agent entry and later resume | Exactly one task on initial admission; authorized later call resumes context without reassignment |
| E05 | Work lasts 60+ seconds | Prompt acknowledgment; safe progress; correct automatic final answer; one task and accepted request |
| E06 | Interrupt and follow up | Playback stops; ordered follow-ups reach same task; work continues unless explicitly cancelled |
| E07 | Cancel versus hang up | Independent work/call lifecycles; history and running work survive hangup |
| E08 | Private inbound | No private disclosure before approval; approve/deny/expiry; spoofed caller ID confers no authority |
| E09 | Company guest intake | Restricted intake succeeds; private task lookup and governed actions fail |
| E10 | Call my phone | Authenticated caller/task; duplicate click does not redial; ambiguous provider result reconciles first |
| E11 | Questions and approvals | Permitted question answers steer work; governed approvals retain existing checks |
| E12 | Provider/network failure | Timeouts, rate limits, credential expiry, disconnect and reload yield actionable recoverable state |
| E13 | Restart/retry | Duplicate and out-of-order callbacks plus process restart never duplicate tasks/comments or replay stale speech |
| E14 | Permissions/lifecycle | Revocation, pause, reconnect, removal and company switch enforce current access mid-call |
| E15 | History/reports | Transcript/task references agree; repeated report updates one record; no recording download |
| E16 | Media/responsiveness | Denied/missing mic, mute, navigation, unmount and end clean up media; usable narrow layout |
## B. Protocol, security and persistence
Test valid/invalid signatures, exact raw-body tampering, stale/future timestamps,
replay, secret rotation overlap, cross-company/endpoint/session substitutions,
stale generations, closed sessions, cursor bounds and replay of already spoken
publications. Verify scoped admission and current authority again at delivery.
Probe event redaction for keys, raw agent logs, tool outputs, private comments and
unapproved answers. Assert delivery and playback are separate durable facts.
Simulate concurrent delivery, uncertain outbound acceptance, reordered reports,
missing lifecycle callbacks and restart at each external-side-effect boundary.
Verify additive migrations against both an empty database and an upgraded copy;
check constraints and backfill defaults for existing Slack/Discord connections.
## C. Real-provider acceptance
Use a dedicated Speko workspace, durable reachable HTTPS callback origin and
designated phone numbers. Record exact tested commit and configuration. Complete
setup with both agent choices, then test real browser, inbound and outbound calls.
Repeat delayed work with interruption and follow-up on both browser and phone.
Demonstrate private-call approval and guest intake, hangup/reconnect/resume,
credential rotation, callback outage/recovery and revocation. Include desktop,
mobile and Safari microphone/playback behavior.
Listen to output: intelligibility, silence, turn-taking, duplicate speech,
interruption and answer accuracy. Record speech-end→acknowledgment (target ≤2s),
result-available→audio (≤5s), and interrupt→playback-stop (≤500ms) under healthy
conditions. Report actual measurements, clock sources and execution time
separately. Capture test audio only with participant consent. Keep keys/private
transcripts out of generic traces and artifacts.
Statuses are **passed**, **failed**, **blocked**, or **not run**. Fixture success
does not substitute for real audio/telephone proof. Keep Speko experimental until
all three transports and delayed-result behavior pass.
## UI/Storybook and completion gates
Use the companion component-to-story inventory. All stories render production
components with deterministic fixtures and no real microphone/provider traffic.
Add changed shared behavior, keyboard/focus/validation/control/recovery tests,
accessibility checks and design-guide examples. Run token gates and Storybook
build. Include stories in the existing Playwright visual suite, review intentional
baselines on its supported environment, and never blanket-update unrelated ones.
Before PR-ready handoff run targeted checks, integrated Speko E2E, existing
chat-provider regression, `pnpm -r typecheck`, `pnpm test:run`, `pnpm build`,
Storybook interactions/accessibility and visual tests. Report anything blocked.
Use the repository PR template if submitting a PR.
Qualification records must include UTC date, tested SHA/dirty patch, case IDs,
fixture/live environment, roles/company boundaries, observed timings, sanitized
session/task references, screenshot/report paths, failures and reproduction steps.
The current first-gate report is `2026-09-11-speko-voice-qualification.md`.
## 2026-10-07 authorized tunnel and playback retest
The user explicitly authorized the Cloudflare test tunnel. The approved proxy
forwards only POST `/api/voice-webhooks/:publicId/tools`; board/UI routes and
all other APIs return 404. Provider signatures, session capabilities and current
company/task authority remain enforced. Quick-tunnel URLs are temporary;
verify the origin before each run and retain no promise of permanent availability.
Audit received audio independently of the UI transcript. A passing live-browser
script is provisional until the whole result and follow-up have been heard or
independently transcribed from the actual received stream. An SDK `listening`
event can occur between words; a final transcript is not confirmed playback.
The second October retest passed its script but failed this audio review.
Retrieval now batches up to eight approved publications in cursor order, stopping
at an interaction boundary. This avoids a separate typed turn for each already
queued result. Streaming publications, current-access checks, repeat semantics,
idempotent receipts and unknown playback status remain unchanged. It does not
prove that a later asynchronous publication can never interrupt ongoing speech.
Retest that case and the three timing targets before telephone expansion.
The optional template was installed through the actual UI and its real Claude
runtime completed a 65-second Python workload, accepted the spoken follow-up,
and spoke the verification word plus the requested phrase. This establishes one
real runtime journey; it does not qualify template retry/idempotency, governed
approvals, human audio, Safari or telephone journeys.
## Agent-requested callback testing — updated 2026-10-07
1. Configure and verify a dedicated Speko persona on the selected agent's native
Apps connection. Keep experimental chat connectors enabled and expose only
signed voice callbacks through explicitly configured reachable HTTPS.
2. In connection **Settings → Call my phone**, save your own E.164 number and
enable **Allow this agent to call me about my tasks**. Speko charges and
recording settings apply; Paperclip does not download recordings.
3. Create an ordinary task assigned to that agent with yourself as responsible
person, requesting one call using the assigned `call_my_phone` connection
tool. The tool accepts no destination parameter and returns no media token.
Confirm actual runtime discovery, a durable gateway invocation, one task and
one `outbound_phone` session before counting placement as passed.
4. Answer the real telephone call. Screening/mailbox, first agent audio and SIP
answered/bridged do not prove a human task conversation. Record them separately.
For an answered call, submit work lasting at least 60 seconds, interrupt and
add an instruction. Assert signed callbacks, durable ordered comments,
selected runtime execution and correct approved audio without repeated caller
prompting. Measure acknowledgment/result/interruption with the stated targets.
5. Hang up and verify provider/Paperclip reconciliation. Rejoin only on an
explicitly authorized fresh attempt; uncertain creation must not blindly
redial. Revoking personal opt-in/current access must stop private delivery.
6. Retain sanitized task/session references and status. Do not include personal
numbers, credentials or private call transcripts in general traces. Review
consent before any audio capture; never automatically download recordings.
The integrated `tests/speko-native/integrated.spec.ts` E10 extension uses real
Paperclip routes, database, task queue, run identity and runtime MCP. Only external
Speko and execution are fixtures. It saves callback settings through the UI,
reloads, asks the execution fixture to discover/call its actual assigned tool,
rejects a simultaneous second request, verifies one outgoing durable/provider
session and output redaction, ends the call without cancelling work and disables
opt-in. It does not qualify real telephone audio or call-screening behavior.
## October 7 completion-audit procedure
Current private PSTN setup uses per-live-call approval in Paperclip; caller ID alone grants no access. A signed call creates one short-lived admission without a task. Approve its exact six-digit code while selecting an authorized task, or deny it; expiry and hangup close admission. Discard speech submitted before approval. Guest mode must be explicitly enabled and writes bounded low-trust intake without waking an agent, exposing private work or approving governed actions. Promote only the exact live call through authenticated Paperclip approval.
Phone polling is enabled in signed phone pre-call hints, never by mutating shared persona defaults on each dial. Verify that a subsequent browser call never reads idle polling instructions aloud. Provider final-report timestamps may be camelCase and durations fractional; the safe projection excludes application control hints, keys, system turns and recording URLs. Check both new and existing history entries.
Final component inventory: 141 stories and 564 theme/viewport interaction/accessibility checks. Run the existing visual suite with an external snapshot directory; review only Speko changes and publish Linux-approved baselines through the existing workflow. Local macOS candidate agreement is not CI baseline approval.
See the dated qualification report for actual provider session/task references, received-media timings, passed/failed/blocked labels and remaining E01–E16 gaps. No fixture result qualifies human phone conversation or Safari media. Do not redial an uncertain call or substitute an internal Speko agent-to-agent route for PSTN proof.
For E02, repeat a catalog import with `collisionStrategy: skip` after its first commit and assert one installed phone agent, the same ID/configuration, and unchanged historical task assignment. The Speko production wizard defaults to that policy; other catalog imports retain their existing defaults. Distinguish this committed-import recovery from concurrent general catalog transaction idempotency.
If Speko returns HTTP 402 / `INSUFFICIENT_CREDITS`, mark the affected actual-provider case blocked, preserve the rejection without keys, and stop retries. Funding is an operator action; fixture runs and UI transcripts cannot replace the blocked independent audio check.
October 7 deterministic E12: exhaust the external transport fixture's credits for one persona, start through the actual Apps UI, and require the funding message. Assert no media connection, redacted provider identity, one durable failed attempt and exactly one provider create after idempotency replay. End/cleanup may retire the local failed call without creating another provider session. Run `tests/speko-native/integrated.spec.ts` for the complete real-server journey plus E02 and E12; live HTTP 402 remains blocked until the workspace is funded.
## October 8 call Activity regression
In the real-server E15 journey, first verify that connection Settings has no Your calls region. Open the connection's Activity tab and refresh its combined feed. Find the completed incoming-call entry, expand it, and verify the saved transcript and task link against durable session/report records. Repeated provider reports must still update one record and preserve the original task assignment. Configure guest intake from Settings, then return to Activity and assert both authorized and guest call entries. Private denied/expired/missed admissions disclose no connected task.
The production feed uses existing caller-authorized history APIs and merges recent calls with connection events by creation time. Recent calls appear once on the first Activity page; older connection-event pages keep their existing cursor. History remains available on paused connections when current caller/task access permits it. History failures retain connection events and expose Retry calls.
Run the real-server native suite and the 44 page/call-entry Storybook stories. Fixtures must never request a real microphone or contact Speko. Include both themes, 390/1200 viewports, keyboard disclosure and end-call focus restoration. The October 8 run passed all three integrated journeys and 176 story interaction/accessibility checks, plus UI typecheck/build, Storybook build and token gates. Review and compare only intentional snapshots against the existing baseline directory; the complete affected visual subset has 88 theme comparisons. Whole-feature live telephone/audio and canonical repository checks remain governed by the October qualification report.
## October 8 simplified Settings regression
After activating a Speko connection, open Settings and verify the bundled provider logo and Open Speko link. There must be no browser Conversation selector, Start voice button, Your calls region or callback introduction. Save/reload outgoing phone settings and incoming number settings normally. Setup's optional voice test remains available, and assigned tasks retain their task voice launcher. E10 checks the simplified Settings surface before saving callback preferences; E08/E09 still exercise signed incoming approval and restricted guest intake.
The current private inbound flow requires the caller to also use signed-in Paperclip: enter the code spoken during this live call, select a permitted task and approve. The pending private admission expires after two minutes. This is a browser-mediated pairing flow, not sign-in by phone. Guest intake can record a message as quarantined work for review; it does not run the agent or expose private task information. This UI change preserves those authorization semantics.
The Conversations empty state now directs users to Talk to agent on an assigned task. The Settings cleanup passed three real-server integrated journeys, 180 page/form/task-launcher interaction/accessibility checks plus four long-header checks, UI typecheck/build and token gates. Test evidence uses `/tmp/speko-settings-cleanup-*.log`; microphone/provider calls were not made for this change. Visual review covers the changed header and shorter forms in both themes; broader live-provider and repository-wide acceptance remains separate.
Final Settings verification: four additional interaction/accessibility checks passed for the corrected Conversations empty state. Reviewed 70 changed candidates and both new long-header theme snapshots; after correcting the stale empty-state instruction, all 90 final affected visual comparisons passed against the reviewed local baseline directory (`/tmp/speko-settings-cleanup-visual-final.log`). No unrelated snapshots were updated. The final UI/Storybook builds passed; the dev server was reloaded and the saved connection Settings verified in the embedded browser. Linux baseline publication and whole-feature qualification remain separate.
## October 8: incoming conversation on its own low-trust task
New calls admitted with **Let callers start new low-trust tasks without sign-in** now create a task before greeting, bind every spoken request/follow-up to that task, and retrieve its approved replies through the normal chat queue. The legacy `guestIntake` wire name remains; it no longer means message-only intake for new calls. Defaults stay private; existing authenticated task approval remains available. Caller ID is never a user identity.
For E09, configure an active sandbox on the incoming line (or use the selected agent's sandbox), enable isolated workspaces, and supply an approved agent-scoped model connection. This affects only new low-trust incoming tasks; it does not change the agent/instance default environment or historical task assignments. Missing isolation fails closed. Browser/outgoing task conversations keep their existing authenticated authority.
1. Call the configured company number from a telephone. Verify the greeting asks what to work on without a Paperclip code or sign-in. Confirm exactly one new task/session/admission.
2. Submit work, interrupt playback, and add a follow-up. Verify both requests and approved agent replies remain on that task, in order. A playback interruption does not cancel work.
3. Ask for another private task or a governed approval. Verify the low-trust boundary refuses it. Do not expand privileges or copy a caller-ID identity to make the test pass.
4. End the call. The task and already accepted work survive hangup; new call requests fail. When Speko's report arrives, verify the task's **Phone conversation transcript** document contains both caller and voice-agent turns, interruptions included, with quarantined source trust. Repeated reports must not create duplicate documents or revisions. No recording is downloaded.
5. Repeat with connection pause/removal, credential rotation, altered task boundary/assignment or sandbox selection. Current authority must be checked before queue processing and reply retrieval.
Daytona cold sandboxes bootstrap the adapter's default Claude ACP server without changing engines; custom ACP commands remain setup failures if unavailable. A changed callback origin can update only tools/webhooks whose exact old definition and provider ID have completed receipts for this endpoint. Foreign integrations and uncertain creation outcomes remain blocked. For a quick Cloudflare test tunnel, expose only signed `POST /api/voice-webhooks/{publicId}/tools` and `/events`; the board API must return 404. Reconnect through the normal connection API after changing the explicit HTTPS origin.
The [dated incoming qualification](2026-10-09-speko-pr-qualification.md) distinguishes signed callback tests, actual Daytona/Claude execution and real telephone audio. Its passing backend proof does not qualify human incoming audio, Safari or the 60-second telephone acceptance case. The old insufficient-credit blocker is historical: check current Speko usage before making acceptance calls.
## October 8: live-call context and dual-model handoff
The voice model owns fast acknowledgments, clarification, and turn taking. The task agent owns work and substantive results. New public phone tasks capture the normal Speko communication guidance plus their low-trust boundary. Accepted, active voice sessions add a server-derived live-call instruction to every execution turn, including resumed sessions. Ending or expiring the session removes that instruction on the next turn; accepted work continues normally.
`get_updates` retains its durable publication cursor and adds a neutral `work` projection: idle, queued, running, pending, awaiting_reply, waiting_for_input, blocked, failed, or cancelled. These are queue/execution observations, not task completion claims or spoken playback receipts. Raw run output and provider errors are excluded. Tool retries retain the original response; use a new tool-call ID for a new status observation.
Run the disk scenario against the existing 10 GiB Daytona test task with locally generated `disk-request.pcm` and `disk-followup.pcm` (48 kHz mono signed 16-bit PCM):
```sh
SPEKO_NATIVE_PORT=3469 \
SPEKO_NATIVE_SCENARIO=disk \
SPEKO_NATIVE_RESUME_ISSUE_ID=<authorized-test-task> \
SPEKO_NATIVE_FIXTURE_PATH=<private-fixture-json> \
SPEKO_NATIVE_AUDIO_DIR=<synthetic-audio-directory> \
node tests/speko-native/live-browser.mjs
```
The fixture specifies companyId, companyPrefix, agentId, agentName, endpointId, and providerAgentId. Use an authorized disposable task already pinned to the real Daytona environment. The current disk scenario expects the test environment's 10 GiB root disk and approximately 9.7 GiB free; it is not a generic capacity test for arbitrary agents. For delayed delivery, the first recording requests a 65-second wait before inspecting only the root filesystem; the follow-up requests a one-sentence answer. Verify actual execution duration, two accepted submit_request receipts, same-task comments, urgent context in all task-markdown variants, approved publications, media cleanup, and synthetic output audio independently. A browser cascade result does not qualify telephone speech-to-speech or PSTN transport.
@@ -1,5 +1,411 @@
# Runner defaults: staged delivery
## Current qualification and repair checkpoint — 2026-10-13
Canonical branch: `codex/codex-runner-default`. Delivery:
[#15683](https://github.com/paperclipai/paperclip/pull/15683).
The published baseline `ea6c8eb5e16d61111968f633a66748b397b64a3e` has
53 successful hosted checks, two conditional Storybook skips, required verify
and E2E passes, fresh 5/5 review and 30 resolved threads. Its
[package qualification](https://github.com/paperclipai/paperclip/actions/runs/38478290686)
passes all four native producers and clean Apple Silicon, Intel Mac and Linux
ARM64 consumers. All 18 package source manifests and binary hashes match; no
Codex payload is bundled. The isolated Apple Silicon install and zero-turn native
startup pass, and fresh installed JavaScript applies all 342 migrations through
0343 with confirmed owned cleanup. These are literal baseline results, not proof
of the new repairs. Linux remains GNU libc 2.39 or newer on x64/AArch64; Windows,
Alpine and 32-bit ARM stay deferred. No warm-cache speedup or paid ARM task is
claimed. Docker, Cargo and native builds remain remote.
The [single baseline managed attempt](https://github.com/paperclipai/paperclip/actions/runs/38478333712)
fails completion reporting and the physical child-file assertion; its
[existing report](https://d1p6rlowie26tp.cloudfront.net/runner-e2e/campaigns/gha-38478333712-1/index.html)
remains red. Two runs execute provider turns. A third callback is falsely marked
successful during startup, before any provider turn, because its onboarding
parent is already Done. One unstarted child wake is cancelled. Recovery now
reuses the existing completed-onboarding handoff validator before applying the
issue-terminal backstop. Company, parent origin/status, assignee, completed child
and remaining children must match. Process-death and ownership checks remain.
Three reproduced baseline failures become 103 passing PostgreSQL controls across
the existing recovery suites, with canonical server typecheck passing. Owned
test clusters stop and release their slot. The native file tool correctly remains
bound to its current task: the original run saved a child document but attached
the file to the parent. First-task instructions now send file-producing work
through the child's own execution, dependency and block handoff, then verify and
link the child's result. Document-only and plan-only paths retain their scope.
Two reproduced instruction-contract failures become 15 passing existing asset
and greeting controls; these static checks do not prove model compliance.
All seven baseline managed lease rows are released or expired with successful
cleanup records, and prior company environment settings are restored. A separate
owned-server supervisor reports incomplete descendant cleanup after server exit;
its missing nested cause remains unresolved. Lease records do not prove physical
deletion or settle unknown charges. Existing cost and cleanup holds remain.
Revised-source live acceptance must still check actual turn events, the child's
downloaded physical file, source-correlated completion, follow-up and continuity.
Do not rerun the known failing baseline or weaken its assertions.
The normal staging preparation and exact baseline Core image build complete, but
the deployment check rejects `fleet_campaign_staging_requires_master`. Current
Cloud policy admits only actual master source ancestry, including preview DB
artifacts; a pinned, owned single target has no exception. No staging campaign
starts and no serving-candidate claim is made. A human sequencing decision is
pending: complete Mac and signed managed acceptance before a normal squash,
then qualify the actual merged revision on the owned staging stack, or use a
separate branch-friendly test environment before merge. Do not bypass this gate
or change merge method to preserve preview ancestry. The preview Core image has
verified content identity but no verified signature; the managed image signature
is separately verified. Actual private Cloud composition and fresh warm/cold
signup remain required production-readiness evidence after merge.
Next action: independent matching-source review, affected map checks and publish
the two scoped repairs in one source commit. Freeze that head, require fresh full
CI and 5/5 review, then repeat the existing package/install and single managed
journeys on admitted artifacts. Upgrade the idle local app with full saved
configuration, account and recorded-run-profile comparisons; preserve its data.
Use a fresh ordinary installed instance for automatic first-agent task/follow-up.
The new $100 QA ceiling permits bounded messages with paid concurrency one and
180-second runs; prior unknown-charge and cleanup holds remain separate.
Existing runners never migrate. Normal protected merge is authorized once
applicable gates and the sequencing decision are satisfied. No production or
provisioning-default promotion, local heavy build, new timer or archive is
authorized. Earlier checkpoints below retain their historical source attribution.
## Current Codex merge checkpoint — 2026-10-13
Current published `1173a859baa78af1d382058aa89c25920da25c3d` passes
the policy, selector and commitperclip gates and is mergeable; full checks and
fresh review remain incomplete. Two reviewed setup findings have treatments:
missing forced-Kubernetes environments stay unqualified sandbox targets, so
automatic Codex creation preserves Legacy without provisioning and explicit
native selection returns qualification guidance. Four baseline failures become
161 passing existing selection/environment controls. Local daemon resolution now
precedes credential staging; preparation errors remove only the owned pre-handoff
root, while unconfirmed probe retirement retains recovery state. Three original
filesystem failures become 96 passing setup controls. Fake credentials and service
controls do not qualify live Kubernetes or provider execution. Matching final
source review, maps and typecheck are required before publishing the fixes.
Published `2902b72c330d37ddff5d59e07927716dc3e1517c` is blocked before
main CI by the repository's tracked-lock policy and another master conflict.
The generated dependency lock is retained as build evidence; the branch restores
master's exact tracked lock, using the existing scripts-disabled CI resolution
path instead of bypassing the gate. Normal reconciliation with
`e0f30a4c7186498b71b2637f253b3399997dac7d` preserves controller-loss
attribution, creator identity and migration 0343, voice qualification and Apps
connection controls. Both test conflicts retain the Codex runner checks and
incoming controls. All 45 built-in and 44 controller/run-state controls pass;
maps and token gates remain clean. This source requires fresh CI/review and
appropriate installed/live qualification. Cancellation is requested for the
obsolete 2902 managed workflow before a paid test job is observed; terminal cancellation and unknown
remote costs still need confirmation. No unchanged paid test is retried.
Independent inspection verifies the literal 578 fresh Mac journey below: exactly
one child, one document revised from one to two, and the same workspace file
changed from Saturday to Sunday with both required markers. Five executed runs
succeed with no interval overlap; one terminal-child wake is cancelled before
starting. Parent session continuity and the separate child session in the same
workspace are recorded. Estimated run cost is $1.820721600; setup usage and
settlement remain unknown. Reload preserves the completed task and revision.
This manual evidence does not relabel the original managed failure or newer source.
The reviewed fixture changes are published as
`8d65fd7fc31d8170082f30a314b87c4779f91e8a`. Before a main CI merge checkout
is created, master advances to `edcfcaf3f69abfda12fcbc63225f7346f53450aa`.
Normal reconciliation retains its repository-skill preparation, signed idle wake
deadlines, readiness errors, voice support and migrations 0341/0342. The sole
text conflict preserves master's cancelled-lock return semantics and the PR's
bounded error-code diagnostic. The dependency lock is completed for the existing
server test dependencies and incoming voice dependency, without changing prior
resolved versions or running install hooks. Frozen-lock validation, 29 existing
native-authority/runtime-skill controls, E2E no-emit, maps and token gates pass.
This combined server/UI/DB source requires new package and live qualification;
literal 578 results below remain attributed to their actual source.
The separate fresh Mac UI journey on installed 578 selects automatic native Codex,
connects an API-key account, creates the first agent, and reaches the ordinary
opening card. Accepting its proposal creates exactly one child task with a saved
document and workspace file. A follow-up changes that existing document to
revision two and edits the same file. Independent content, recorded execution,
workspace, session-boundary and accounting inspection remains in progress.
The failed managed eval is retained separately; this manual journey does not
turn its failed oracle green. All paid work remains bounded by the new $100
allowance, 180-second runs and single-provider concurrency, with prior holds kept.
Canonical branch: `codex/codex-runner-default`. Delivery PR:
[#15683](https://github.com/paperclipai/paperclip/pull/15683).
The runtime/install prerequisite #16028 and release repair #16149 are merged.
The finish line remains ordinary native Codex onboarding, checked task/follow-up,
saved-agent preservation, exact-candidate installation and required checks, then
a normal protected merge. Production deployment and default promotion remain
outside this merge campaign.
Reconciled head `d68f1facf0e174a4f8a771a2055e02c72a47c289` receives a fresh
5/5 review with all 28 threads resolved. Its required E2E check passes, but the
aggregate verification check fails two test shards. A retained company fixture
collides because it truncates random UUIDs to six characters; full-UUID seed
treatment passes 255 existing PostgreSQL controls with zero skips. The existing
Runner durable-progress case lacks the diagnostic evidence needed to identify
its failure. Bounded failure diagnostics retain the original error, all deadlines,
usage, recovery and deduplication assertions. One exact local case passes;
controlled delayed-save and early-admission failures show why that pass cannot
prove the original cause. Independent review approves these two test-only edits.
The next published head still requires its own CI and review.
Literal 578 remote qualification now passes all four producers and the maintained
Linux, Apple Silicon, Intel Mac and Linux ARM64 install scopes. All 18 tarballs,
source manifests and binary hashes match; no Codex payload is bundled. Native
consumer reports cover zero-turn open/close and cleanup, not paid ARM execution.
Fresh local installation/native/CLI controls pass. Its fresh DB helper fails
before migration with missing bootstrap stderr; its original cause remains unknown.
The ordinary existing-data restart separately reports exhausted Mac shared-memory
IDs. Releasing exactly two dead, unattached task-owned fixture segments restores
the app without changing host settings or other services. Installed 578 applies
migration 0340, reaches recovery ready and preserves three full agent execution
configurations, eight recorded run identities and safe account summaries, with
zero provider work. This proves upgrade preservation, not fresh initialization.
A separate ordinary installed CLI entry then starts with a new isolated home
and empty data, applies all 339 packaged migrations including 0340 and reaches
recovery ready with zero companies and provider actions. This proves fresh
startup after the owned resource cleanup; the original test-helper failure and
its missing cause remain recorded.
The original managed child-task failure remains red. Explicit first-task skill
invocation and delivery source are recorded, but the retained trace cannot prove
the model received the child-rule bytes or the complete dynamic-tool schema.
Two rejected human-input calls recover through the ordinary API; their rejected
argument shapes are not retained. Causality remains provisional. The fresh staging
image and protected check pass at literal 578; deployment is blocked by an already
active workspace deployment, with no campaign started by this QA request. Wait
for that operation before any explicit normal deployment retry. No production
or provisioning-default action is authorized.
Historical literal candidate `57881c607fcea782ac30f601b768b2142fc2184b`
passes all required checks: 53 successful checks, two conditional Storybook skips,
fresh 5/5 automated review and 28 resolved review threads. The existing hosted Linux
login/reload case passes against its recorded CI merge. The previous failed
attempts below remain historical evidence.
Normal reconciliation with master `7eea9d8214fec00dfde32bda7fcf9b20a428e330`
accepts its source-annotation Storybook/map migration. All 263 authored suites and
2503 story identities, exports and play counts remain intact. Retired aggregate
files and their review history remain in Git; current indexes regenerate as
ignored outputs. Durable creation/onboarding annotations describe fixture limits. The 28
existing tooling controls, UI typecheck, token gates and 35-area/175-ID map check
pass. Independent inspection finds no change to native execution, defaults,
onboarding, credentials, workspace, DB, CLI or packaging source relative to 578.
The isolated GitHub review-heading change and Storybook build preparation retain
their incoming master source. Fresh published-head CI/review is still required.
Literal 578 [remote package qualification](https://github.com/paperclipai/paperclip/actions/runs/38464237723)
has completed successfully. The [single managed onboarding attempt](https://github.com/paperclipai/paperclip/actions/runs/38464212481)
passes automatic selection, saved environment qualification, native authentication,
hire and reload, then completes two successful native runs with session continuity.
It fails the accepted-child assertion: the model puts its document/file on the
onboarding parent and finishes that parent despite the delivered first-task skill
requiring a child. Preserve this candidate failure; it is not a passing E2E cell
or complete task/follow-up proof. The owning verifier records six terminal lease
rows with successful cleanup, of which four appear in the selected report;
physical deletion and unpriced usage remain unsettled.
The former staging QA stack is archived with a decommissioned database. Its
normal preview preparation rejects the lifecycle before deployment. A new owned
QA workspace has been provisioned through the ordinary signup path; it still
needs candidate deployment and live verification. Previous preview/runtime proof
is historical. Heavy builds remain remote, existing-agent data stays preserved,
and no production deployment, default promotion or timer is authorized here.
Published `e301c68d645eabd9fa7ae3a9450a460f6d2d0439` passes required CI with
52 successes and two conditional skips. Its fresh review finds one linked-login
setup defect. Literal executable source `6c0eca871616a110954553d6ff971e7655c85f93`
passes [remote package qualification](https://github.com/paperclipai/paperclip/actions/runs/38445419339),
including all four producers and clean Apple Silicon, Intel Mac and Linux ARM64
consumers. Fresh installed JavaScript initializes migration0339. The existing
Mac app upgrades while preserving three full agent configurations, eight
historical runs and saved account summaries, with no provider work during upgrade.
The [managed6c attempt](https://github.com/paperclipai/paperclip/actions/runs/38448001365)
passes the saved environment probe, native account/model hello, native hire and
campaign bounds. A legitimate reload then returns onboarding to step one before
Get started. Both setup leases and fixture cleanup pass; no task/artifact/follow-up
is reached. Preserve this failed attempt. The production draft-restoration fix
passes192 existing/new controls and independent source review, including delayed
loading, explicit fresh starts, old runner choices and company/account boundaries.
The managed fixture keeps its reload assertion. The separately scoped linked-login
fix stages checked credentials only for isolated setup and keeps the general
no-follow guard, refresh target and bounded retirement contract. Its original
source passes both regular-file controls and fails both linked-file controls
after the real lower materializer omits authentication. The matching treatment
passes69 setup controls and12 unchanged lower controls, server no-emit and
independent source review. Private copies retire only after confirmed cleanup;
an uncertain close retains owned state and remains a failure.
The reviewed fix commit is `12046f522bca29ded24425be71b856993b4997f7`.
The normal merge retains exact master `393d1c410862aa93561548e0a39feec3b89df6ff`,
including migration0340, shared/plugin lifecycle contracts and file recovery.
Independent source inspection confirms all four reviewed fix hashes and the
incoming executable changes. Storybook reconciliation retains263 suites and2503
authored IDs, both review histories and all four incoming recovery states. Its
27 existing controls, maintained catalog check and35-area/175-ID map check pass.
Only JavaScript dependencies are prepared locally; native/image builds stay remote.
The combined736 source passes368 focused checks across10 files with zero final
skips. The initial sandbox listener failures are preserved separately; unchanged
support probes and owned loopback execution reach the affected tests successfully.
Incoming master `c7f4b74111d16f0b57112fa6d0b6a59c2d63bfe8` then adds fresh-task
workspace source isolation. Its eleven server files remain exact master, and281
affected source/trust/preparation/runtime controls pass without repeating the368.
The catalog retains263 suites/2503 IDs and both histories.
An actual task bootstrap check finds a narrow compatibility mismatch: an explicitly
configured or operator `CODEX_HOME` with linked auth can pass setup while task
isolation omits that link. Ordinary new defaults create no such link; regular host
logins and server-selected managed account homes seed correctly. Keep the general
no-follow guard. Use existing server-owned managed credential provenance to reject
the unbound linked case with explicit Legacy/managed-account guidance, while
retaining checked setup seeding for resolved accounts. The existing fake bootstrap
stops before provider launch; it is not live account proof. The existing trusted
outer managed credential-home context closes this mismatch without a new schema
or permission field. Four linked cases reproduce false setup success before the
guard;81 final setup controls, server no-emit and independent source review pass.
Regular homes, API-key precedence and resolved-account setup aliases remain
supported. Raw configuration cannot provide the trusted provenance.
Published `1d09569b054e0ad9f4bc9e4d92ad1212d4794f7c` retains that combined
source. Its exact-head review is4/5 with one additional selected-key precedence
finding: `CODEX_API_KEY` still enters subscription validation when the task
materializer would use that key directly. Six local/remote selected-key controls
reproduce the failure; six `OPENAI_API_KEY` controls retain their behavior. The
two-line correction skips unrelated subscription reads and refresh binding for
either selected key. Frozen treatment passes93 setup controls,12 unchanged lower
controls, server no-emit and independent source review. The first93-control run's
91 passes and two import-deadline/follow-on failures remain recorded; the unchanged
standalone run passes without extending a deadline or weakening an assertion.
The [1d CI run](https://github.com/paperclipai/paperclip/actions/runs/38459704117)
passes build, typecheck and native verification but has two independent blockers.
The onboarding browser case expects the obsolete return to the Agent step. Its
captured screen correctly restores Connect, Ada and the original authorization
link. Update that existing case to verify the exact active session, company,
name/harness/Auto choice, one login start and no pending-login hire through both
route reopening and actual reload. Independent source review passes. Local
baseline reproduces the old assertion; the final local attempt cannot initialize
its fresh PostgreSQL cluster before browser execution. Preserve that failure and
require the existing hosted Linux E2E case to prove treatment. The chat shard
loses its hosted runner connection; no failing chat assertion or test log is
available. A new ordinary current-head CI run must replace that incomplete gate.
No new image, package or paid live campaign was dispatched during these fixes.
Next action: publish the reviewed narrow corrections together. Require fresh
CI/review, affected installed-package and managed first-task proof before ready
or merge. Historical receipts keep their literal sources. The following
checkpoints are retained history, not the current merge state.
## Production preparation checkpoint — 2026-10-13
The runtime prerequisite [#16028](https://github.com/paperclipai/paperclip/pull/16028)
is ready for review at `271d434c170e74bdedde65d0b13059a55419c943`.
[CI attempt 2](https://github.com/paperclipai/paperclip/actions/runs/38346601686)
passes 54 checks with four conditional skips; fresh Greptile is 5/5 and all four
threads are resolved. The first attempt's bounded Pi Node archive timeout is
retained. The unchanged-source retry passed without relaxing source or deadlines;
its underlying network/host cause remains unknown. The passing CI installation
records merge source `7a82a37438e6e448abc7cc5caa60dc2519a97be0`, distinct from the
PR head. The [final literal-source package campaign](https://github.com/paperclipai/paperclip/actions/runs/38347027535)
passes all four daemon producers, public Linux assembly and Apple Silicon,
Intel Mac and Linux ARM64 clean consumers. The Linux ACPX component probe uses
explicit installed authority; normal Mac/ARM native lookup rejects authority
overrides. Neither establishes final cloud onboarding/task acceptance. Small
report ZIP downloads did not complete in the browser and the CLI token is invalid;
no independent current-report rehash is claimed.
GitHub's normal ready-PR gate still requires a code-owner review. On 2026-10-13,
normal protected squash auto-merge was enabled for exact `271d434c`; approval
remains pending and no slice was merged. The user authorizes normal protected sequential merges,
not admin bypasses, production deployment or provisioning-default promotion.
[Codex #15683](https://github.com/paperclipai/paperclip/pull/15683) remains clean
at `1a0ca66242121e39d88455aa2b52a07acc4a07d9`, based on the historical `5a9ce11`.
The parent has advanced and GitHub reports conflicts. Reconcile with the actual
merged parent before publishing prepared fixes or claiming final checks. The
Claude owner retains its branches, private installed-authority correction and
separate $50 qualification ceiling. Those fixes need package and live acceptance;
root does not rewrite the Claude branches.
Fresh ordinary managed onboarding currently lacks the saved platform probe
before Auto resolution; an unqualified immutable OCI environment selects Legacy.
The prepared Codex-only UI correction reuses the existing permission-gated saved
probe on explicit Connect, refreshes scoped discovery and validates the selected
runtime. It retains actionable failures, explicit Legacy and current creation/
discovery non-allocation. The existing explicit-only Product E2E cell gains fresh
wizard-owned qualification, two authoritative setup lease IDs, independently
checked physical-file output and follow-up continuity. Its fixture does not
create an agent or preprobe. Missing responses preserve unknown cost coverage.
No new suite, grader, automatic roster or local-prompt replacement is introduced.
The privately composed source passes 44 targeted onboarding controls and 184
existing Product E2E support controls, UI/E2E no-emit and guarded patch
applicability. The earlier full wizard controls pass 117 cases at their recorded
source. Independent review found an unanswered-setup accounting gap: four cases
fail before the fix; 117 first-task controls pass after. Comment cleanup preserves
353,839 composed executable tokens and semantic ASTs. Required onboarding maps
retain IDs, actual probe authority and source-only/not-run limitations; structural
checks pass 35 areas/171 IDs. Storybook metadata must be reviewed after actual
parent reconciliation; its catalog/script are absent from literal `1a0ca662`.
This private preparation is not integrated, published or live-qualified.
A private reconciliation rehearsal composes exact Codex `1a0ca662` with exact
prerequisite `271d434c` without modifying either published branch. It retains
master's render helper, moved Storybook paths and additional catalog cases; the
managed onboarding cell is added to the existing catalog with 730 total cases.
The rehearsal is not an actual post-merge candidate and does not close hosted,
installed-package or live Cloud acceptance. Its narrow checks and source manifest
remain private until normal source reconciliation is authorized by the actual merge.
The private root review reproduced four cache failures under production
`staleTime: 30_000`: setup omitted fresh availability reads, hid a discovery
error, and skipped qualification after an image change. Both managed Codex
setup reads now set `staleTime: 0`. The same existing controls cover cold and
production-cache defaults; 53 selected UI controls and matching-source UI
no-emit pass on Node 24.19.0. Earlier 44-case results remain tied to their
pre-correction source. This correction is private and requires ordinary
published-head review and full qualification after the protected parent merge.
Cloud source `23531d729756ab0461a53f9358beb8df5c1781ed` uses named Daytona
snapshots without a verified final boot-image binding for fresh-company native
qualification. A read-only metadata request was rejected before execution because
automatic approval review requires explicit use of the particular API key.
Authorization is pending; no key was read or provider request sent. The expired
GitHub device code needs a new attended sign-in when the human is present.
Production Fleet Admin sign-in and a concrete current QA owner grant also remain
pending. The existing QA tenant remains pinned/user-managed and unqualified;
old auth probes and preview images cannot close the live gate.
The original $250 ceiling and $248.179254104 held/consumed ledger remain intact;
unknown charges and cleanup holds are not certified invoice balance or available
funding. Codex retains its bounded $2.50 setup/two-task-turn reservation plus $2
cleanup. The expanded manual first-task cell has no separate paid reservation.
No provider turn, paid environment allocation, local Docker/Cargo/native build,
rollout or default promotion occurred in this preparation. The preserved local
preview remains `http://127.0.0.1:3125/COD/agents/all`, literal behavior source
`fe1ecf1c3449c21d6e6f0c9d9772d1949b80ea82`; its data and recorded runners remain
untouched. Root does not upgrade existing agents.
Next gate: obtain actual code-owner review and restored GitHub CLI authentication,
then perform the normal exact-head parent merge and reconcile Codex/Claude with
its actual master commit. Compose these prepared fixes, retain required maps and
fresh review/checks, resolve the Cloud boot-identity boundary through authorized
metadata, and qualify the final immutable managed candidate. Actual private
Cloud distribution, warm/cold signup, useful task/follow-up, existing-agent
preservation and production-image rollback/forward-recovery checks remain open.
The stack is not production-ready and production deployment remains unauthorized.
Evidence: `/private/tmp/pr2-271d434-final-qualified-ready-receipt.json`,
`/private/tmp/pr2-managed-onboarding-accounting-root-review.json`,
`/private/tmp/ci-artifacts-271d434-installed-native-lookup-audit-receipt.json` and
private composed source manifests. Public PR bodies contain the exact current
checkpoint; historical receipt sources remain literal.
Updated 2026-10-13 UTC.
## Fresh cloud onboarding remains unqualified
@@ -1481,6 +1887,11 @@ to run. The actual legacy Codex task completed and its independently read file
contained the exact two requested lines. The same-task follow-up is running.
No second task, agent hire, or automatic runner conversion was used.
Next action: commit and push the narrowed candidate, rerun its checks and fresh
review, then update the PR and existing evidence report. Start the Codex-default
slice after the user chooses to proceed. Merging and deployment remain outside
this task.
### Occupied credential fixture follow-up — 2026-10-12
Current-head `021df207` Runner Vitest 2 failed during fixture preparation with
@@ -1501,3 +1912,141 @@ zero provider calls or native builds. Comment-only removal preserves the tested
executable structure; the suite was not repeated. Evidence is recorded in
`/private/tmp/ci-final-021df2-shared-credential-quorum-receipt.json` and its
comment-closure receipt. Fresh published-head CI and review remain required.
### 2026-10-13 Published canary and fresh staging qualification
The human merged prerequisite #16028 at actual Core master `d67e3507b23041212fa26302ce6de078c5ebcc05` and asked to cancel the existing timer, then test the published npm canary locally and on a new staging stack. The `finish-runner-default-stack-and-merge` heartbeat was deleted. Codex defaults #15683 remains separate and unmerged. No production or provisioning-default promotion is authorized.
The human approved a separate $25 ceiling: $15 for one owned QA stack/sandbox including pool backfill, $5 for setup and at most four short task/follow-up turns, and $5 for cleanup. Zero automatic retries. The original $248.179254104 held/consumed and all original unknown and cleanup holds remain unchanged. Actual new resource cost is unknown and held within the new reservation.
Ordinary authenticated staging signup created `stack-pool-7998e841ace7` at https://runner-canary-d67-qa-oct-13.staging.paperclip.app. It reached fresh first-agent onboarding with zero agents or provider turns. Its user-managed pin is verified. Initial distribution `cloud-38355190192-1` is old source and has observed schema drift; it is baseline only. Exact d67 signed standard image, source gate and signed migrator have passed. Matching private composition is building through the existing canonical workflow, without a duplicate dispatch.
The public d67 release38389963483 ended successfully but skipped native production, publication and canary onboarding. Registry canary.5 provenance binds it to old4a641d, so local acceptance remains blocked. The focused repair [PR #16149](https://github.com/paperclipai/paperclip/pull/16149), exact `ab99d3f7604cb2ac8d8a45c81276797af834e325`, adds explicit cancellation/source-result guards to the existing producer and canary smoke. Its existing contract cases reproduce two missing guards before treatment. All70 release controls and20 source-verification neighbors pass after treatment; independent source review is clear. All required hosted gates passed with fresh5/5 and actual code-owner approval. PR #16149 merged at `60bc0d5fee9a6e48db08fc016521fee3d9f57d67`; its new master-push release38395574681 is running. Concurrent master changes include Storybook indexing and verification-skill docs; npm and staging source identities remain separate. Source predicate tests support the diagnosis but do not establish actual GitHub scheduling or publication.
The native-runner QA override is applied and converged through one-target feature campaign1791869766576, with zero failed targets. Literal d67 private distribution `cloud:38392212140:1` is qualified. Supported one-target deployment request `f7cb6751-91f8-49a4-9ab8-6092ecb27e7c` passed exact-source/private-artifact preflight38395788220; deployment38395855695 succeeded with authenticated serving verification and `set_default=false`. The pin and current private distribution remain verified.
Attended OpenAI device authorization completed in the embedded browser. Ordinary fresh onboarding created Legacy preservation QA (`f9e30b8e-7ceb-4f88-b373-1a2cba65859d`) with its Codex Legacy configuration and unopened first-task question. Its sandbox and connection settings were retained. Native Codex package QA (`861f95bc-c9fc-4e32-8abb-8829d3fe42de`) was created separately through the explicit experimental runner picker, using Codex, gpt-5.6-luna, the responsible user's saved subscription and Paperclip Computer. This tests the merged prerequisite; automatic Codex defaults remain outside this source.
The native creation Test reported success, but its visible details and exact d67 route show a Legacy Codex ACP/CLI model hello, not native runtime execution. At least one real setup hello is held in the setup reservation separately from the four task-turn allowance; other unmeasured setup usage is not assumed zero. Setup lease `1f2b04ce-97c2-4f81-8f92-0ece0fb54feb` and provider resource `622b8bb6-8bec-40d2-83c2-fa5edddfa6e8` have no independent cleanup confirmation yet. Green setup is not native execution or physical cleanup proof.
Native QA policy survives reload with timeout180 seconds, concurrency1, interval disabled and max-turn continuation disabled. Separate transient/connection retry policy still needs an existing supported control before launching the task. The nonce-bearing first file challenge is drafted, not submitted; task turns remain zero. Existing file-artifact and session-continuity assertions are being reused, with manual adaptations identified rather than relabeled as an unchanged E2E suite pass.
The retry audit found no supported retry-only UI control and no certified provider-start bound: existing native recovery can launch additional continuation prompts. The human explicitly approved normal recovery within the same $25 ceiling, with at most four manual task/follow-up messages, 180-second run timeouts and no automatic test reruns. Production recovery policy is unchanged. One manual staging task was submitted (`9f706825-36db-4950-9179-659406db37fb`); its native execution, file bytes and continuity remain pending. Manual message counts and observed underlying provider/recovery events will be reported separately.
Release38395574681 has now actually completed all four native producers, including Darwin x64 and Linux ARM64, and its canary publisher is active. This supplies hosted scheduling evidence for the release repair. Actual source-bound registry publication and published onboarding smoke remain pending; canary.5 is still excluded as old-source evidence.
Next action: verify the actual staging serving revision, wait for the source-bound published registry package, install the real package in an isolated Apple Silicon consumer, and run real file task/follow-up journeys within the new budget. Preserve the old3125 test-drive and all receipts. Current evidence: `/private/tmp/runner-d67-published-canary-qa/evidence/` and `/private/tmp/ci-artifacts-d67e350-artifact-readiness-receipt.json`. Neither requested live runtime test has passed yet.
#### 2026-10-13 Final published-consumer and fresh-stack result
Actual master release38395574681 completed all four native producers, npm publication and real canary onboarding smoke. Public `paperclipai@2026.1013.0-canary.6` binds to exact60bc, including narrow merged release repair #16149. Its clean isolated Apple Silicon install passed normal lifecycle, all18 no-bundled-Codex tar checks, packaged daemon/provider verification, native startup/open/close and CLI/doctor checks. Official optional npm Codex dependencies are retained; no local Cargo/Rust/Docker/runner-source build occurred. Literal d67 private staging composition and literal60bc npm remain separately attributed.
Ordinary local onboarding completed with the explicitly authorized OpenAI API key saved in a managed connection, and created Legacy preservation QA. The local subscription device flow expired; no subscription was saved. No credential values were written into prompts/reports. Native saved-account setup exposed a real published UI defect: the selected native runtime delegates to Legacy readiness and can trigger a second forced CLI probe, failing `Command not found in PATH: "codex"` despite successful packaged native resolution. Current private #15683 already contains the native setup probe correction, but its artifact/UI has not been tested here. Configure navigation cannot adopt the failed connection; no developer PATH or global Codex workaround was used.
The supported published API created a separate explicit-native local QA agent with the saved responsible-user OpenAI API-key binding. Real UI task [NPM-2](http://127.0.0.1:3136/NPM/issues/NPM-2) completed native runs88eeb636 and4990be3e in43/46seconds. Independent26/52-byte downloads, exact random challenges, negative newline controls, durable attachments and run-attributed work products pass. Same saved account/grant and execution workspace are recorded. A self-added200-cent monthly cap correctly paused after unpriced metered gpt-5.6-luna usage; spent0 is not proof of free use. Removing only that supplemental cap to ordinary budget0 and explicit resume caused a recorded adapter config-revision freshness reset. The second provider session is fresh, so strict same-provider-session continuity fails and is not waived. No pricing or production budget policy was changed.
Fresh staging [RUN-2](https://runner-canary-d67-qa-oct-13.staging.paperclip.app/RUN/issues/RUN-2) completed native runs7d242e7b and a8e62d9c in93/73seconds at d67/cloud:38392212140:1. Independent26/52-byte downloads pass; recorded UI/PRP events show session.started then session.resumed with the same provider session and workspace. Source-bound UI proof is distinct from a direct stored-row/full-grader export, which was unavailable. Its setup green was a Legacy hello and remains excluded as native readiness proof.
Existing local Legacy full execution settings survived native enablement, an unrelated title edit and reload byte-for-byte; that control made zero provider calls. Both native QA agents are paused after four total authorized manual task/follow-up messages, zero test reruns, with normal product recovery unchanged. Local live runs are0. The installed preview remains [3136](http://127.0.0.1:3136/NPM/issues/NPM-2). Historical3125 is stopped, with its original data intact; no current safe staged source-build preflight was available and it was not restarted. Staging remains pinned/user-managed and available for inspection, with no production/default promotion.
The existing exact-source file/artifact graders were reused. Strict registration helper title checks fail because the manual prompts requested readable titles rather than filename-as-title; correct attachment/run attribution passes separately. No metadata was rewritten to manufacture a pass, and no full catalog-cell pass is claimed. Physical cleanup of setup lease1f2b04ce/provider resource622b8bb6 and provider invoices remain independently unconfirmed. The separate25-dollar reservation and original248.179254104 held/consumed ledger preserve all unknown and cleanup holds. Metered model pricing remains unknown/unpriced. Required next gates are corrected native setup artifact qualification, priced-model budget acceptance and authorized physical cleanup confirmation; this does not make the default rollout production-ready.
Detailed receipts and sanitized report: `/private/tmp/runner-d67-published-canary-qa/evidence/`. Public package admission/source receiptc9eeaf…; native consumer receipt45b613…; paid-pair offline integrityb6bb4e…; exact account attribution is a separate six-field projection. These are literal qualification sources, not the unmerged root HEAD1a0ca662. Record-only changes are retained locally for the next actual reconciliation commit; no doc-only CI churn or dependent branch mutation was introduced.
The sanitized report is uploaded and independently download-verified as attachment-backed artifact work product122676da on the unassigned completed operator [NPM-3](http://127.0.0.1:3136/NPM/issues/NPM-3). It does not wake an agent or close the feature gates. Native task artifacts are unchanged. The authorized Claude owner received the prerequisite source/qualification boundaries; no ownership or allowance was reassigned.
#### 2026-10-13 Authorized Codex defaults finish and merge
The human requested that #15683 be finished and merged normally. A separate incremental $100 ceiling and as many bounded messages as needed are explicitly approved. The previous four-message/$25 campaign and original$250 ledger retain all unknown-charge and cleanup holds; they are not refunded or reassigned. Reuse local3136 and owned staging stack7998; preserve their data and receipts. Root owns actual-master reconciliation, exact-head checks/review, ordinary Mac/managed onboarding, checked task/follow-up and normal protected merge. Claude owner retains dependent branches and separate allowance. No production deployment or provisioning-default promotion is authorized. No timer is recreated.
Current-master integration includes `833769ab557255b11dd8f650f43ed7333653f5e4`, then `e3029c632b26b68595adc1a704a387833b3cefcb`. The ordinary merge retains the published Codex history and prerequisite squash history. Its audited logical source delta preserves master fixes, the prepared managed Connect qualification, fresh scoped discovery, and existing first-task eval assertions. The remaining merge conflicts concern Storybook indexes and dated reviews, not execution code. Independent review of both source compositions found no concrete P1/P2 regression; source review does not establish live acceptance.
On the integrated checkout, two focused Codex runs pass 261 tests each across onboarding, runner selection, setup, editing, imports and readiness. Server and UI direct TypeScript checks pass after JavaScript-only shared/DB/adapter-utils/SDK preparation. All token gates pass. New master recovery controls initially report a missing declared trace test dependency and a sandbox-denied PostgreSQL listener; the four unaffected suites pass 74 cases. Isolated installation of the exact declared trace dependencies and an authorized temporary listener allow the two affected suites to pass all 60 cases. No tests are disabled, no lockfile or production policy is changed, and no local native/Docker build occurs. Full canonical workspace checks remain assigned to fresh hosted CI.
Fresh-source remote package qualification, ordinary Apple Silicon onboarding and immutable managed staging onboarding remain pending. The previous canary60bc and stagingd67 receipts stay attributed to those sources. The new budget record reserves resources60/provider30/cleanup10 dollars and retains all prior unknown holds. The supported private Cloud skill and CLI are read from exact private master `4f3a63ad6f3f84c87e0e129da35909d8ccc7ffb0`; a deliberate pre-merge Core preview is separate from actual private Cloud distribution. Freeze the final reviewed product source before building; deploy only the owned pinned QA stack, with `set_default=false`.
Published intermediate448db859 passes the focused source controls and starts fresh hosted checks. A bounded managed-image review then identifies a concrete setup mismatch: real sandbox tasks select provider outer isolation, while `probeNativeRunnerEnvironment` overrides the verified transport choice with false. Correct this internal forwarding and derive its value from the server-resolved target; preserve local/SSH Codex isolation and removal of injected environment flags. The obsolete remote package qualification38423256993 is cancelled to limit costs and is excluded from final proof. Native/Docker work remains remote. Current source and new-head qualification must close the corrected boundary before acceptance or merge.
The maintained Daytona execution image is distinct from a standard Core app image. A saved immutable OCI digest without snapshot/template fields uses normal environment probing, measured OS/architecture/libc, actual image binding and confirmed lease cleanup. The existing full-stack E2E workflow owns its content-addressed execution image and one explicit managed-onboarding cell; its image build and live cell are not yet dispatched. A Core app image cannot be assumed to have compatible Daytona boot behavior merely because it contains the daemon. No provider credential is read to work around this boundary.
The isolation correction changes three production lines, with no API/configuration field or permission change. Inert launch baseline1/8 fails; matching treatment8/8 and23 inert/source neighbors pass. Selected-target server baseline12/12 fails; the full treatment suite51/51 passes, including contradictory configuration/environment flags. Direct server no-emit and independent source review pass. Read-only and approval policy, owner-bound credentials, deadlines and cleanup remain intact. A separately retained overbroad local-listener scaffold failure is not counted as native execution proof.
Intermediate448 hosted CI completes successfully. Fresh review4/5 correctly identifies the new managed case entering a local-only confirmation fixture. Baseline reproduces two failures; scope the existing local fixture correctly, retain all twelve local cases and the thirteenth explicit managed case, and reuse the separate managed-fixture checks. The full existing E2E support run passes2694 controls and exposes two more stale roster assumptions. Update those assertions while retaining the completion judge for accepted managed work and every Pi admission/negative control. No parallel suite or replacement grader is added. Final source still needs fresh published checks/review and live qualification.
Embedded-browser inspection of the built448 stories confirms the dark shared Runner popup and saved Legacy choice. It also exposes remaining OS-native environment/lifecycle/ACP dropdowns on the relevant runtime page. Their narrow shared-picker conversion preserves all values and callbacks and leaves unrelated provider-specific controls alone. These UI changes require a new JavaScript-only Storybook build and rendering checks; the old build remains literal448 evidence. No screenshot baseline is created or changed.
The corrected source passes the full existing E2E support suite:125 files/2697 tests, plus all128 existing Node source/qualification contract controls and direct E2E no-emit. Relevant dropdown baseline145/145 and treatment152/152 pass, including exact save requests for selecting/clearing an environment while retaining Legacy/native execution and accounts. UI no-emit and token gates pass. Independent review of the managed-isolation and confirmation-fixture corrections is clear. These are local source checks; exact-head hosted CI/review, fresh remote packages, rendered stories and real Mac/managed onboarding still remain required. Next action is a single corrected candidate publication, then affected qualification using the existing workflows.
Current published Codex head1a0ca662 is draft with green historical checks. Actual master833769ab is newer than merged prerequisite d67 and release repair60bc. Prepared private onboarding/Storybook work will be reconciled by source, without claiming its private/historical checks as final qualification. Native Connect correction is already in the Codex slice. Final managed defaults require the saved immutable OCI environment probe owned by ordinary Connect. Existing suites/fixtures/assertions/reporting are reused; no duplicate grader or silent Legacy fallback is added. All heavy builds stay remote, Codex payloads remain external official npm dependencies, and saved agents retain runners.
Next action: preserve/commit current evidence, integrate actual master plus reviewed prepared corrections, run targeted checks, freeze/push candidate, require fresh fullCI/review, then qualify ordinary creation/onboarding on Mac and the one staging target before protected squash merge.
The frozen30bc candidate passes all current-head required CI and fresh5/5 review. Its existing remote release-smoke qualification passes all four producers and clean platform consumers. The actual managed onboarding cell38428601763 fails before agent creation: scoped discovery selects native, but Codex0.160 attempts a nested filesystem sandbox while scanning AGENTS.md for the read-only setup session. Both measured setup leases release successfully; the separate fixture environment deletion fails because the fixture leaves it selected as instance default. Preserve this failed attempt, unavailable provider billing and cleanup holds. No task artifact or follow-up is reached.
The correction skips project instruction discovery only in the new empty setup workspace through the supported trusted Codex configuration. It retains the generated security arguments, read-only permission profile, approval-never, no dynamic tools, existing bounded hello turn and teardown deadlines. Ordinary task instruction discovery and saved agent configurations remain unchanged. Pinned official Codex0.160 source confirms the zero instruction limit precedes filesystem probes. Eight inert baseline failures become23 passing source/cleanup neighbors; direct runner/server TypeScript and maps pass. This does not establish hosted treatment.
The existing managed first-task fixture now snapshots and restores its prior instance default and managed-only setting before deletion, including lost setup responses. Unconfirmed default restoration blocks deletion and remains red; other restoration/deletion errors remain inspectable and retry only outstanding cleanup. Three reproduced baseline failures become129 passing first-task controls, with direct E2E TypeScript passing. Independent source review finds no actionable runtime/permission P1/P2; the required source-comment cleanup is applied. Final source needs fresh CI/review, package artifacts and successful ordinary Mac/managed journeys before normal merge. The one owned Core preview deployment for30bc completes through its existing exact-source check/deploy path; actual readiness is independently checked next. No fleet default is changed.
Corrected product source ca31623d36a3d63204077e2e951ff9cdcf2664cf passes all48 ordinary hosted CI jobs, required verify/E2E and fresh5/5 review with26 resolved threads. Its hosted package artifact11834160973 has verified ZIP digest d5d60bf5056f5573461f8d4bd873da78a0204c7f7295d03d5aa7234e55d4af69. The second isolated Mac consumer verifies all18 tarballs, no bundled Codex, official npm Codex0.160, all four daemon bindings and zero-turn native startup/cleanup. Normal install hooks include third-party optional C++ addons; no Paperclip runner/Cargo/Rust/Docker source build occurs locally. The source-bound preview completes one-target deployment38438245490 to the existing pinned QA stack, without default promotion; independent result admission remains separate.
Before paid cell38435063658 entered its matrix job, an admission audit found that ordinary onboarding timeout0 and agent concurrency20 did not satisfy this campaign's retained180-second/single-run bounds. Cancelled the campaign before its live cell started; image/build costs remain unknown and held. Extend the existing first-task fixture with a normal operator configuration PATCH and independent read-back before Get started. Only the timeout/concurrency bounds may change; runner/account/model/environment/permissions remain the wizard's original selection. This is a fixture correction, not a production default or API change. Its first iteration passes149 controls but independent review identifies the concurrency gap. The final combined bound reproduces three functional failures with the previous helper, then passes153 controls and direct E2E TypeScript. Independent review confirms that the timeout reaches the native turn deadline and the queue uses the saved single-run cap; exact source review closes before publication or further live eval admission. No failing or cancelled attempt is relabeled as passed.
The owned local3136 server is updated from30bc to literal ca316 hosted packages after an idle snapshot and stopped-data/home backup. All existing full execution configurations and recorded run projections match before/after, with no provider tasks during upgrade. The fresh Mac company's saved draft resumes with its agent name retained. Ordinary OpenAI API-key Connect creates native Codex with gpt-5.6-sol without a runner override; only the existing QA timeout/concurrency settings are then bounded before Get started. Actual useful task/artifact/follow-up proof is still pending. The staging immutable QA environment is selected temporarily as the instance default, with the prior Paperclip Computer value recorded for restoration. Its normal server credential fallback has not yet been verified. No direct provider-key extraction or production rollout is attempted.
The literal ca316 Mac journey now passes independent exact-file and registration checks for29/63 bytes, saved API-key account binding, native Codex provider session and workspace continuity across all five executed runs. One queued child run is cancelled before start and retained in evidence. Two manual messages and two confirmation responses produce five successful native runs; no process-loss retry occurs. Both task and child finish Done, and the QA agent is paused afterward. Rate-card estimates total$3.504199600, not invoice cost. The existing strict artifact/session helpers are reused offline; this is a real UI journey with independent evidence, not a full catalog-cell pass. Receipt7ef97c4705b085d465eeaf19f11d231e7b01e5a66c61b517cfcde0ec70a2db97 remains literalca316.
Candidate0065 has fresh5/5 review and26 resolved threads but its required E2E gate fails: the unchanged signoff fixture receives a cancelled run while waiting for executor success on GitHub's combined master checkout. The fixture discarded errorCode, so the precise cause is inconclusive. Preserve the failed gate; add only a bounded diagnostic to the existing assertion without weakening ownership, authorization or terminal-state checks. Managed38440601585 fails during image preparation after the hosted runner reports shutdown; its provider pack/live cell are skipped. No named live cell or provider task is admitted. Unknown preparation costs remain held; no automatic retry is dispatched.
Actual master252d9b5077f4eee98ec48225641ef1a02d824158 is integrated through an ordinary merge. Its only conflicts are the three Storybook catalog files. Semantic union preserves226 authored entries,2242 stories, stable IDs, both review histories and actual evidence limits; the existing generator,27 catalog/map controls and structural map checks pass. Runner/Rust/Codex selection/setup/onboarding/guard sources remain byte-identical. Master adds instance-secret storage and migration0339, including its account-home claim check; keep those changes and require fresh combined-source account/lifecycle controls, JS/DB installation, CI/review and current-source managed acceptance. Prior receipts retain their original revision.
On the owned staging stack, ordinary environment Test connects to the immutable image but cannot confirm probe-lease cleanup. New-agent discovery remains Legacy; the supported onboarding entry surfaces the exact pending-cleanup error before hiring. This is a blocked managed acceptance, not a native pass or a silent runner conversion. The QA environment had autoDeleteInterval0; source ordering makes immediate deletion after stop before archival a plausible cause, not a proven provider diagnosis. Attempting to change its QA interval to60 is correctly rejected while cleanup is pending, so persisted configuration remains0. Preserve the failed lease, its holds and the guard; do not clear durable state or extract provider credentials to manufacture qualification. Next action is confirmed owned-resource cleanup, then qualification of corrected QA configuration and normal native setup/task/follow-up.
Combined-source integration passes100 existing controls with the repository launcher's canonical isolated HOME/config/TMPDIR contract:41 device-login,12 real-PostgreSQL instance-secret and47 lifecycle tests, zero skips. Initial direct-invocation99/100 and alone identity-verdict failures remain recorded; no expectations or product code were changed. No on-disk worktree config write is observed, and3136 uses a separate preserved home/data. Direct server/E2E TypeScript pass. The existing signoff failure assertion now retains only a bounded verified errorCode; ownership, issue checks, deadlines, retry semantics and terminal failures stay intact. Actual-helper baseline12-pass/4-missing-diagnostic failures become16 passing inert controls, with no browser/provider work. This improves subsequent diagnosis and does not claim to repair the earlier cancellation.
The integrated6c candidate now passes all48 ordinary hosted jobs, required verify/E2E and fresh Greptile5/5 with26 resolved threads. The earlier signoff case passes on this combined source; its earlier0065 cancellation remains an inconclusive historical failure, not a proved flake. The remote four-platform/package qualification38445419339 binds literal6c. A single guarded managed onboarding cell38448001365 also resolves literal6c through the trusted master workflow and independently verified target lock; its exact selection and180-second/concurrency1 guard pass admission. No second paid cell or automatic test rerun is dispatched.
Master advances once more to c8efdbfba43377d39f57e4822e92d796a8a044b6 through Storybook-only #16196. Its only conflicts are the same three catalog files. Semantic reconciliation preserves all226 candidate suites and37 new master suites,263 suites/2499 stories, stable IDs and both review histories. Existing27 catalog/generator controls and35-area/175-ID map checks pass. Independent virtual-merge and actual staged checks prove every production/native/package/build component remains byte-identical to6c. Keep the6c package/image/live receipts literal; this catalog-only merge requires fresh head CI/review and applicable Storybook checks, not another expensive native build or paid runtime campaign.
The supported Cloud CLI is re-read from current private master8472ece87f8d9a9e17a6116b9f4631d98ce63486 and is byte-identical to the previously used maintained command. Its one-target preview request d227da49-fd73-44c0-9377-f25711e529bc builds literal6c remotely in38448052890, preserving the existing pinned/user-managed QA stack and leaving fleet/default promotion disabled. Build, deployment and actual serving-source verification remain pending. A separate QA environment with the same immutable execution image and autoDeleteInterval60 is saved through ordinary UI, with instance default unchanged and no probe yet. The prior failed environment, durable teardown record and cost holds remain intact. It cannot borrow the older environment's qualification facts; it needs its own new saved probe and confirmed matching cleanup before automatic native onboarding.
Existing ordinary board lease APIs and CLI diagnostics are identified, but anonymous challenge creation and the installed CLI's existing board context both receive401 at this tenant's public edge. No browser/provider credential is extracted and no new inspection API/workflow is introduced. The plugin settings route correctly honors Cloud's hidden-settings gate. Existing Fleet Admin provider links reach the normal signed-in Railway log UI; two successful aggregate orphan-cleanup sweeps prove the controller operates, but neither receipt binds the exact outstanding probe lease. Preserve that uncertainty and its hold. Current-source installed JS/DB migration/account preservation, independent managed task/follow-up and normal protected merge remain the next gates. No timer or production deployment is started.
#### 2026-10-14 Codex qualification and new Test environment reconciliation
Frozen product9546f41e964953c801ad8c2d8bdecadbd5cd3830 passes current-source required CI and fresh5/5 review with30 resolved threads. Its existing four-platform/package campaign38485482843 succeeds: all18 tarballs/four daemon manifests, normal isolated Apple Silicon install, native credential-free startup/open/close and fresh installed DB initialization through0343 are independently verified. This source-built qualification package is not a registry-published npm canary. No Codex payload is bundled, and no local Cargo/Rust/Docker/native source build occurs.
The original managed onboarding case38485488621 passes its19 assertions and completed judge, without retry. Four actual native turns execute the child-bound240-byte file and real completion callback/reply with parent session/workspace continuity. Its checkout reports dirty state: the verified generated target lock replaces the committed lock, but full final porcelain is unavailable. Literal HEAD, runtime/assets and effective graph are verified separately. The reused signed execution image keeps its historical producer identity. Guarded environment removal and server shutdown pass; physical deletion and invoices are not certified. Earlier failed attempts and unconfirmed cleanup holds remain intact. Public evidence: https://d1p6rlowie26tp.cloudfront.net/runner-e2e/campaigns/gha-38485488621-1/index.html.
Ordinary fresh9546 Mac onboarding persists native Codex without a runner override before any QA bounds. The first useful document task and actual Done-parent completion callback execute successfully. One human follow-up updates the same child document to revision2 and publishes a child-bound1,101-byte file. Independent API and real browser downloads match SHA256b758f6d23b33cfa9cfc597a4c3bc2abbf74dc56b7b5d2b30fc45f65c1a4d1905. All seven actual native runs succeed; parent sessions/workspace continue, child execution has its own task session, observed concurrency1, longest run under47seconds, reload preserved. Two recovered proposal-format errors remain a nonblocking quality follow-up.
Existing installed Mac upgrade preserves all three execution configurations, safe account summaries and eight historical recorded run profiles. The existing Legacy agent's ordinary title edit/reload keeps execution settings, and its shared Advanced dropdown retains Legacy. Two actual Legacy/direct-adapter runs complete the same task and independently checked15-byte then34-byte files. Prior session state is passed and workspace continues; returned provider UUID changes, so stable provider-ID continuity is not claimed. After explicit human authorization, the root-created company QA guard is restored to its original0 and a500-cent hard stop is scoped to the selected Legacy agent. Historical unpriced costs/holds remain unchanged, normal service resolves only the new QA incident, other agents remain paused, and the company is paused again after all runs finish. Rate-card estimates: Mac3.4154336, managed1.170946, Legacy0.114767 dollars; none is an invoice. The separate100-dollar ceiling and all original250/25-dollar unknown/cleanup holds remain enforced.
The human selected the actual new Test environment for pre-merge acceptance. Its deployed policy supports verified branch previews, unlike Staging's current master-ancestry restriction. Normal Test email-code sign-in has sent a code and awaits the human handoff; no OTP redaction workaround, session impersonation or credential extraction is used. No actual owned Test tenant, schema admission, deployment or live task is claimed yet. The maintained one-target CLI and deliberately core-only preview path are prepared, with existing snapshot/migration-role/health/lock protections and set_default=false. Private Cloud composition and production/default promotion remain separate post-merge gates. The human also authorized a code-owner-review exception for PR15683 only, after all current-head CI/review/live gates pass; no global repository rule is changed and no other PR's approval is waived.
Remote preview38498802456 completes at exact9546, through trusted workflow definitionb8ffeb973a2a1d430efabffd755f15b6c7cf112a. The ready result matches its single request; immutable Core image digest4cba5c3546c3af3b948f0ee9c3532ada7c754491ce2d175a00164adc46698976 and exact9546 DB/shared registry archives match producer bytes/integrities. This Core preview has no standard signed-image attestation; npm SLSA structure is source/invocation-bound but cryptographic verification is not claimed. The signed execution image is a distinct artifact. No image layers or large transfer archive are downloaded locally. Terminal admission receipt: /private/tmp/current-9546-preview-preparation/TERMINAL-PREVIEW-PAIR-QUALIFICATION.json, SHA25692faae84c89e9e37e23129b6a5cd18580ed1c09517db91286afdf1445e3b5c6f.
Before merge, actual master advances to875943ac83e730fd4cfbe1e1860b3f4d7bf0ac78 and GitHub reports five content conflicts. Ordinary reconciliation preserves the Codex shared exports, flag-free Codex runtime, unified harness picker/display and incoming Grok Bot exports, three-flag admission, dedicated connection and Execution/Usage summary. The shared display helper additionally preserves Grok Bot branding; it must not label that existing external provider as Paperclip Runner. Seven narrow controls extend the existing display, mounted configuration and runtime-selection suites. An initial new test expected a saved connection section from an unsaved fixture; it is corrected to the existing save-first guidance without changing production behavior. Required maps now align35areas/176 capability IDs and direct token gates pass. Incoming shared Rust/backend/protocol bytes and migration0344 are materially different:9546 artifacts/live proof remain literal, and final integrated native/package/DB qualification must be refreshed remotely. No evidence is relabeled as combined-source proof.
The resolved composition passes226 cases across the five existing runtime/display/mounted/selection/heartbeat suites. Direct server and UI no-emit checks pass after JavaScript-only Runner SDK declaration preparation and isolated installation of the exact declared Speko0.0.13 dependency with lifecycle scripts disabled. Initial missing-dependency/stale-declaration diagnostics remain setup limitations; no production workaround or dependency/lockfile change is made. All three existing token checks and staged diff checks pass. Fresh hosted full checks/review and remote native/package qualification remain required.
Current inspectable QA results remain on local3136/3137 with preserved data. The normal board context publishes the sanitized qualification checklist as an attachment-backed primary work product on NPM-3; Done/unassigned status remains and no agent is woken. Canonical PR: https://github.com/paperclipai/paperclip/pull/15683; branch codex/codex-runner-default. Test login/owned target, refreshed reconciled-head gates/artifacts and real Test onboarding/task/file/manual follow-up remain the next action. No timer, merge, production deployment or provisioning-default promotion is performed in this checkpoint.
#### 2026-10-14 current Test deployment and native cleanup failure
Exact published651a passes fresh current-head CI/review and the remote four-platform/package campaign38502151368. Its normal installed Apple Silicon startup, fresh343-migration initialization through0344 and upgrade preservation pass; earlier9546 live evidence remains literal. The immutable preview38503641696 and matching DB/shared bytes pass independent admission. No Codex payload is bundled and no local Docker/Cargo/Rust build occurs.
The human completes customer and separate Fleet Admin sign-in. One fresh customer-owned Test workspace is cold-provisioned, pinned through normal Admin UI and verified after reload. The maintained one-target core-only prepare/deploy succeeds with exact651a app/schema and authenticated serving-source verification, preserving the pin and fleet default. This unsigned branch preview is not the post-merge private Cloud distribution. Its execution image retains the distinct historical signed producer ea6c.
One ordinary Dashboard first-agent Auto Codex API-key Connect records account connection and environment probing on the saved immutable QA target. Native setup then fails before hire: runtime closing exhausts the existing10-second cleanup deadline and authority release remains unconfirmed. The failed payload is delivered after110573ms; HTTP200 is not readiness. No agent, task, follow-up, Legacy switch or unchanged retry occurs. Hello usage, physical cleanup and invoices remain unverified and held. The failure receipt is SHA2561bfce873af81f2424d9ca66dfd64404a21f19e386c3b51e2e0e08cb3f6e37be3. Actual Test acceptance blocks merge despite the scoped code-owner exception.
Read-only forensics reproduces two relevant bounded-close defects through the existing suites: a remote durable-state read can exceed its remaining suspension deadline, and an authenticated WebSocket awaiting peer close acknowledgement can outlive the setup budget. Late suspension proof is already rejected, and authority is retained; the repairs must preserve those protections and require actual physical socket closure before release. These reproductions establish source defects, not the sole cause of the live failure. The retained controller projection and provider request logs contain only permitted metadata; credentials, prompts and provider keys are not extracted.
Next action: complete narrow deadline/physical-close repairs and independent review, retain baseline failures, freeze a new candidate with fresh applicable gates/artifacts, recover only confirmed owned cleanup, and repeat changed-source Test automatic setup/task/checked file/manual follow-up. Then merge the exact ready head under the human's scoped exception and discover/wait for actual npm publication, signed standard image, migrator and private Cloud composition. Production deployment/default promotion remain outside authorization. The original timer stays cancelled and all prior unknown-charge/cleanup holds remain intact.
The narrow repairs now pass source controls and independent review. Four delayed-state baseline failures become15 passing deadline/containment/authority controls, with direct runner runtime TypeScript passing. Ingress's original no-acknowledgement regression fails before repair; a second review reproduces an earlier-error socket escaping active ownership. Final12 controls pass after retaining every owned socket until its physical close, with direct server TypeScript passing. Missing physical-close evidence remains blocked, and the original10-second setup deadline is unchanged. Maps35areas/176IDs and diff checks pass. These JavaScript repairs change neither permission policy nor native Rust; new-head hosted gates and actual Test treatment remain required.
The actual retained Test controller records turn.accepted/started/completed and completed drain/suspend commands. Their stored timestamps are command issuance times, not completion times, so they cannot identify which close stage exhausted the deadline. The internal setup identity differs from the public environment lease; their correlation remains contextual. No hello content, provider invoice or physical deletion is inferred. The local3136 evidence viewer is restored through normal installed651a startup after a current DB-only read-only idle/paused check. All three agent configurations/accounts and ten recorded run identities match its previous651a snapshot. The refreshed primary NPM-3 report is independently downloaded and hash-verified, preserving Done/unassigned status and historical cleanup state. Local3137 and all prior evidence stay unchanged.
@@ -76,6 +76,21 @@ Implementation: `packages/db/src/work-signals.ts`,
`server/src/services/work-scheduler.ts`, `delivery-work-coordinator.ts`, and
`delivery-work-notifications.ts`.
## Routine external-wake contract
Updated: 2026-10-13. Signed Cloud control callers can request the earliest
supported future routine deadline during an owned idle hold. The report binds
its generation to the process, hold and routine/trigger catalog. Cloud must
commit a durable alarm and revalidate the same generation before stopping.
See [idle-sleep safety](../idle-sleep-safety.md#scheduled-routine-wake-protocol).
This is a bounded routine-only slice of external waking. Existing routine
execution, catch-up and local ticking remain unchanged. It does not expose the
whole work scheduler's deadline or migrate other loops. Unknown triggers,
pending work, agent timers, plugin jobs and other unsupported sources remain
sleep blockers. Full provider sleep/wake qualification and fleet enablement
remain open; route and embedded-Postgres tests establish the local contract.
## Using this checklist
Items have stable IDs so they can become separate issues or PRs. All boxes start
@@ -399,6 +414,13 @@ flowchart LR
explicit deep readiness still tests DB health, and signed claim/bootstrap
mutations retain their existing validation and tracking.
Implementation progress: `/api/liveness` reports startup state and the public
commit without auth/session resolution, SQL, or provider I/O. It is mounted
after hostname and signed-bootstrap validation, before standby/auth, and its
exact GET/HEAD route stays reachable without adding a sleep hold. `/api/health`
retains database readiness and signed bootstrap. Callers must opt into the
liveness endpoint; this does not claim all external probes are migrated.
- [ ] **DB-05 — Audit external probes and configured endpoints.** Inspect the
fleet gateway, uptime monitors, deployment checks, DB pool settings, and Neon
suspend configuration. The [ECS example](../../docker/ecs-task-definition.json)
@@ -449,7 +471,20 @@ Longer polling intervals alone do not complete an item.
for both stale-claim expiry and any saved retry time. Startup recovers unfinished
requests. Claim and settlement writes signal in their own short transactions,
with agent wakeup outside those transactions. Empty and terminal queues disarm.
Remaining **1s** maintenance: provider runtimes, Telegram maintenance,
Telegram maintenance now has separate commit-driven discovery and action
workers. Discovery restores legacy subscription obligations on startup and
after endpoint or chat-connection configuration commits, without recurring
empty scans. Startup walks keyset pages with at most 100 endpoints per run,
so endpoints beyond the first page remain discoverable. Configuration commits
carry connection hints through outer settlement and uncertainty recovery;
they only revisit the changed connection. Failed discovery retains its page,
and concurrent edits queue a fresh scoped pass. Existing action rows provide retry and stale-claim
deadlines. Stop-subscription repair parks while the endpoint or connection
is inactive; registration and removal keep their existing eligibility.
The explicit bounded recovery helper remains available. Provider subscription
proof, credential ownership, and idempotent provider mutations stay in the
Telegram service. Provider responses are simulated in the PostgreSQL tests.
Remaining **1s** maintenance: provider runtimes,
run milestone/wake-notice projection, GitHub operation
recovery, and Teams protocol maintenance. GitHub pre-ingress recovery
must still inspect provider history: a lost callback has no local queue row.
@@ -0,0 +1,99 @@
# Speko review qualification — 2026-10-09
Status: experimental. Deterministic checks and real-provider acceptance are separate gates.
## Review stack
- Runtime and task/session authority: PR #15727.
- Production UI and deterministic Storybook fixtures: PR #15728.
- This qualification PR adds integrated tests, protocol proof tools, visual/a11y coverage, and the E01–E16 runbook.
## Current evidence
107 targeted migration, provider, protocol, and session-store tests passed after integrating current master. Fresh installation, pre-Speko upgrade, and repeated migration application passed. Full repository typecheck and build passed on the master-integrated feature before the review repairs. The full local test run hit timeouts in workspace snapshot, runtime, runner API, and native-session suites on a heavily loaded host (load average exceeded 80); it was stopped after those failures. This is not a passing full local test result. Latest-head CI must pass independently. The final stack includes runtime 82a96b128d; UI 43be85d01 was fully green before inheriting this test-only fixture change. The final original-feature checkpoint is 720379c17.
Fresh review-repair evidence:
| Gate | Result | Tested source / evidence |
| --- | --- | --- |
| Durable session, authority, reply, question and admission regressions | Passed: 75 tests | Runtime 99fa4a2e85; `/tmp/speko-pr-admission-tests-current.log` |
| UI call recovery, controller and readable history after errors | Passed: 35 tests | UI dadb0f106 plus test-only TypeScript signature correction; `/tmp/speko-pr-ui-history-tests.log` |
| UI typecheck after repairs | Passed | UI 2caea58bad; `/tmp/speko-pr-ui-history-typecheck-final.log` |
| Post-master migration upgrade/replay and heartbeat scheduling/preparation | Passed: 27 tests | Runtime bf1ead3772; `/tmp/speko-pr-post-master-tests.log` |
| Server typecheck after master integration | Passed | Runtime bf1ead3772; `/tmp/speko-pr-post-master-typecheck.log` |
| Heartbeat preparation and communication guidance | Passed: 15 tests | Runtime 174d08bc64; `/tmp/speko-pr-guidance-tests.log` |
| Proof protocol and initial report redaction | Passed: 9 tests | `/tmp/speko-pr-proof-tests.log` |
| Cleanup-failure report redaction | Passed: 2 tests | `/tmp/speko-pr-proof-redaction-final.log` |
| Token gates | Passed | Combined feature review repairs; `/tmp/speko-pr-token-final.log` |
| Storybook build / interaction / accessibility / responsive capture | Passed: 148 stories, 592 checks | Light/dark, 390/1200 width, reduced motion; `/tmp/speko-pr-storybook-checks.log` |
| Added history-error stories and affected pages | Passed: 188 checks | Fresh 150-story build; `/tmp/speko-pr-storybook-affected.log`; two secondary-error stories included |
| Task voice request error/retry and active-control preservation | Passed: 3 regressions, UI typecheck and token gates | UI 845e622b06; `/tmp/speko-pr-task-launcher-tests.log`, `/tmp/speko-pr-task-launcher-typecheck.log`, `/tmp/speko-pr-task-token.log` |
| Bounded notification fetch and request coalescing recovery | Passed: 13 API tests | UI 38057142bb; `/tmp/speko-pr-notification-timeout-tests.log` |
| Multipart answer delivery, ordering and Backlog admission | Passed: 78 persistence tests and server typecheck | Runtime 04a69ea6a; `/tmp/speko-pr-ordered-persistence-final.log`, `/tmp/speko-pr-runtime-exact-final-typecheck.log` |
| Final UI request recovery and footer | Passed: 6 regressions, typecheck, token gates; 2 focus assertions rerun | `/tmp/speko-pr-ui-review-final-tests.log`, `/tmp/speko-pr-ui-review-final-typecheck.log`, `/tmp/speko-pr-ui-review-token-final.log`, `/tmp/speko-pr-incoming-focus-tests.log` |
| Final setup, task launcher and incoming-call recovery stories | Passed: 153-story build, 220 affected checks | UI 43be85d01 with runtime 04a69ea6a; `/tmp/speko-pr-storybook-all-review-final.log`, `/tmp/speko-pr-storybook-all-review-checks.log`; no unrelated baseline updates |
| Authenticated E03/E14 isolation and revocation | Passed: 1 journey | Feature f121270c8; `/tmp/speko-pr-authenticated-final.log` |
| Integrated browser/phone journeys | Two passed; main journey failed in latest retry | `/tmp/speko-pr-integrated-startup-budget-final.log`; initial browser transcript did not retrieve saved answers. Execution and publication success do not supersede the visible delivery failure. Earlier successful portions are historical. |
| Dependency locking | Repository automation | The user explicitly requested no lockfiles. Root locking is managed by the existing refresh-lockfile workflow; standalone proof installation uses --no-package-lock. |
The master-integrated combined source is preserved in feature commit 134d5b67c (origin/master 98e3cec78e); the successful authenticated run used the prior feature commit f121270c8. At that revision Speko migrations were 0323–0329 after master added 0322. Earlier integrated attempts ran the preceding feature commit with the review patches applied. Reports do not promote those runs to exact-head acceptance.
The integrated test exposed a Slack-only communication-guidance join introduced by the master refactor. The runtime repair now delivers connection guidance to Speko and retains Slack-only command hints. The post-master fixture completed the benchmark in 66.9 seconds and saved approved replies; its browser trace showed the last notification GET stayed in flight until the assertion expired. UI 38057142bb adds a ten-second fetch deadline, with an abort-and-next-poll recovery test. A subsequent fresh run retrieved delayed browser answers, resumed work, answered structured questions, recovered across restart and invoked the assigned outbound-call tool; its inbound execution assertion failed because the fixture selected a Backlog task, which the execution gate correctly refused. The fixture now selects a Todo task, and submit_request immediately rejects Backlog work with an actionable message. The next fresh run retrieved browser replies but failed its 60-second restart-evidence assertion; the new app later served both shorter journeys, which passed (`/tmp/speko-pr-integrated-reviewed-final.log`). Restart now uses the same 120-second startup budget as initial fixture boot, retaining the process-ID and recovery assertions. The final fresh retry failed earlier at the initial browser-answer assertion (100 seconds); both shorter journeys passed (`/tmp/speko-pr-integrated-startup-budget-final.log`). Its synthetic runtime persisted two approved replies, but neither was retrieved in the browser. The request trace shows notification requests returning null, followed by a request at 21:45:57 UTC that remained unfinished through failure; the loaded production bundle contains the ten-second fetch deadline. This remains an unresolved integration failure; host contention alone is not a demonstrated cause. No inbound-push or restart qualification is claimed for this attempt. A local 600-second overall budget is used on this contended host; the repository 360-second default remains unchanged. Healthy-provider timing targets remain independently unqualified. A further retry reused the previous provider fixture and failed setup, so it is not acceptance evidence. Temporary test services were shut down without changing the saved user instance.
The new long-answer repair splits provider messages at 16,000 UTF-16 code units without cutting surrogate pairs, persists each part receipt, resumes known rate-limit failures, and blocks polling from replaying an accepted prefix. The 77-test persistence suite initially hit its explicit 30-second database startup hook before any assertions ran on the loaded host. It now uses the repository’s documented embedded-Postgres test startup budget. All 77 tests passed on runtime a7002737b, including multipart rate-limit/restart and unknown-outcome regressions and protection against polling replay of an accepted prefix (`/tmp/speko-pr-multipart-persistence-final.log`). Server typecheck passed (`/tmp/speko-pr-multipart-final-typecheck.log`).
Runtime 04a69ea6a received Greptile 5/5 with no unresolved review threads, and its CI typecheck/build passed. A chat-retry browser shard failed its authorization-denial feedback assertion twice on runtime 04a69ea6a. Runtime 82a96b128d begins that fixture directly on the canonical agent route, preserving authority and visible-error assertions. Its three-repeat local verification was blocked before tests ran by the 120-second server startup timeout (`/tmp/speko-pr-chat-retry-canonical.log`); all ordinary CI checks subsequently passed. UI 43be85d01 passed its ordinary CI tests/build/Canary and received Greptile 5/5; dependency locking follows the existing repository automation. The user explicitly requested that no lockfiles be added.
A real OpenCode/OpenRouter DeepSeek task executed in the configured Daytona sandbox, preserved low_trust_review, ran df -h, and persisted its initial update and final answer. Its 10 GB root overlay had about 9.9 GB available. The ephemeral sandbox cleanup succeeded.
The initial task update took 33.3 seconds, the final answer 44.3 seconds, and run completion 80.5 seconds from task start. These are cold sandbox timings, not speech latency. They do not meet the two-second live acknowledgment target.
## Outstanding failures and unverified behavior
The remote run succeeded but task settlement retained in_progress: its completion claim used bare comment UUIDs as evidence and supplied no durable verification reference. The status arbiter rejected that evidence. This is a runtime completion-evidence issue, not an answer or sandbox startup success.
The original call had ended before that board retry. There was no new voice reply or publication for the retry. Provider push acceptance and spoken playback were not proven. Older publication records belong to the earlier failed call and must not be used to qualify this retry.
Browser voice, inbound telephone, outbound callback, Safari/mobile playback, and 60-second delayed-result delivery need the real-provider acceptance matrix. Test fixtures do not substitute for actual audio. No new phone call, speech input, recording download, or participant audio capture is part of PR preparation.
## Evidence handling
Private call logs, provider account IDs, credentials, and transcripts remain outside these public PRs. The test harness writes new evidence to local report directories. Only consented, redacted results should be shared. Historical development reports are retained in the original feature worktree; they are not current-head proof.
See [the E2E runbook](2026-09-11-speko-voice-e2e-runbook.md) and [the component/story inventory](2026-09-11-speko-storybook-inventory.md). Keep Speko behind the existing experimental chat-connector setting until all supported real-provider journeys pass.
### Final merge preparation
The user authorized merging the feature and explicitly requested no lockfiles. The standalone proof lockfile was removed and its installation instructions updated. The final cleanup repairs preserve reports on failed provider hangup, allow retrying unconfirmed hangup, coalesce concurrent cleanup, and continue media cleanup after failures. Five deterministic cleanup/redaction tests passed. The connected live-browser harness now creates its qualification task in Todo, where submit_request can run. Syntax checks passed; no live calls were placed during merge preparation. Master integration renumbers Speko migrations to 0324–0330 and retains the new GitHub registration migration. Exact-head CI and review are checked before merge.
The final master-integrated runtime c7b00b5988 passed the real embedded-Postgres upgrade/replay test, 42 communication-guidance/provider/protocol tests, database/shared builds, and server typecheck. UI 7c7c2b38c6 passed typecheck, token gates, 26 focused component/connect-policy tests, and the full 154-story Speko Storybook build. All 108 affected approval and conversation interaction/accessibility checks passed in light/dark themes at 390/1200 widths with reduced motion, real microphone access forbidden, and external networking blocked (`/tmp/speko-final-merge-storybook-checks.log`). These deterministic passes do not resolve the separately documented integrated browser-answer retrieval failure or establish live audio acceptance.
The changed approved-call confirmation was visually inspected in both light and dark narrow layouts. No unrelated visual baselines were updated.
### Runtime authority review repairs
Runtime f03a42673 (carried in master-integrated 7e73d5ba21) fixes three new review findings. Both missed-reply collection and publication retry check prior-call receipts for the same caller, endpoint, task, conversation, and publication; a partly accepted or uncertain answer cannot automatically replay on rejoin. Callback preference writes no longer install agent tools: verified connection setup provisions them only after normal agent_config:update authorization. Guest intake clarifications use task comments and submit_request follow-ups; agent-created and system-created protected question waits are rejected for those unverified tasks.
All 83 real-database voice persistence/authority regressions passed (`/tmp/speko-final-review-security-tests-retry.log`); a focused final test also passed for both agent/system question creators (`/tmp/speko-final-guest-native-guard.log`). Server typecheck passed. The first local database attempt skipped all tests after its startup probe failed; that skipped run was not counted as passing. The retry used a successful real embedded-Postgres instance. Fresh exact-head CI/review are required before merging. No provider calls were placed, and no lockfiles were added.
Latest UI review repair: voice start, inspection, and hangup requests now have ten-second deadlines. Production-client/controller regressions prove that a lost start retains its idempotency key across reload, and an uncertain hangup retains the exact call for cleanup retry without reopening media. All 36 focused API/lifecycle/recovery tests, UI typecheck, and token gates passed. No UI component markup or lockfiles changed.
Runtime follow-up review repairs preserve pending questions across reconnect, allow canonical authenticated task-page answers to continue the original voice request, and retain accepted guest tasks in their saved sandbox when future-call settings change. Current permission, credential, isolation, sandbox availability, and company ownership checks remain enforced. All 85 voice persistence tests and server typecheck passed. Five focused native/legacy signed-tool and task-page continuation/authority regressions passed; the other 145 cases were intentionally unselected in that focused run.
Harness review repairs: successful local cleanup operations are tracked individually; failed operations remain retryable and End stays available until local and provider cleanup complete. Eight cleanup/redaction tests pass. Audio cleanup awaits finalized MediaRecorder data and a successful upload; a failed upload retains the recording for retry and keeps End available. Recording finalization and upload have bounded deadlines. No real audio session was run for this repair. The live browser harness attempts provider hangup independently of evidence-write failures. README links now point to the included report and runbook instead of absent historical private reports.
Interrupted setup qualification: safe secret-presence serialization and production-component recovery regressions pass, alongside UI/server typecheck and token gates. The 155-story build and all 32 affected provider-setup interaction/accessibility checks passed across both themes and desktop/mobile widths.
Callback rotation review repair: ownership receipts now bind the provider identity and exact old callback independently from the replacement secret. Legacy receipts use the previous vaulted key and are upgraded before provider changes. Five focused real-database ownership/rotation/uncertain-creation tests and server typecheck passed; current and legacy simultaneous URL/key rotation and foreign callback rejection are covered.
Qualification provenance and media repair: the live browser report reads the assigned agent’s actual adapter type instead of inferring Claude from the scenario name. Synthetic media pump failures are observed immediately, release blocked input, and enter the hangup/evidence finally path. Ten focused cleanup/media/redaction tests pass; this repair placed no live calls.
October 13 review repair: browser evidence saves are serialized, with each report snapshotted when enqueued. Final cleanup evidence waits for any prior save, and a failed periodic write does not prevent the final report. All 20 standalone proof tests passed, including the local HTTP surface; browser-client syntax check passed. No real calls were placed. The UI repairs passed 26 focused controller/launcher tests, UI typecheck, and token gates. Fresh CI and exact-head review are required before merging the repaired heads.
October 13 master reconciliation: all 76 affected Storybook checks passed and narrow-screen captures were inspected. UI master integration retains the generated-catalog policy and adds source-owned Speko capability annotations; 28 map structural tests, 26 focused UI tests, UI typecheck and token gates pass. An unchanged skill-audit deadline test failed once in UI CI, passed on the identical qualification backend and locally, and its single failed-job retry passed. No assertions or deadlines were weakened.
Final October 13 fixture evidence: all 624 Speko Storybook interaction/accessibility checks passed across 156 stories, both themes, 390/1200 widths and reduced motion on UI source 249cbc616a. The subsequent merge adds GitHub server guidance and documentation without changing Speko UI source. Narrow captures were inspected. Report requests now have ten-second abort deadlines, periodic saves cannot build a backlog, and server disk writes remain serialized after an aborted client request. All 21 proof tests passed, including stalled transport followed by a late server write and final evidence preservation. Browser client/server syntax checks passed. Live-call acceptance remains unproven.
October 13 merge handoff: UI #15728 merged at 22d05644f4888ff75c344c471524acf993087338 after 55 passing checks and a fresh 5/5 review with no unresolved findings. Its final source b5684d9a42 passed all 152 affected page/launcher Storybook checks across both themes and narrow/desktop widths; the final build contains 157 Speko stories. Qualification is refreshed against merged master. The visual runner preserves both configurable local ports and the upstream external Storybook base URL override. No provider calls or lockfiles were added.
Hosted Storybook review repair: the Speko request guard permits only the configured Storybook origin, including hosted URLs, and continues to reject unrelated provider requests. A deterministic browser regression serves a synthetic hosted origin without external traffic and verifies navigation/assets succeed while Speko requests are blocked. Hosted-origin isolation and representative local narrow-screen stories pass. Two CI jobs on the prior head were interrupted by runner shutdown signals, without assertion failures; the repair requires fresh current-head CI and review.
@@ -0,0 +1,159 @@
# Chat channel workflow refactor
The user authorized six hours of sustained work starting at 2026-10-13 02:14 UTC,
with a target of fewer than 8,000 lines in `server/src/services/chat-channels.ts`.
The starting commit is `7eaa9cfa9ce04398a5eb0211a86aacaaa01959dd`: 19,153 lines,
762,442 bytes. At kickoff, the preceding ten PRs were reviewed and green, but not yet merged.
The user authorizes publishing and merging reviewed changes to paperclipai/paperclip.
The previous plan prioritized too many small helper cuts. This plan prioritizes
complete workflows, provider ownership, and meaningful reductions per PR. Shared
transactions and admission policy belong in shared workflow modules. Provider
transport, envelope checks, setup, and native interactions belong in provider
folders. Do not put shared code in one provider's folder or use a mutable context
bag to move the entire service unchanged.
| Priority | Responsibility and destination | Estimated net reduction | Contract and state | Risk and verification |
| --- | --- | ---: | --- | --- |
| 1 | Native interaction callbacks and continuation: `interactions/`, `telegram/confirmation-actions.ts`, `discord/question-forms.ts` | 2,900 | Current actor/runtime/destination readers; durable token and interaction transactions; deferred wakeups. | Preserve token replay, audit order, provider acknowledgement, post-commit recovery, and live fault barriers. Existing public service, HTTP and real-database interaction tests before and after. |
| 2 | Endpoint configuration and provider setup: provider `setup.ts`, shared credential persistence/configuration | 1,600–2,200 | Credential lease and current endpoint; provider registration outcome; stable native identity. | Preserve fail-closed persistence, webhook/receiver ownership, partial setup cleanup, and credential rotation races. Existing setup and runtime tests. |
| 3 | Message admission and provider policy: shared intake workflow, GitHub message policy, provider envelope projections | 2,400–3,000 | Delivery claim and conversation/task admission; explicit provider policy results; per-service message provenance. | Preserve row locks, deduplication, author authority, task generations, attachments, and GitHub automatic/explicit admission. Existing real-database ingress and replay tests. |
| 4 | Durable delivery and lifecycle: shared queue, provider lifecycle inputs | 1,700–2,000 | Conversation leases, replay decode, ordered drains, mutation reconciliation; shared live receipt state. | Preserve stale lease exclusion, event order, deletion/edit races, deferred startup and shutdown. Existing concurrency and lifecycle tests. |
| 5 | Outbound publication: provider delivery modules and shared publication worker | 2,700–3,400 | Current-source authorization; exact transport parts; attempts, unknown outcomes, completion receipts and cleanup. | Preserve no duplicate sends, ambiguous acceptance, credential fencing, file recovery, concurrency and current task-control completion. Existing assembled publication and file tests. |
| 6, if needed | Operator recovery and endpoint projections | 800–1,200 | Explicit replay/resolution and company-scoped board calls. | Preserve retry audit, current policy and authorization. Existing operator-resolution integration tests. |
The estimates are not a PR quota. Inspect every full execution path before moving
it. Increase size only where a cohesive responsibility has a narrow contract.
After every reviewed slice, remap the remaining file and report the measured size.
For each slice: run a behavioral baseline before editing production; retain
existing bodies and SQL; compare normalized AST and statement order; run server
typecheck, module boundaries and public-path tests. Review all intentional callback
and dispatch substitutions. Preserve live option reads with getters or callbacks.
Keep per-service state per service and shared cache/lease ownership shared.
Open one PR per cohesive extraction with the full repository template. Verify its
current-head review and all CI gates before opening the next extraction. Build each
on its immediate predecessor. Run repository-wide typecheck, tests and build once
at the final handoff; investigate and disclose any failures or unreached coverage.
The earlier batch recorded local timing/host cleanup failures; green CI and passing
focused retries do not erase that evidence. No timeout or assertion weakening.
Public application fixtures prove assembled service/HTTP/database behavior. They
do not prove live third-party execution. Use only owned fixture data and processes.
## First extraction
The native interaction workflow reduces the service from 19,153 to 16,117 lines
and from 762,442 to 656,146 bytes. Telegram owns confirmation resolution and
settlement. Discord owns correction draft retention and accepted-answer cleanup.
Shared callbacks retain token/source/actor checks and atomic question resolution.
Shared continuation work retains durable wakeup recovery. SDK state persistence
has a direct module import and retains the public compatibility export.
The same 62 public-path interaction cases pass before and after. Seven supporting
suites pass all 70 cases. Server typecheck and module boundaries pass. AST checks
cover nine moved declarations, three provider bodies, and retained service order.
Fault barriers remain live getters. No assertion or timeout changed.
## Second extraction
Endpoint configuration and provider setup reduce the service to 14,241 lines and
580,227 bytes. Shared modules own endpoint records, credential identity/persistence,
and the credential-leased configuration state machine. Channel folders own Telegram
registration, GitHub repair, Speko tool installation, Photon configuration and
inspection, and Slack setup projection. Registration dependencies remain live.
All 1,278 chat cases passed on the first PR before this move. The final setup wiring
passes 268 selected integration cases, server typecheck, and module boundaries.
AST checks cover 25 declarations and nine provider bodies. One final test attempt
could not start PostgreSQL because this Mac exhausted IPC slots; after reclaiming
one unused zero-attachment segment with a dead creator, the same suite passed.
## Third extraction
The publication workflow reduces the service to 11,198 lines and 462,108 bytes.
Authorization, durable preparation, transport, failures, attempt ownership, task
control completion, and bounded endpoint scheduling now have named modules.
Photon owns prompt and reply delivery. Discord and Telegram own durable Markdown
attachment preparation. Shared native splitting remains shared across providers.
The same 301 public-path publication cases pass before and after. Eight supporting
suites pass all 185 cases. Server typecheck, module boundaries, and AST checks pass.
The AST audit covers 26 declarations, three provider bodies, and retained service
order. Shared endpoint lanes and Teams cooldowns retain their original maps;
shutdown and publication wake listeners stay live. Early callback registration
uses typed forwarding functions instead of reading factories before initialization.
## Fourth extraction
Ordered delivery and lifecycle reconciliation reduce the service to 9,287 lines
and 388,734 bytes. The delivery ledger owns ordering and runtime-fence projections.
The conversation queue owns exact leases, reconstruction and ordered replay.
The lifecycle workflow owns edit/delete admission and reconciliation. Teams owns
authenticated route recording. GitHub owns restoration of durable message policy
into the same per-service provenance maps.
The same 225 lifecycle, ordering, lease, replay and recovery cases pass before and
after. Typecheck and module boundaries pass. AST checks cover 26 declarations, the
GitHub restoration body, and retained service order. Live maps and lease hooks retain
their original lifetime. The publication predecessor's packaging retry passed unchanged. This fourth
slice is published as PR #16096.
## Fifth extraction
Inbound authority, envelope preparation, durable admission and resource admission
reduce the service to 7,899 lines and 335,607 bytes. The shared admission module
keeps endpoint locking, runtime and credential fences, gateway lease renewal,
deduplication and delivery insertion in one transaction. Teams, Telegram and
Photon own their destination rules and use that same transaction. The main
message path now calls preparation, durable admission and resource admission
before the retained task workflow.
The same 278 selected public-path cases pass before and after the first move.
All 1,278 existing chat integration cases pass on the final provider dispatch
in 309.47 seconds. Server typecheck and module boundaries pass. One full-suite attempt
could not allocate PostgreSQL shared memory before any test ran. Only a verified
unused 56-byte segment with a dead creator and zero attachments was reclaimed
before retrying. No active database was stopped.
AST checks cover 21 moved declarations, envelope and resource phase bodies,
three provider destination bodies, and the complete admission transaction after
restoring the explicit provider calls. The service still owns the per-call
gateway ownership handoff. The envelope retains its per-call recovery map and
the original authenticated runtime. No assertion or timeout changed.
## Stack landing
The preceding ten PRs reached master through #16058. The five workflow PRs are
#16080, #16085, #16089, #16096 and #16105. Each extraction has individual behavioral
evidence and a 5/5 review. The four child PRs merged into their predecessors after
each combined revision passed its own checks and review. Every consolidation
preserved the tested tip tree exactly.
The final master integration leaves the service at 7,917 lines and 337,195 bytes.
The 18-line increase over the extraction tip preserves upstream execution-default
selection and authorization. Endpoint serialization and credential-leased updates
retain that policy in the extracted endpoint module. Task creation and failed-run
recovery retain their upstream behavior. All 107 extracted declarations match
current master after reversing the documented binding substitutions. The endpoint,
task-creation and recovery functions also pass exact normalized AST comparisons.
Repository-wide typecheck and build pass on this integration. The first full local
test command passed 18,391 server tests and skipped 105, but one unchanged tool-access
test hit its 15-second timeout. That case passed alone. The UI and CLI groups passed
8,706 tests. Shared and adapter groups passed 4,751 tests and skipped 20. A database
group could not initialize one PostgreSQL fixture. This Mac has a 32-segment shared
memory limit and concurrent fixture databases. The unchanged database cases are
being rerun one file at a time before the remaining chat and serialized route lanes.
Keep the original failed runs in the verification record. No assertion or timeout
was changed. The root PR remains open for fresh review and CI against master.
The service now has 67 direct functions. The largest retained paths are message
task handling (1,449 lines), webhook dispatch (685), operator action resolution
(488), and publication resolution (343). Provider setup, transport preparation,
native interactions and destination admission live in their channel folders.
Shared admission, delivery, lifecycle and publication transactions have named
workflow modules. The retained message path calls those phases and keeps task
mutation and per-call ownership together.
@@ -1211,3 +1211,89 @@ The served controller is ad5875fa with the recorded 52486d6b lookup repair and
Full workspace typecheck/tests/build and final packaged acceptance remain
unrun on the reconciled head; they belong to the still pending cloud/full-check
handoff after dependency and local acceptance gates are satisfied.
## Published prerequisite evidence remains separate — 2026-10-13
The source owner reports public canary `2026.1013.0-canary.6` on
`60bc0d5fee9a6e48db08fc016521fee3d9f57d67`, following merged prerequisite
d67e3507. The 60bc object is available locally and its own commit changes only
the release workflow and its verification tests (#16149). This checkpoint does
not merge that later master into the Claude branches or run a new workflow.
The source owner reports four native producers, publication and real onboarding
smoke passing, plus clean Apple Silicon installation and two native Codex task
runs through the supported API. Its fresh staging pair remains separately bound
to literal d67/cloud38392212140-1 and reuses its provider session.
Those are prerequisite/Codex measurements, not qualification of our untested
Claude package. The source owner's published saved-account Connect UI still
uses a Legacy CLI probe that fails on its clean local PATH; its private Codex
#15683 fix remains separate. Its released gpt-5.6-luna costs are unpriced, and
an additional positive-budget control correctly fails closed. Restoring its
budget to default zero changed the configuration revision/session; local same
provider-session reuse is therefore not claimed. Four authorized Codex turns
were used, its QA agents are paused, and physical sandbox teardown/invoices
remain unconfirmed. None of its $25 allowance funds this Claude lane.
Our public heads remain c60bf4b/4440df2/173a73e, with newer reconciled fixes
committed locally. Claude budget-check/retry approval is still pending; no new
paid check, retry, hold release, foreign process cleanup or borrowed environment
was performed. Current-source broad checks, final packages, local useful-task
and revision proof and fresh PR review remain gates. The old source merge timer
was canceled by its human; this chat has no authority to recreate it or promote
production defaults.
## Actual Codex merge composition — 2026-10-14
Codex #15683 merged as `adb69e8f09852c772d9901ae270e5b2d66e39c77`.
Fetched that exact object using the existing repository authentication. The
original /Users/dotta/.codex/worktrees/670b/paperclip checkout no longer exists,
but its committed behavior branch is intact at f4b24bf695. App-managed recovery
reported Not a git repository, so the same branch was recovered into the isolated
/private/tmp/claude-runner-default-recovery worktree. No source-owner branch,
preview or allowance was changed.
Protocol composition `9ac6e674fa` retains the actual merged Codex implementation,
including shared bounded suspension reads and ingress shutdown. Its shared server
executor is byte-identical to adb69; transport differences are Claude effort
fields/admission only. The v7 input reader retains v1–v6, including Dot and Grok
Bot bindings. The merged Grok Bot gates remain intact in Claude behavior.
Copilot profile 18 already belongs to merged Grok schema evidence, so the combined
Claude source extension uses pending profile 19, preserving that immutable v18
and the earlier private Claude v18 under a separate fixture name. Pi25 retains
its previous digest; no provider qualification boundary is promoted.
Protocol checks pass 326 controls with one existing distribution-root fixture skip,
plus runner noemit, schema/profile/manifest generation and map contracts. These
are JavaScript/fake-provider checks, not new native package or live proof.
Cached dependencies were restored into isolated copies after the old absolute
workspace links became dangling. A frozen install stopped on the inherited
manifest/lock mismatch; a separate pnpm version query refused an unverifiable
registry fetch. No signature guard or patch policy was bypassed. The existing
installed dependency lock identity is retained in
/private/tmp/claude-adb69-dependency-recovery/receipt.json. Newly merged Speko and
OpenTelemetry packages were installed at their manifest-pinned versions into a
private prefix with npm lifecycle scripts disabled. Canonical shared/plugin SDK,
eval-kernel and runner JavaScript outputs were prepared without Docker or Rust.
Fresh full dependency/source checks still belong to current-head hosted CI.
The defaults composition retains Codex onboarding draft recovery and its
explicit-Connect probe handling. A combined test exposed an inherited reset that
started another setup probe when measured discovery changed; restoring merged
navigation ownership fixes all 39 targeted managed Code/Claude controls. A
separate stale Claude target control now requires an explicit Connect action
before a second test: obsolete results cannot hire, and environment updates do
not automatically spend another setup turn. Native/Legacy configuration and
saved-account assertions remain intact.
The actual merged Storybook uses source annotations and generated indexes, so
its deleted old maps/storybook-map files are not revived. The canonical Codex
story location and stable identity are retained. The current catalog generator
passes 283 files/2,727 stories; map contracts pass 35 areas/176 capabilities.
UI/server typechecks and token gates pass. Final focused settings/creation checks
cover 577 controls across their recorded runs, and all 31 native input-builder
controls pass. Logs use /private/tmp/claude-adb69-* prefixes. No new rendering,
paid model turn, budget read/resume, hold release or local native build ran.
The local preview remains its separately recorded older treatment; this source
composition is not a claim of current installed/runtime or task/revision proof.
@@ -0,0 +1,201 @@
# Project repository skills
## Finish line
Deliver automatic imports and five-minute refresh, project-derived visibility,
latest-version execution with immutable execution snapshots, legacy adoption,
production UI and Storybook coverage. Completion requires passing repository
checks, a live GitHub-to-routine update journey and a reviewable PR with evidence.
## Decisions
- Track the configured project branch, defaulting to GitHub's default branch.
- Import future skills unless excluded. Existing manually imported sources keep selections.
- Refresh using the setup person's existing authorized GitHub connection.
- Access through any originating project is sufficient; evaluate current project ACLs.
- Retain installed versions and project provenance after detach or upstream removal.
- New executions use latest installed versions; resumed executions keep their snapshot.
- Legacy projects adopt explicitly. Existing imported sources update automatically.
- Advanced reference pin UI and GitHub push webhooks are deferred.
## Current qualification — 2026-10-13 UTC
Implementation and live acceptance passed, including upstream updates, private
access/recovery matrices, eleven rebuilt browser journeys, responsive inspection
and a final real v2 execution after master reconciliation. All standard local test
phases completed across documented retries. The final safe-fallback correction
passed 89 pinned Node 24 cases and server typecheck/build. Project fallback retains
shared dependencies, permits safe package updates and restores complete packaging
when the repository fits. Final review/check results and authorized merge state
are recorded on PR #16066; only its exact green head may be merged.
GitHub CLI authentication was restored by the user. Local and browser-published
histories were reconciled with an unchanged, identical tree. Final-head checks
must pass before merging. Merge is already authorized; no further merge
permission is needed.
The temporary reconciliation checkout and obsolete previews have been stopped
and removed. Final local acceptance data and evidence are retained. See the
[acceptance report](2026-10-12-project-skills-acceptance.md) for current outcomes
and limits. The process notes below are historical and do not supersede this
checkpoint.
## Historical progress
- Repository implementation and verification paths inspected; worktree started clean.
- Persistence, attachment jobs, background checks, manual refresh, project access, runtime snapshots and Sources UI implemented; integration review remains.
- Initial preview migration was `0336_lovely_bloodstorm.sql`; master reconciliation replaces preview migrations with replay-safe generated `0341_abnormal_bucky.sql`.
- Focused source persistence tests passed (13 existing cases); new project source tests passed (3 lifecycle/access cases).
- Source API/UI regression tests passed: 69 tests. Runtime-skill regression suite also passed.
- UI/server direct TypeScript checks passed after building workspace dependencies; repeat after latest changes.
- Token gates passed. Storybook build passed.
- Storybook Playwright journeys passed: legacy adoption/navigation, automatic additions, failure/retry, preference keyboard behavior and mobile overflow (5 tests).
- Manual Sources review completed in IAB; fixed cramped intermediate-width action layout. Project creation and routine Storybook walkthroughs remain.
- GitHub account `cryppadotta` authenticated. Claude and Codex CLI sessions authenticated; no model API key in environment. Live test must use an authorized existing CLI session or connection.
- Live GitHub acceptance, expanded permission/worker/runtime coverage, required full checks and PR handoff have not run.
## Current process/evidence pointers
- Branch: `codex/project-repository-skills`; checkout `/Users/dotta/.codex/worktrees/4631/paperclip`.
- Owned Storybook: `http://127.0.0.1:6187`, exec session 14926. Port 6007 belongs to another process and was not changed.
- IAB tab 1 shows the full Sources journey; browser binding 4. Preserve/reuse the binding when continuing.
- Runner dependency build completed; exec session 59507 was its build handle.
- Logs in `/private/tmp/project-skills-*.log`; browser screenshots under `tests/storybook-visual/test-results/` (ignored).
- Full feature remains the finish line. Next: expand authorization/runtime tests, inspect project/routine journeys, launch isolated live instance and complete GitHub update execution acceptance.
## Verification
Source/worker lifecycle and failure tests; authenticated human/agent access matrix;
runtime latest/resume tests; Storybook browser journeys and responsive review;
live disposable GitHub repository and supported runner; token/map gates, Storybook
build, recursive typecheck, Vitest and production build. Record actual results here.
## Live acceptance progress (2026-10-12)
- Created the project and attached the disposable private GitHub repository through
the production browser UI. The worker imported `acceptance-marker` without an
import action. No agent assignment was added automatically.
- Created a routine through the UI with a stable skill mention. The real
`codex_local` runner (`gpt-6.1-sol`, existing ChatGPT CLI login) completed it and
wrote the exact first marker from the installed skill reference file.
- Pushed an updated marker and a new skill. The production worker imported both
at 23:21:03 UTC, without Refresh, about five minutes after initial import.
- Ran the unchanged routine through the UI again. The runner wrote the exact
updated marker. The first successful run retained version
`1ccdfa45-4a82-44ad-96cb-9ffa6e20fc64`; the second selected
`2bd9801c-1b96-417b-b081-2867e65afdcf`.
- A real agent bearer key could not list/read the private skill before project
membership (404), and could after membership (200). Removing membership revoked
access. Granting membership through a second private project restored access;
its source response exposed only that accessible project's name. Both projects
reused one source and the original skill identity.
- Restarted the owned instance with its retained data and latest source changes.
Doctor passed for PID 40476 at `http://127.0.0.1:3110`; source links, installed
skill identities and selections persisted.
- Manual refresh succeeded. Disabling the disposable GitHub connection produced
a clear source error while retaining both installed skills. The connection was
restored; the browser connection-repair journey is in progress.
- Initial provider setup attempted an unsupported model (`gpt-5.4`); corrected
the disposable agent to the supported model before claiming live execution.
Agent provisioning was an API fixture. Project/routine creation and execution
used the real UI. No synthetic model response was used.
Evidence directory: `/private/tmp/paperclip-project-skills-proof-BGunNG`.
Non-secret records include `fixture.json`, `execution-v1.json`,
`execution-v2.json`, marker files, `automatic-update.json`,
`private-agent-access.json`, `private-union-access.json`, `connection-failure.json`
and `execution-v2.jpg`. The separate test key file is credential material and must
not be published or attached.
## Latest verification and remaining work
- Live legacy adoption reused the existing source and skill IDs. Listing the older
repository did not import it. The real Sources action performed adoption.
- Seeded disposable human identities and real bearer authentication passed direct
skill/file/version/source checks. Access through either project worked. Removing
membership revoked access. Agent responsible-user mismatch failed closed.
This is API identity proof, not a multi-person browser sign-in test.
- Linking the repository through an open legacy project made its skills visible.
Changing that project to private revoked access for the unrelated company member.
- Real UI connection repair persisted after reload and kept installed selections.
- Current instance restarted at http://127.0.0.1:3109 (owned PID 73371). Startup
applied migration 0337. Doctor passed. The unchanged routine produced the exact
v2 marker again in successful run f003baa3-37d7-4203-bd4d-a0c4b45171ca.
Its snapshot includes four selected immutable versions and excludes the new,
unassigned project skill. Older execution version evidence remains unchanged.
- Recursive typecheck, production build, Storybook build, maps and token gates
passed. Six browser journeys passed against built Storybook (no retries).
- Latest focused server/UI check passed 94 tests. Worker/startup check passed 44.
The isolated recovery test passed. A GitHub review fixture was corrected to admit
a new event before checking changed configuration; that focused test passed.
- Full suite is running in exec session 45645, log
/private/tmp/project-skills-final-full-suite.log. Observe this exact handle.
- Manual mobile review found cramped provenance names. Source headings now use
the full narrow-screen width, with actions below. Token/UI checks are rerunning.
Desktop, intermediate and mobile real-app light captures and mobile dark capture
are in the evidence directory. Finish both-theme Storybook and recovery-dialog
review before final handoff.
- Still required: final full-suite result, remaining requirements audit, final UI
build/browser verification, sanitized inspectable acceptance report, commits,
rebase and template-compliant PR/review handoff.
- Owned current server session 94907; development Storybook 14926; built static
Storybook 34961 (6188). Preserve ownership and use the stop helper for cleanup.
## Rebased checkpoint — 2026-10-12
- Implementation is in four logical commits on `codex/project-repository-skills`,
rebased onto master `4b958ecbd8`. Current committed head is `afc5f22a0c`.
- Master added the downstream Storybook catalog. The new suites now live in the
Skills feature home, with explicit stable IDs preserving every existing URL.
Shared simulation lives in `ui/storybook/support/projectRepositorySkills.ts`.
Catalog structural checks passed (225 files / 2,235 stories) and nine catalog
tests passed. Existing source dependency records preserve their classifications.
- Post-rebase recursive typecheck, production build, Storybook build, map/token
gates and all six built-browser journeys passed. No Linux visual baseline was
compared or updated.
- The earlier full-suite process was stopped before rebase. The authoritative
post-rebase full suite is exec session 12928, log
`/private/tmp/project-skills-rebased-full-suite.log`. It is live; do not restart
it because output is quiet.
- The owned instance restarted at `http://127.0.0.1:3110`, PID 71855, server
session 62515, and Doctor proved committed head `afc5f22a0c` with ready UI/API.
Its retained source, skill identities, routine and execution history persisted.
- Manual mobile connection repair passed via keyboard. A missing focus return
was observed after saving; the UI now returns to the source actions button.
Its eleven focused UI tests and UI typecheck passed. The updated Storybook
build is session 73545 and must be followed by the browser focus assertion.
- Keep the full objective active. Still required: final suite result, complete
requirements audit, remaining theme/state review, acceptance evidence handoff,
template-compliant PR and review/check loops. No PR has been opened yet.
## Review fixes and evidence checkpoint
- PR #16066 is open in draft and attached to the Codex task. Initial CI passed;
Greptile requested fixes for API-key repository creation, default-branch tracking,
local file version freshness, and missing screenshots.
- API-key agents can attach repositories without an authenticated run. Their jobs
retain no invented setup person. Default-branch bindings preserve HEAD, separate
from fixed branches. Fresh unpinned local executions capture changed installed
files; resumed/pinned executions keep their immutable selections.
- A local-import path was proved to discard private snapshot provenance. It now
rejects known private snapshots/materialized copies as company-wide imports,
with an opaque not-found response for unauthorized readers.
- All 27 focused source/runtime tests passed after these fixes. Six browser cases
passed with real emulated touch taps, keyboard controls and repair focus return.
- The first post-rebase full run finished: 17,961 passed, six failed. Two failures
used pre-review module implementations alongside added tests. Four other cases
timed out or lost an HTTP/database connection and are being rerun in isolation.
Final qualification must use a fresh full run on the frozen reviewed code.
- The approved initial Storybook preview published through the existing CODEOWNER
workflow. Its immutable build is 38329548539-1 for commit 3e82dada92. Publish the
reviewed head before handoff. Acceptance screenshots and minimized execution
receipts are now in ui/storybook/public/project-skills-evidence/ for the existing
Storybook artifact workflow. No credential or identity key files are included.
## Reconciliation checkpoint — 2026-10-12 evening
Master integration preserves the durable task-workspace changes alongside project skill authorization and execution snapshots. The regenerated migration follows master's 0338 and its real database replay regression passed. Recursive typecheck and production build passed in the temporary reconciliation worktree. Ten focused Storybook journeys passed, including project creation, second repository attachment and immutable simulated routine revisions. Final built-artifact checks, full-suite qualification, updated PR review and a current implementation acceptance run remain.
The reviewed-head full run ended with 17,687 tests passing, two failing, 383 skipped and 18 failed files. Database startup errors identify host shared-memory exhaustion; public MCP also timed out. This is a failed run, not completion evidence. The owned acceptance server was stopped after recording successful reviewed-head run e2cbfc2b-aa07-4fa0-b240-82033d6d1035, and its data/evidence remain available.
The user authorized merging once final PR checks pass. Do not merge an incomplete or conflicting head.
@@ -0,0 +1,517 @@
# Project repository skills: acceptance evidence
Live GitHub updates, immutable routine executions, access/recovery checks,
production-component browser journeys, and manual responsive review passed.
Local standard test phases were completed across documented environment retries.
Final review/check results and merge state are recorded on PR #16066; merge is
gated on its exact head. This report separates real outcomes from test fixtures.
## Environment and artifacts
Implementation checkout: `~/.codex/worktrees/4631/paperclip`, branch
`codex/project-repository-skills`, PR [#16066](https://github.com/paperclipai/paperclip/pull/16066).
The isolated instance uses embedded PostgreSQL and a retained disposable data
directory outside the checkout. Doctor verified the served source revision and
loopback port ownership before the live journeys. No production company data was
used. The test GitHub repository is private and contains only generated skill
fixtures. The supported live adapter is `codex_local`, using model `gpt-6.1-sol`
through the existing authenticated Codex subscription.
The tracked [evidence bundle](../../ui/storybook/public/project-skills-evidence/)
contains the original four captures and a final post-reconciliation capture and an explicit, minimized
[version receipt](../../ui/storybook/public/project-skills-evidence/versions.json).
It is included in the existing Storybook build artifact and branch publication.
Credential files, full provider logs, human authentication keys, and connection
secrets are excluded. This direct Codex task has no driving Paperclip issue or
injected artifact-upload context; the PR and Storybook artifact provide the
review access path.
## Live GitHub → import → execution
1. Provisioned an empty company, one authorized GitHub connection and a supported
test agent through normal APIs. This is fixture setup, not onboarding proof.
2. Created a project and attached its repository through the real board UI.
The background worker imported `acceptance-marker` without a second skills
setup step. Import did not assign the skill to every agent.
3. Created a routine through the real UI and selected the stable slash mention.
The runner read the installed skill and reference, then wrote the exact
`project-skill-v1` marker in the task workspace.
4. Pushed a changed skill and a new skill to the configured branch. The production
worker imported both at **23:21:03 UTC**, without Refresh, about five minutes
after initial import.
5. Ran the unchanged routine through the UI again. The runner wrote the exact
`project-skill-v2` marker. The earlier execution still identified its original
immutable version.
6. Restarted the owned instance with retained data. A further real execution
succeeded with v2. Its snapshot contained only four delivered immutable
versions; the newly imported, unassigned skill was absent.
| Execution | Immutable project skill version | Exact output |
| --- | --- | --- |
| `2db73573-eeaf-420e-aad8-898a87377342` | `1ccdfa45-4a82-44ad-96cb-9ffa6e20fc64` | `project-skill-v1` |
| `ae685356-02a9-4369-9bb3-b76bb112bcce` | `2bd9801c-1b96-417b-b081-2867e65afdcf` | `project-skill-v2` |
| `f003baa3-37d7-4203-bd4d-a0c4b45171ca` | `2bd9801c-1b96-417b-b081-2867e65afdcf` | `project-skill-v2` |
| `e2cbfc2b-aa07-4fa0-b240-82033d6d1035` | `2bd9801c-1b96-417b-b081-2867e65afdcf` | `project-skill-v2` |
| `b91818ac-9e9a-4a98-bd6b-63c0a58e4a1a` | `2bd9801c-1b96-417b-b081-2867e65afdcf` | `project-skill-v2` |
| `83f6f277-5a4a-4814-ba55-8a7ed4a517e1` | `2bd9801c-1b96-417b-b081-2867e65afdcf` | `project-skill-v2` |
The earlier reviewed real execution passed on implementation
`614a2d1d72892128c7fc949d2485308756e7c687`. It delivered four selected immutable
versions, excluded the unassigned addition, and preserved the first run's v1
snapshot. The uploaded output was exactly 17 bytes, with the v2 SHA-256 hash in
the receipt. The model was `gpt-6.1-sol`; its successful heartbeat execution is
`b91818ac-9e9a-4a98-bd6b-63c0a58e4a1a`.
After master reconciliation, another real execution passed on
`cea9e474ba462ed9385ce2f8acb58c245585b310`. The unchanged routine completed
through the real API and supported runner; the completed task was inspected in
the browser. It wrote a fresh 17-byte workspace file matching v2 exactly, delivered
the same four immutable versions, and left the original execution on v1. Startup
checked the unchanged upstream source successfully at 11:45:25 UTC. This output
is a verified workspace file; the earlier reviewed execution also proved upload.
The new receipt and capture distinguish those two evidence paths.
Initial upstream commit: `d7e95f01903678531981ce684e721191ecb0a7da`.
Updated upstream commit: `f4b35ea0082150bda320cda7b3c0777d263bf430`.
The marker files and their SHA-256 hashes are in the receipt. These runs used
real model responses. An initial unsupported model selection failed; the agent
was corrected to the supported model before recording successful execution.
## Recovery, adoption, and access
- **Manual refresh:** the real Sources action completed without replacing skill
identities or selections.
- **Connection failure:** disabling the disposable connection produced an
actionable source error while retaining both installed skills. Re-enabling it
and saving an authorized connection through the real repair dialog recovered
updates. Reload preserved the result.
- **Legacy adoption:** an existing workspace was seeded without a binding to
represent pre-feature data. Listing it did not import anything. The real
**Import skills** action reused the existing repository source and skill IDs.
- **Private agent access:** a real bearer key could not list/read the private
skill before project membership. Membership granted access; removal revoked
it. Membership in another qualifying private project restored access.
- **Human access:** separate disposable users and real hashed bearer credentials
passed skill, file, version, and source reads only through their qualifying
projects. Responses omitted inaccessible project names. An unrelated company
member received not-found responses. Revocation took effect on subsequent reads.
- **Responsible person:** an agent with project access could not read on behalf
of an unrelated person. The same agent could read on behalf of an authorized
project member.
- **Open/private transition:** linking through an open project made the shared
source visible. Changing that project to private revoked the unrelated
company member's access.
The multi-person evidence uses seeded identities followed by production bearer
middleware and APIs. It does not claim separate browser sign-in journeys. The
private GitHub repository requires the authorized owner's access for inspection.
## Automated proof
The final focused project-source suite passed **12 cases**. The source and runtime
suites passed **16 cases**. The replay-safe migration regression passed with a real
embedded database, retaining installed content, private provenance, scheduling,
and setup identities when renumbered SQL runs again.
The service and authorization suites cover transactional enqueue/rollback,
legacy edits without adoption, empty repositories, unchanged commits, additions,
exclusions, invalid siblings, source deduplication, ref changes, detach/delete,
lease competition/expiry, restart recovery, graceful shutdown, backoff/rate limits,
revoked setup access, and explicit connection repair. They also cover private
reads, forks and publication, responsible-person restrictions, immutable resume,
explicit pins, inaccessible references, and fresh local file snapshots. Known
project-derived local snapshots/materialized copies cannot become company-wide
imports. Default-branch HEAD and explicit branches retain distinct identities.
OAuth expiry and larger failure matrices use deterministic provider boundaries;
no live OAuth-expiry claim is made.
**Eleven browser journeys passed against the built Storybook artifact** on the
final implementation. They cover automatic import after project creation and
second repository attachment, empty-source guidance, legacy adoption/navigation,
background additions, refresh failure/retry, keyboard preferences, mobile touch,
connection repair/focus, repair after a concurrent update, and latest routine
execution with immutable earlier versions. Stories mount shipped pages and
components with simulated provider/import/execution data; they do not replace
the live acceptance above.
Recursive typecheck, production build, Storybook build, token gates, map checks,
and catalog checks passed after master reconciliation. The final fallback follow-up
also passed server typecheck/build and **89 pinned Node 24 cases**: scanner/source,
project worker, and both workspace authorization suites. Eleven built-browser
journeys passed again after master reconciliation. The signoff retry passed ten
browser/API cases across two runs.
The standard `pnpm test:run` phases on source d8ab984 were completed across retries:
| Phase | Passed files | Passed cases |
| --- | ---: | ---: |
| General server | 900 | 18,429 |
| UI | 729 | 8,181 |
| CLI | 66 | 527 |
| Shared | 89 | 908 |
| Skills catalog | 5 | 20 |
| Adapter utilities | 73 | 1,736 |
| Other workspaces | 130 | 2,079 |
| Database | 51 | 194 |
| Serialized server | 158 | 3,113 |
This is complete phase coverage, not a claim that one uninterrupted monolithic
command exited zero. The serialized run passed 156 files, then hit a 15-second
route-test timeout; the failed file and the last unrun file passed all 21 cases in
isolation. The final five-suite run passed all 89 cases on source
`40bafbb7a2f7753ac48765081bd2583f611cf5f2`, preserving assertions and deadlines.
Full final-head CI covers the reconciled master and subsequent corrections;
its authoritative results are linked from the PR.
GitHub CLI authentication was restored by the user. Earlier browser publication
and local source trees were identical and their histories were reconciled without
content changes. No host credentials or production data were mounted in the Linux
verifier. Review findings were fixed with regressions and resolved through the
[check-pr workflow](../../.agents/skills/check-pr/SKILL.md).
Earlier local full runs failed. macOS runs encountered database startup/hook
failures from shared-memory exhaustion and a public-MCP timeout. The first Linux
setup omitted generated SDK builds; the second lacked standard test utilities
and was stopped after that diagnosis. Those attempts are not passing evidence.
Two pre-existing login tests also assumed an x64 host. Their intended native
and legacy platforms are now explicit, and all 13 login cases passed on ARM64.
The subsequent 2 GB heap run exited unsuccessfully: 18,422 tests passed,
76 skipped, and one worker aborted from JavaScript heap exhaustion in the
existing setup-token route suite. Its 30 cases passed with an explicit 4 GB
heap. With the 4 GB heap, all 900 server files passed: 18,429 tests passed and
76 skipped. The UI group then reported 8179 passed and one failure. The reset
reproduced in isolation; its editor now holds accepted selections until parent
data refreshes. Both focused UI suites passed all 38 cases. Subsequent phase completion and final focused verification are recorded above.
The final Linux run uses Node 24, built workspace dependencies, pinned Rust,
and the standard process, shell, SSH and JSON test tools in an isolated container.
No host credentials or production data are mounted.
The ownership-checked acceptance cleanup passed: runtime, loopback port 3107,
and its embedded database stopped cleanly; disposable data and evidence remain
retained. All owned Storybook previews and the temporary reconciliation checkout
were removed after their captures and verification logs were preserved.
## Experience review and limitations
Manual real-app inspection covered mobile, intermediate and desktop in both
themes. Storybook inspection included long names, validation warnings, empty and
paused sources, retained removed skills, private project unions, and an 80-skill
list. The list had no horizontal overflow and its footer was keyboard reachable.
A cramped provenance layout, missing repair focus return, and blank simulated
routine section were found, fixed and covered by regression journeys.
The final concurrent-repair story also passed manual inspection at 390px in dark
mode. The selected account remained checked after a 409, its error and footer
fit on screen, keyboard retry succeeded, and focus returned to source actions.
The shared task-defaults editor was also inspected after saving on mobile in dark
mode: the acknowledged selection remained visible and Save became disabled.
Sampling does not claim interaction coverage for all **27 new exports**. No Linux
screenshot baseline was compared or updated.
The existing Storybook deployment workflow published commit 5869973 in run
38394544972, including the sixth real execution receipt and final task capture.
Subsequent fallback changes affect server code; shipped UI and story sources remain
identical to this published build:
[review guide](https://github.com/paperclipai/paperclip/blob/586997352198b2dbf025445706762e27d38e6764/ui/storybook/stories/skills/project-repository-skills/README.md),
[project creation](https://d1p6rlowie26tp.cloudfront.net/storybook/branches/codex-project-repository-skills-8ad0b8be51ae75bc/builds/38394544972-1/?path=/story/skills-project-repository-skills-02-journeys--create-project),
[repair retry](https://d1p6rlowie26tp.cloudfront.net/storybook/branches/codex-project-repository-skills-8ad0b8be51ae75bc/builds/38394544972-1/?path=/story/skills-project-repository-skills-02-journeys--repair-conflict).
Published deployment metadata and story IDs were verified over HTTP. The in-app
browser blocked CloudFront navigation, so hands-on inspection used the identical
local built artifact. No browser security warning was bypassed.
## Inspectable captures
Real isolated Sources page:
![Real Sources page](../../ui/storybook/public/project-skills-evidence/sources-desktop.jpg)
Shipped mobile repair dialog with Storybook fixtures:
![Mobile connection repair](../../ui/storybook/public/project-skills-evidence/connection-repair-mobile.jpg)
Real completed routine execution:
![Real routine execution](../../ui/storybook/public/project-skills-evidence/routine-execution-final.jpg)
## Review fixes
Initial-import and scheduled-refresh queries exclude live leases before bounding
batches. A real database regression places ten leased records ahead of eligible
work and verifies import and refresh still proceed. Connection repair derives
its source from the current query and reloads the revision after a conflict while
retaining the chosen account. Runtime-test teardown drains tracked execution
writes before truncation, resolving a reproduced database teardown deadlock.
![Mobile concurrent repair](../../ui/storybook/public/project-skills-evidence/repair-conflict-mobile.jpg)
The final review identified an oversized-repository refresh that could drop shared
dependencies. Repository sources retain installed versions when fallback would omit shared
files; safe self-contained packages can still update. Initial and subsequent project fallback scans reject detected omitted
dependencies. Project sources automatically restore complete packaging when it fits. All 56 scanner
and source-service cases passed, including manual and scheduled oversized refresh,
retained shared/sibling files, unchanged versions, and recovery after size reduction.
The signoff fixture retry also passed ten real browser/API cases across two runs.
Environment retries also preserved the original failures: a telemetry opt-out
variable conflicted with a mocked CLI test; Docker overlay storage affected probe
identity tests; a native temporary mount initially disallowed execution; and an
oversized stream fixture failed under that mount. The normal-storage cases and
all 56 probe cases on an executable native temporary filesystem passed. A later
host rerun used Node 26 and hit database/subprocess timeouts. The pinned Node 24
run passed the unchanged audit deadline, project suites and authorization cases.
No assertions or timeout thresholds were relaxed to obtain these results.
## Final source-removal integration
Integrated master’s keep/delete choice with project provenance. Removed project
sources retain an internal access identity, invalidate refresh and attachment leases,
and stop tracking. Kept copies and forks remain dynamically restricted. Ordinary
reattachment retains removal; explicit adoption restarts tracking. The rebuilt Storybook passes all 13 interactive project-skill browser cases, including
kept-copy access wording and cancelled removal; the Sources UI/API suites pass 21
cases. The initial Linux pass exposed two harness mismatches: source authorization
now precedes request validation, and repository skill instructions use a wrapper.
Both assertions retain their intended contract with corrected fixture setup/file
paths; the final service pass and current PR checks are recorded on PR #16066.
## Final review corrections
The security review’s per-revision approval recommendation conflicts with the
approved automatic/latest behavior. The response records repository-author trust,
per-refresh credential/access/policy revalidation and the manual-update option.
The scanner subsequently passed. Greptile then identified two concrete defects:
legacy adoption without a saved source ID did not restore removed tracking, and
Codex’s reused home could retain a revoked private skill link. The initial correction resolved the removed repository/ref; the final privacy
review superseded reuse with separate active tracking identity, described below. Codex launches against a
home scoped to its permitted immutable inventory, including an empty inventory,
with the selected credential source preserved. Three Codex launch/injection/sync
suites pass 32 cases; final service and real-provider results are recorded on the PR.
Post-review verification passed 212 cases across 13 pinned Node 24 suites,
plus the full typecheck and build. A fresh real ACP routine execution (`PRO-7`,
`95d14fcf-5643-4d5f-9512-d160efcb2446`) delivered four pinned versions and
reported the v2 marker. The CLI probe exposed the host’s old Codex 0.153.4
client: both requested models were rejected before model work. The repository
already pins Codex 0.160.0. With that client and the original `gpt-6.1-sol` model,
`PRO-9` succeeded in run `d94d7009-8787-4483-81e4-71ec0b512ed6`, marked its
task done, and independently verified the existing 17-byte v2 evidence file
without rewriting it. Its invocation used `skill-runtimes/<agent>/<inventory digest>`;
the selected account remained usable. The v1 execution still identified version
`1ccdfa45-4a82-44ad-96cb-9ffa6e20fc64`. Eight successful execution receipts
now distinguish newly written files from provider-reported or preserved outputs.
Failed probes are recorded separately. The disposable agent’s original settings
were restored and the superseded probe task was cancelled.
The live walkthrough also reproduced a withdrawn AI connection request still
showing an active “Fix connection” action after a successful task. A failing
regression test captured it. Withdrawn requests now use the existing terminal
card renderer; 70 interaction/Sources UI/API cases pass. A production-component
Storybook state and a narrow light-theme browser case preserve this recovery state.
The final compatibility review also found provider settings skipped for generated
Codex homes. A launch-level regression failed for both default and explicit
credential homes. Provider settings now apply to generated skill homes while
caller-owned homes remain untouched; the three Codex suites pass 33 cases.
Final qualification passed 213 service/runtime cases on pinned Node 24, 70
interaction/Sources UI/API cases, and 14 rebuilt Storybook browser journeys.
Typecheck, build, token gates, maps and catalog checks passed. The restarted
real app on source `c9a5897bb0843ee5ac89ee0bb9210ca864d6ceca` shows the
withdrawn request as inactive after reload, alongside the completed CLI result.
The updated CLI capture records this corrected recovery state. Final head checks
and merge status remain authoritative on the PR.
The final retained-content privacy correction separates tracking from provenance.
After removal, adoption creates or joins an active source; it never adds readers
to the removed source holding editable copies. Forks capture the originating
project set independently, so later open-project attachments cannot expose private
local edits. Membership, project visibility and deletion remain dynamic. Generated
migration 0341 makes source identity uniqueness apply only to active rows. The
regression matrix covers public re-adoption, direct private file/version denial,
private fork preservation, original-workspace adoption, and membership revocation.
Final qualification of the retained-audience correction (`4f7df5e683`) passed
232 tests across 14 pinned Node 24 suites. One scanner subprocess deadline failed
under concurrent build/install load; the unchanged full batch passed on retry.
The 37 source/privacy cases also passed on macOS. Final typecheck and production
build passed after installing two test dependencies added by concurrent master.
Repository policy leaves lockfile publication to its scheduled refresh bot; no
lockfile change remains in this PR. The rebuilt artifact passes all 14 interactive
browser cases. Maps, token gates and catalog tests pass; the catalog inventories
227 files and 2,252 stories without claiming all were rendered. Application and
preview processes owned by this task were stopped with their evidence retained.
Current-head GitHub checks and review results are recorded on the PR.
The final catalog review found stale immutable versions after installed catalog
bytes changed. A reference-only update regression failed before the fix. New
unpinned executions now compare installed catalog files, as they already did
for local files, without network fetching; unchanged content reuses its version
and pinned resumes preserve the old bytes. The runtime/catalog suites pass all
17 cases. This final correction changes no UI; the published Storybook build
38427815861 pins 6219538f75 and contains all eight successful execution receipts
and the two explicitly classified old-client failures.
A fresh review then identified a removal/import race and stale account selection
in generated Codex homes. Both were reproduced before correction. Final source
linking locks the source before the binding, follows removal's lock order, and
rechecks removal and the binding lease. A losing import retries with independent
tracking; it never adds readers to retained edits. Generated homes now include
the selected subscription account and credential source in their digest. Switching
accounts uses a new home; same-account token refresh keeps the home. The regression
uses a regular credential file to model remote copy-back. The source/Codex suites
pass 71 cases, and recursive typecheck and production build pass. These are
deterministic race and launch tests; they do not claim another live model run.
The final default-account follow-up reproduced a mismatch between host and
company credentials: hashing the host source while seeding the saved company
login could reuse a previous account's generated home. The digest now reads
the same prepared company or explicitly selected home used for seeding. The
default-company switch regression fails before correction and passes afterward.
All 33 Codex launch/injection/sync cases and recursive typecheck pass. The
source-removal correction passed fresh review; final CI/review results remain
recorded on the PR. No extra live-provider result is claimed for this correction.
The final security scan identified API-key imports persisting a responsible user
as unattended refresh authority. Direct imports now share project attachments'
setup resolver: API keys retain attribution without a setup person; authenticated
runs derive the person from the persisted active run. Legacy recovery cannot
restore deliberately absent API-key authority and accepts agent attribution only
with a matching recorded run. With valid membership fixtures, both API-key
regressions fail on the previous route setup and pass after correction. All 101
affected route/source/database cases pass, including scheduled repair and legacy
audit recovery. Recursive typecheck and production build also pass. Current-head
security and CI results are recorded on the PR.
Final master reconciliation includes `da9af6741585aeb439b5d38af398eab841131d6e`.
Master added migration 0339, so the unmerged feature migrations were regenerated
through `pnpm db:generate` as 0340 (project tracking), 0341 (retained source removal)
and 0342 (active-source identity indexes). Their replay-safe SQL preserves installed
content and provenance. Migration numbering/safety and five-snapshot retention
pass. All 151 affected source, authorization, catalog-version and Codex cases
pass across eight suites on the merged checkout, along with recursive typecheck,
production build, maps, catalog and token gates. Inherited budget/secret review
sources retain their prior classifications; no extra provider proof is inferred.
The final merged Storybook build succeeds and all 14 project-skills browser
journeys pass against it. This includes the inherited shell updates; no Linux
visual baseline comparison is claimed. Final publication and current-head PR
gates are recorded on the PR.
CI caught a stale replay-test filename after regeneration. The test now opens
0340_salty_vance_astro.sql; its preservation assertions remain unchanged. The
wider macOS Node 26 database run hit eight unrelated native PostgreSQL deadlines.
The qualified Node 24 rerun passed all 51 database files and all 195 tests, with
no skips or changed deadlines. Its input records e3b107976f plus the one-line
fixture correction and the corrected fixture hash. This supplements the 151
merged service/runtime cases and 14 rebuilt browser journeys. Final PR checks
remain the authoritative merge record.
The last concurrent catalog merge integrates master 252d9b5077. Its background
trace-context and runtime-skill suites pass all 12 cases; recursive typecheck
and build pass. Feature controls and fixtures are unchanged from the 14-case
built-browser qualification. The verification inventory now records 59 remaining
gaps and preserves variable-dialog and production obligations for the partially
covered routine-run journey. Catalog/map checks pass without treating source
classification or test presence as additional execution proof.
The final resource review adds generated migration 0343 and durable automatic
refresh credits: unchanged Git trees require no download, including empty commits;
512 MiB of scan/download allowance refills per hour, with conservative reservations
and refunds for small repositories. Manual Refresh remains available. Initial
imports admit 20 jobs per project and 100 per company; overflow remains durable
and is admitted as capacity frees. Repository attachment requires workspace-write
permission, and skill-import policy is checked before provider reads. Policy denials
stop automatic retries until an explicit repair/adoption. These changes passed
all 61 qualified Node 24 files and 397 tests without skips or deadline changes.
The final PUT-route and legacy-tree-learning follow-up passed all 48 affected
cases; recursive typecheck and production build pass afterward.
The final running checkout (32c5cdc4ee plus the recorded PUT-route/tree-learning
follow-up) also passed isolated runtime doctor. Through the real board UI at
127.0.0.1:3107, a new disposable project was created without repositories, then
the approved private acceptance repository was attached through Configuration.
The saved workspace persisted after reload. Sources showed both skills imported
automatically under the new default-branch source without Refresh or adoption.
The earlier projects track main explicitly, so their existing source and versions
remain independent. The picker warned that another connection could not load;
the selected Acceptance GitHub connection successfully listed and attached the
repository. This is an additional real attachment check, not another model run.
The screenshot is retained in the inspectable evidence gallery.
A later master merge introduced 0340_open_warlock. All unmerged feature schema
changes were regenerated together as 0341_abnormal_bucky through pnpm db:generate,
with the same preview replay safeguards and five newest snapshots. Agent setup
now pins only a GitHub connection/grant already authorized in the persisted active
run identity. Responsibility remains attributable but does not authorize searching
the person's other connections. Missing run selection and legacy agent sources
require an explicit human connection repair before unattended reads.
Final-head 684105f683 passed all 402 qualified Node 24 cases across 62 files
and all 14 rebuilt browser journeys; CI and security also passed. Greptile then
reported a deferred-admission/detach race and stale generated Codex settings.
Both regressions failed before correction. Admission now conditionally updates
only still-pending, capacity-waiting bindings with a workspace. Generated homes
include selected config.toml content in their identity, so edits and removals
reach the launched process without carrying old private inventory. Focused
verification and fresh final-head review are recorded on the PR.
Both final review fixes pass all 54 affected worker/Codex cases, recursive
typecheck and production build. Master c7f4b74111 changed workspace preparation
and its catalog notes; the catalog conflict preserves both sets of stable IDs
and classifications. Its affected workspace tests and final CI/review are
recorded on the PR. No new feature canvas or provider run is inferred from
this source reconciliation.
A subsequent queue review reproduced two database failures: adoption held the
binding while waiting for the company lock, and 100 deferred rows from a full
project hid another project's work. Both regressions fail on the previous head.
Adoption now captures run identity and takes the company queue lock before
source/binding locks, reusing that validated setup while enqueueing. Admission
excludes full projects before its bounded waiting-row selection. Verification
and current-head gates are recorded on the PR.
The final initial-import resource finding is corrected with durable company
credits, reserved before provider work. The failing-download regression observed
five reads before correction instead of the allowed four. New cases cover
worker recreation/refill, small-import refunds and completed large measured
jobs retaining their charge. These are simulated download sizes with real DB
transactions, not new oversized live downloads. Generated migration and final
qualification results are recorded on the PR.
The initial-budget commit passes all 251 qualified Node 24 database/source/setup
cases across 54 files. The final refill review reproduced a backwards timestamp
from interleaved older/newer sweeps. Both initial-import and source-refresh
reservations now clamp time to the persisted budget timestamp. The real database
regression fails before correction and verifies no repeated refill afterward.
Focused final verification and current-head CI/review are recorded on the PR.
Qualified Node 24 reproduced the earlier timestamp assertion failure, then passed
all 57 affected cases on the corrected source with no skips or deadline changes.
The macOS reproduction timed out in native DB setup; its broader attempt hit a
privacy-test deadline. Those failures are retained separately from the qualified
pass. Recursive typecheck and production build pass after the correction.
Final head 0fa7fd008b passed fresh security and Greptile 5/5; tests completed
without failures before another master merge introduced a catalog conflict.
Master 7eea9d8214 moved Storybook metadata into each story and made generated
indexes ignored. The two project-skill suites now carry their existing capability
associations, production/fixture classification and durable limits inline, keeping
all explicit meta IDs and exports. Both feature recipes and master's verification
sections are retained. The deleted aggregate catalog/review ledger stays deleted.
Map/generator validation passes; rebuilt browser and final-head gates are recorded
on the PR. This structural migration is separate from the earlier live receipts.
The final catalog-merge CI attempt lost eight jobs to the same runner shutdown;
the logs show cancellation rather than failed assertions. Greptile separately
reproduced adoption restoring a stale workspace selection. Adoption now shares
the editor's root-provenance/project/workspace lock order, re-reads the selected
repository, rechecks project access and rejects a changed selection before queue
mutations. Its real edit-interleaving regression fails before correction. Final
focused results and fresh CI/review are recorded on the PR.
The stale-adoption correction passes all 61 affected Node 24 cases across four
suites with no skipped tests or changed deadlines. The macOS broader attempt
timed out starting two native databases; it did not establish a code failure.
Recursive typecheck and production build pass. The final rebuilt Storybook
publication 38464595162 pins 60537b0695 and contains all eight live receipts;
the adoption-only correction leaves its controls and fixtures unchanged.
@@ -0,0 +1,175 @@
# Grok Bot production readiness
Status: implementation and qualification in progress. Actual client OAuth and a routine wake with an exact chat acknowledgement are observed. The candidate has local authenticated challenge receipts, real Rust assigned-work/file/finalization tests, and durable proactive-intake tests. Deployed two-way work acceptance remains a release gate.
## Candidate and release contract
The production candidate started at `origin/master` commit `833769ab557255b11dd8f650f43ed7333653f5e4` and incorporates master through `e0f30a4c71` in the managed `codex/grokbot-production` worktree. The complete earlier prototype is preserved in snapshot `e0a8150ca248c1b80c58a7e26c10ccda9951907b`; its October 2 test results are historical, not evidence for this candidate. Reuse its provider-specific work where appropriate. Do not import its old gateway baseline, migration numbers, independent session coordinator, or retired UI entry point wholesale.
Use `.agents/skills/create-external-bot-integration/SKILL.md` and its release, Runner, onboarding, conformance, and deployment references. The user selected an existing staging tenant for acceptance; its hostname and verified stack identity are recorded in the private qualification environment manifest. Cloud permits one company per workspace. The user chose a dedicated synthetic qualification project in the selected existing staging company, and authorized a new Bot because Night Shift’s old web link is unavailable. Use the new Paperclip Qualification Bot and one identifiable app/ingress/Runner candidate. Preserve existing tasks, agents and connections.
| Area | Required release behavior | Evidence / current state |
| --- | --- | --- |
| Bot identity | New Paperclip Qualification Bot for acceptance; one Bot to one Paperclip agent; fixed company, agent, client, resource, authorizer, and binding generation | New Bot and temporary fixed agent grant observed; production provider binding implemented and locally tested; not deployed |
| Entry point | Agents → Invite an external agent → Grok Bot; existing shared invitation, copy-prompt component, role/manager controls, Back and Save & exit | Grok preset, persisted setup and secure credential fields implemented; rendered Storybook journey inspected |
| Setup | Copy a complete prompt, approve scoped OAuth, create a webhook-only routine, copy its desktop URL/key into secure Paperclip fields, watch both checks, Done | No terminal or config edits; account-wide plugin access disclosed |
| Outbound / inbound | Supported routine webhook / authenticated agent-purpose remote MCP | Historical outbound observed September 30; current desktop OAuth, authenticated reads, continued access, revocation and reconnect observed; one current routine wake and exact chat acknowledgement observed; candidate’s authenticated receipt pending in the real client |
| Idle work | Bot starts governed work without a placeholder task or echo assignment; can create/assign an authorized task to its responsible human | First production milestone alongside assigned work |
| Cloud placement | Ordinary managed Rust Runner per admitted assignment, reused across messages/tools; no compute for idle connection/readiness traffic | Must prove shipped Linux artifact, configured environment, lease and cleanup on the selected tenant |
| Native capabilities | Bot retains its relevant native browser/apps/skills; Paperclip permissions govern Paperclip calls | Public-source native-tool case required; no new third-party grant solely for testing |
| Paperclip capabilities | First-party context, identity/people, authorized search/coordination, progress, questions, documents, output files and canonical completion/review | Share native operations, receipts and authority; do not maintain a second broad tool executor |
| File powers | Output artifact publishing through bounded task/assignment grants; input attachment access explicit; Paperclip workspace and shell access deferred | Cannot read Grok's filesystem or inherit file/workspace grants from connection pairing |
| Lifecycle | One active assignment; duplicate/lost-response reconciliation; read-aware follow-ups; durable waits; real restart recovery; stale calls fenced | Require run/session/assignment/controller/lease/process evidence |
| Stop | Revoke Paperclip work authority and future dispatch; account for managed Runner cleanup; remote Grok activity remains unknown | “Stop Paperclip work” and “Open Grok”; no claim of global Bot termination |
| Economics | Recorded budgets gate admission; Grok usage/spend unknown; managed Runner cost separate | Never report zero Grok cost or promise control over its billing |
| Distribution | Experimental private connection on authenticated HTTPS instances and Cloud | Localhost relays, internal Grok APIs and public marketplace distribution remain deferred |
| Qualification bounds | One active Bot assignment; short synthetic tasks; no paid soak; bounded attempts and explicit resource ownership | Start with at most six principal task cases and twenty webhook invocations; inspect ambiguity before another send; pause to review any additional spend or scope |
## Architecture decision
Adapt the merged external-agent Rust Runner lifecycle used by Dot, retaining provider identity as `grok_bot` and preserving `openai_dot` behavior. Grok-specific code owns Bot URL validation, routine secrets, wake dispatch and provider instructions. Shared code owns agent-purpose OAuth/pairing, admission, durable mailbox/operation receipts, authority, canonical completion, finalization and managed recovery.
On Cloud, reasoning remains at Grok while the admitted Rust Runner uses the configured managed execution environment. Do not run the assignment coordinator on the control-plane host as a fallback. Self-hosted local Runner placement follows the existing explicit local configuration. A sandbox containing Runner does not confine Grok's native computer or apps, and does not grant it workspace tools.
Reuse `/mcp/runner` and its agent-purpose issuer where the current protocol supports the fixed Grok binding. Keep personal `/mcp/paperclip` grants separate. Preserve existing Dot tool/API compatibility while adding a truthful Grok/provider-neutral presentation. Extend the actual negotiated backend and artifact capability contract; a TypeScript-only reference driver is not production Runner evidence.
Persist a routine dispatch intent before network activity. Send references, generation and correlation IDs only; retrieve authoritative content over MCP. Store URL/key through company secret storage. Apply public HTTPS/DNS/redirect policy, bounded timeouts and redaction. Authenticated readiness acknowledgement is distinct from HTTP acceptance. Lost or uncertain delivery requires reconciliation and never an automatic second invocation. Do not assume Grok can implement Dot's signed MCP Events subscription protocol.
Persistent agent authorization permits idle contact. Task effects additionally require the admitted current assignment and run/turn; shared checks enforce private-task visibility, responsible-user access, pause, reassignment, current grant, governance and recorded budgets. Use stable operation IDs and argument digests, current generation checks and durable receipts. Do not manufacture a native identity or use a board/person grant to satisfy Runner checks.
Normal comments need the shared read-aware wake protocol: retain the ordinary deferred wake until the active assignment reads that exact comment. Preserve unread comments at completion; consume read comments once. Test input replies, new-session requests and self-authored messages separately. A webhook or inbox acknowledgement alone is not proof that feedback was read.
Use current lease-renewal and durable waiting paths. Distinguish pairing-code, access-token, persistent grant, assignment and dispatch lifetimes. Do not repeat the prototype's arbitrary one-hour work-session expiry as an undisclosed human-input limitation. Expired or revoked authority denies effects; unknown remote work keeps its recovery hold before another assignment.
## Delivery sequence and finish conditions
| Gate | Work and concrete exit condition | Owner / evidence |
| --- | --- | --- |
| P0 — current candidate | Preserve snapshot, start on current master, inspect actual staging serving revision and current Cloud ingress/Runner support; record one credential-free environment manifest | Codex; branch, revisions, public origin, owned resources |
| P1 — provider boundary | Fresh scoped connection, actual Grok read tool, token refresh/reconnect, harmless routine → authenticated MCP challenge; verify tools are callable in Night Shift | Codex + human at required provider consent; real ingress/OAuth/ack receipts, no work task or managed job |
| P2 — governed vertical slice | Assigned task and idle intake both pass through the real Rust Runner and normal finalizer; one task/run/assignment, first-party document saved/read back, no self-dispatch loop | Codex; real provider and actual Rust/DB evidence kept distinct |
| P3 — onboarding and capabilities | Shared invitation Grok preset, supported generated prompt and secure routine setup; persisted Back/Save & exit, automatic safe pending-code renewal, real lifecycle/readiness states, Done; questions, output files and native tools | Codex; existing UI components, Storybook states, real rendered transitions and artifacts |
| P4 — reliability | Duplicate/reordered delivery, ambiguous effects, completion follow-up race, durable input/dependency waits, real controller restart, stale authority, stop and cleanup pass | Codex; compare original run/session/assignment/binding/controller/Runner fingerprint/lease |
| P5 — review candidate | Focused auth/protocol/Runner/UI tests, full required checks, maps/token/Storybook checks and PR review green on one frozen candidate; compatible packaged Runner artifact | Codex; PR template, exact head/checks and immutable artifact digest |
| P6 — deployed acceptance | Selected staging tenant serves candidate app, ingress and ordinary configured managed Runner image; fresh onboarding and both work directions pass without chat nudges or manual repair; cleanup accounted for | Codex; actual qualification Bot campaign, screenshots/private evidence, run/document/artifact links and provider deletion receipts |
The next critical gate is the remainder of P1. Scoped staging prerequisites, a temporary agent grant, the new Bot and its webhook-only qualification routine were explicitly approved. The temporary shared Dot gateway is client interoperability evidence only; it is not a production Grok provider or a passed Runner acceptance test. Keep the endpoint/data alive while the user/Bot tests it, and announce any intentional shutdown with resumption instructions.
## Acceptance campaign
Use the skill's C01–C10 evidence format, one row per candidate/case. Record PASS, FAIL, BLOCKED, UNVERIFIED or NOT_APPLICABLE; list every operator nudge, app reattachment, consent, simulated dependency, manual call and repair.
- **C01 fresh setup:** enter the normal invitation UI; actual read, OAuth renewal/reconnect, routine challenge, fixed identity, Done and refresh persistence. Saved setup, expiry, incorrect routine credentials, outbound-only success and revoked access must remain truthful.
- **C02 assigned useful work:** normal task with a fresh nonce → autonomous acceptance → progress → question/answer → report document and bounded output file → completion/review. Check bytes/hash, revisions, canonical result, disposition and cleanup.
- **C03 idle work:** from no assignment, Night Shift creates governed intake and an authorized task assigned to its responsible human. No placeholder, duplicate task/run or echo wake. Same ID replays before/after completion; changed arguments conflict; admission failure settles visibly.
- **C04 native capability:** use a public synthetic source through Grok's existing browser/native tools and save a useful result. End transport-only test restrictions explicitly. No implication that Paperclip's catalog disables those tools.
- **C05 restart/follow-up:** accept, capture identities, restart the owned controller and prove its identity changed; ordinary comment resumes the same assignment/session/Runner. Test read-before-finish and unread-at-finish races. Simulated recovery is separate evidence.
- **C06 stop/authority:** stop, pause, reassignment, membership loss, grant revocation, refresh replay and stale callbacks deny effects; fence/reconciliation and managed resource cleanup are inspectable. Remote Grok activity remains unknown.
- **Additional protocol cases:** concurrent claims/queues, callback destination policy, mutation response loss, mailbox cursor concurrency, lease renewal, missing completion/checkpoint, artifact corruption/limits and cross-company/private-task access.
- **C07–C10 deployed contracts:** no idle compute, one managed Runner reused per assignment, incompatible artifact rejected before offer, allocation/admission failures settled, real tenant ingress and shipped images validated.
## Validation and release disposition
Reuse `server/src/__tests__/dot-runner.test.ts`, current Runner protocol cases and Product E2E fixtures, adding provider-specific regressions rather than a parallel harness. Read the current eval skills before extending their contracts. Use the actual managed fixture only after inspecting its current cost bounds and `finally` cleanup. Scripted MCP/managed successes do not qualify Grok's tool loading or wake behavior.
Before review-ready handoff run `pnpm -r typecheck`, `pnpm test:run`, `pnpm build`, UI token gates, relevant map checks, Storybook catalog/build and guided browser checks. Do not commit `pnpm-lock.yaml`; current repository policy assigns it to CI. The prototype's old broad-test failures are retained history; they are neither current failures nor a current green aggregate result.
Inspect current private Cloud runbooks and serving versions. Reuse existing tenant `/mcp/runner` routing first; change ingress only for a demonstrated missing route/auth behavior. Keep private Cloud source and qualification secrets out of public plans/PRs. Record the app image, ingress SHA, Runner digest, configured managed environment and resource receipts. A local binary override is not proof of the shipped managed image.
Production ready means one reviewed candidate, required checks green, the named staging deployment and shipped Runner verified, the ordinary C01/C02/C03 journeys witnessed with the approved qualification Bot, required recovery/capability cases passed, and all resources released or intentionally retained with an owner and resume path. Report review-ready, merged, staged and canary-verified independently. Fleet-default enablement and a production-wide rollout require their own explicit authorization.
## Provider sources checked October 13
- [Grok Bot custom connectors, vendor support](https://forum.cursor.com/t/grokbot-custom-connectors/169965/5): a chat request adds a publicly reachable custom MCP server. Actual desktop OAuth and authenticated reads were observed. Continued access beyond the initial token lifetime was observed; token rotation receipts and routine callbacks remain unverified. The separate Grok chat app’s connector documentation does not establish Grok Bot support.
- [Grok Bot routines](https://cursor.com/help/grok-bot/routines): bearer-authenticated JSON POST is documented; HTTP 200 is acceptance, not completion. Missing/ambiguous transport evidence remains uncertain.
- [Grok Bot plugins](https://cursor.com/help/grok-bot/connect-plugins): plugin connections belong to the account and are available across its Bots; installation is not proof of authenticated runtime access.
There is no verified production API in this record for resetting Night Shift's remote memory, stopping all its execution, streaming its full transcript, or reporting its spending. These remain unavailable claims until supported provider evidence says otherwise.
## Current execution record
- The production worktree is on the fetched master baseline above. The old implementation is recoverable from its complete saved snapshot; it has not been represented as upgraded production code.
- Exact Node 24 / pnpm 9 workspace installation succeeded with a frozen lockfile. No lockfile change was made.
- The selected staging stack's Primary host was verified through its signed-in admin detail page. It currently follows fleet releases, so an immutable acceptance candidate will need an explicit per-tenant pin.
- Public agent resource and issuer discovery returned HTTP 503 with “Assistant connections are disabled.” The signed-in tenant UI is usable; network access and provider compatibility have not been blamed for this configuration gate.
- Approved prerequisite overrides were applied to exactly the selected stack. One canary campaign succeeded; desired/applied configuration hashes converged. Agent resource and issuer discovery subsequently returned HTTP 200.
- Cloud’s company-create endpoint rejects tenant-side creation. The user selected a dedicated test project in the existing company. That project was created without repository or third-party app access.
- Night Shift’s original browser URL returned Page not found. At the user’s request, a new Paperclip Qualification Bot was created through the running Grok Bot desktop app. Existing Bots were preserved.
- The actual Bot added a private remote MCP connection through chat and completed OAuth through the current Cursor client. A one-use operator invitation fixed the company and agent in the consent preview; no persistent credentials were copied into chat. Paperclip shows the temporary agent connection as established, and the Bot’s inbox read returned its binding generation and an empty inbox. This was assisted setup, not prompt-only onboarding.
- The temporary protocol agent is labeled Grok Gateway Qualification / Temporary Grok client interoperability test, with the shared Dot provider. Attachment and workspace powers are off. Readiness still requires a verified wake and acknowledgement; no readiness flag or subscription was faked.
- The Bot saved Paperclip MCP Qualification as a webhook-only routine. Its detail row and search result only focused the Routines section during computer use; the documented Bot-generated Webhook URL navigation link opened the fields. Credentials were saved privately, and one guarded routine test returned HTTP 200 and an exact nonce acknowledgement. No real work task, managed job or candidate deployment has been initiated.
- The new candidate’s narrow routine transport uses the existing DNS-pinned public-network guard, closed reference-only payloads, redacted outcomes and single-send behavior. Its transport and existing public-network guard/rebinding regressions pass: 77 tests across three files. Server typecheck also passes. It is now wired into durable dispatch, the shared agent authority/Runner and setup UI. Full repository typecheck, production build, token gates and Storybook build passed before the latest baseline update; final checks and deployed acceptance remain outstanding.
## Updated provider access contract
The current verified client surface is the **Grok Bot desktop app**, signed in with its Cursor account. Do not use the unrelated Grok chat custom-connector UI as a substitute. The observed setup starts with a chat request to add the public MCP URL, followed by an Authorize card and browser OAuth. Record app version and verify the generated prompt against this actual flow before calling setup self-serve. The observed client is Grok Bot 0.70.2, built October 11, on its stable track; its update settings reported up to date.
Do not require a working `grok.com/bot/...` URL for onboarding when the current provider no longer exposes that surface. Bot identification must support its displayed name and a provider-supported link only when available. “Open Grok” needs a supported app handoff or clear desktop instruction; the old dead browser URL is not a recovery action.
The existing Dot readiness contract requires its authenticated MCP Events callback verification. A Grok routine’s HTTP 200 cannot satisfy that contract. The Grok transport must own a distinct routine wake verification, durably acknowledge its challenge through the bound agent grant, and then enter the shared external assignment lifecycle. Preserve Dot’s actual event-subscription checks unchanged.
## Current P1 evidence and remaining gate
| Claim | Observed evidence | Scope / limit |
| --- | --- | --- |
| Fresh custom agent OAuth | Actual Grok Bot Authorize card, current Cursor client consent, fixed company/agent preview, paired connection persisted in Paperclip | Temporary shared gateway; assisted setup; production Grok provider not enabled |
| Callable authenticated tools | Actual inbox response; subsequent capabilities returned the agent name changed only in Paperclip and `ready: false` | Native client response plus persisted binding/configuration; no admitted task |
| Continued authorization | Capabilities call succeeded after the initial 15-minute token lifetime without a new consent step | Supports client renewal; token endpoint/rotation receipt not independently inspected |
| Revocation | Paperclip revoked the temporary connection; real stale inbox attempt returned authentication-required and no data | Current connection boundary only; no task mutation/reassignment test yet |
| Reconnect | Fresh one-use invitation and consent for the same agent; real read returned a replacement binding and empty inbox | Existing plugin reused; old binding revoked; operator-driven test |
| Routine wake | Vendor-confirmed desktop row-click regression; Bot-generated Webhook URL navigation link opened the panel. One guarded invocation returned HTTP 200 and the exact nonce reply | Operator workaround required; chat acknowledgement is not a persisted authenticated nonce receipt in Paperclip. One of twenty permitted webhook calls used |
| Current source checks | Local authenticated MCP challenge, Rust task → document/file → finalization, proactive intake/deduplication, and renewed-session recovery tests pass. Repository typecheck, build, token gates, maps and Storybook build pass | Source candidate is not deployed; complete final suite and candidate-bound real managed acceptance remain required |
Do not promote the temporary shared Dot connection to ready or substitute its event subscription with an unverified Grok webhook. The remaining P1 gate is the candidate’s durable authenticated challenge acknowledgement through the actual Grok client. Assigned work, idle intake, restart and managed cleanup still require real deployed acceptance. Local tests use scripted clients and synthetic storage; they do not count as provider acceptance.
## Current implementation evidence
- Separate `enableGrokBot` gate defaults off. Existing Dot event readiness and person MCP behavior remain distinct.
- Shared Rust external backend identifies `grok_bot_mcp`; session completion does not assert remote termination, transcript streaming or usage accounting. Existing native provider identity guarantees remain required.
- Routine URL/key are one immutable encrypted secret version. Closed reference payloads, DNS-pinned public egress, no redirects, durable single-send intents and authenticated nonce receipts distinguish delivery from reply.
- Recovery holds span old bindings. Inspection cancels uncertain intents and requires re-verification; stop fences session authority before cancellation, without a global Grok stop claim.
- First-party native operations, deferred feedback and proactive admission reuse existing ownership, receipts and finalization. File grants bind current company/agent/assignment/grant and exact bytes; they use existing artifact storage.
- Guided setup and management include resume, fixed consent identity/authorizer, account-wide plugin disclosure, both verification checks, observed contact, queued work and recovery. Pairing codes remain in browser authorization; routine credentials never enter chat instructions.
- The latest upstream fetch advanced beyond the original baseline. Integrate it and regenerate the unshipped migrations before freezing a review candidate. The newer baseline resolves the earlier unrelated Storybook catalog drift; the reconciled catalog passes structural checks, with no new runtime-proof claim.
- Cloud’s current ingress allows the existing agent protocol but needs exact GET/PUT exceptions for bounded file tickets. Extend the current Cloud baseline in isolation and test header stripping and denied adjacent routes. No Cloud primary edits or fleet-default change are authorized or required.
The Grok routine is still a **transport-only qualification** routine. Explicitly replace those test instructions before actual assigned/proactive work; retain Grok’s own authorized native tools. No real client work, Linux managed Runner artifact or deployed candidate has been qualified yet.
## Review and environment changes — 2026-10-13
The app and supporting Cloud ingress candidates are open as draft PRs. The first app review found task-summary privacy, deferred-feedback durability, settled-delivery reconciliation and stale Stop targeting gaps. The corrections use the existing task privacy predicate, keep comment admission independent of routine egress, close notification obligations only on canonical successful finish, and pass the displayed run to Stop. Recovery records distinguish dispatch uncertainty from revoked work; a late reply cannot clear a work-session hold or restore task authority. OpenAPI setup contracts and feature-card ordering are synchronized.
The guided story now uses Night Shift's production task thread, question form and document card with synthetic local callbacks. Incorrect credentials can be replaced from saved setup. This proves UI behavior only.
Cloud master has introduced a separate Test environment for branch experiments. Staging now admits only master-derived app and schema revisions; the previous pre-merge staging harness override is retired. The selected staging tenant remains the authorized destination, but a pre-merge candidate cannot be forced onto it. Candidate testing must either use an explicitly authorized Test workspace/harness or wait for reviewed master changes. Do not change the staging guard or fleet default to bypass this constraint.
## Candidate checks and review corrections
The candidate passes repository typecheck, production build, token gates and the Storybook build. The saved-setup retry and pre-assignment Stop regressions pass. The shared provider descriptor schema accepts Grok and rejects invented native process identity. Copilot's versioned source declaration advances to v18 because that shared schema changes; v17 remains immutable, all pinned source hashes are checked, and Copilot qualification remains pending. Current-head full CI and review remain release gates.
The supporting Cloud ingress candidate passes typecheck, routing smoke and its full suite (3,339 passing, 93 optional skips). Current-head review is 5/5 with no open findings. Neither candidate has been deployed. The actual-client evidence remains one routine HTTP acceptance and matching chat acknowledgement; candidate-side authenticated acknowledgement and the six bounded principal journeys are outstanding.
The next review corrections apply the native deliverable catalog's current work-mode policy to upload-ticket issuance and use. Confirmed rejected deliveries have an explicit operator retry; each retry retains the prior receipt, reserves one idempotent new intent and rechecks binding, grant, routine revision and work-session authority. Unknown or accepted delivery remains single-send. Thread Stop uses the selected run and its agent. Recovery locks all of the agent's current and retired bindings before routine rows. Historical Copilot v17 inputs remain decodable while new launch admission stays pinned to v18.
The focused rendered UI regressions pass (144 tests), as do OpenAPI route coverage (21 tests) and Runner contract/integrity/history checks (82 tests). The current server fixture attempt could not initialize PostgreSQL because the host exhausted its shared-memory slots; no server-test pass is inferred from that attempt. Clean-worker CI must execute the file-policy, rejected-feedback and lock-order regressions before hand-off.
## October 14 setup qualification follow-up
The merged candidate passed source checks and was deployed to the approved staging
workspace. The natural Grok picker and Save & exit recovery were observed there.
The actual Grok desktop client reused its custom MCP plugin and opened the shared
agent authorization flow with its registered Cursor client identity.
Setup stopped before granting access: the masked pairing field lacked a Copy
button, and the pending authorization action still named Dot. Add an explicit
Copy code control through the shared clipboard helper, keep the code masked and
out of setup prompts, and use a provider-neutral approval action. Preserve the
fixed company, agent, authorizing person and permissions preview. Requalify the
rendered copy and authorization path on the deployed follow-up candidate before
running work cases. This is not yet evidence of an authenticated candidate reply
or a completed managed Runner journey.
+58 -35
View File
@@ -114,48 +114,71 @@ agents. The durable event inbox below is separate: acknowledging an event does
not complete required lifecycle work. See [Agent lifecycle](../AGENT-LIFECYCLE.md)
for phase ordering, recovery, and existing-installation limits.
## Durable resource lifecycle inbox
## Durable resource lifecycle delivery
Plugins with `events.subscribe` can read durable, company-scoped resource hooks
through `ctx.events.listLifecycle(companyId, limit?, afterId?)` and acknowledge successful
work with `ctx.events.acknowledgeLifecycle(companyId, eventId)`. Use an existing
plugin job to poll each configured company; the host checks invocation scope and whether
the plugin is ready and enabled for that company. These methods are separate
from the fire-and-forget `ctx.events.on()` bus.
Proactive jobs and timers may read only companies authorized by the plugin's
company configuration. Calls inside a host-issued invocation must match its company.
Declare `resourceLifecycle: ["project"]` (or `["agent", "project"]`) in the
manifest, with `events.subscribe`, and implement `onResourceLifecycle(event)`:
An event has `id`, `companyId`, `resourceType`, `resourceId`, `action`, and
```ts
async onResourceLifecycle(event) {
const config = await ctx.config.get(event.companyId);
if (!config.provider) return { eventId: event.id, status: "deferred" };
const finished = await reconcileCurrentResource(event);
return { eventId: event.id, status: finished ? "acknowledged" : "retry" };
}
```
Core delivers events to ready plugins with a configuration row for that company,
unless the plugin is disabled there. Each invocation has the event's company
scope. The dispatcher wakes after the mutation's outer transaction settles,
on host startup, plugin activation/worker start, and company configuration or
enablement changes. Successful worker `onConfigChanged` completion wakes delivery
again, so a callback that deferred while configuration was still applying is
revisited. Failed scans retain pending work through idle drain. Empty and deferred
queues have no periodic scans. `retry`,
exceptions, invalid results, and unavailable workers leave the event pending and
schedule another attempt after 30 seconds. Other acknowledgments or mutations
do not bypass that event's delay; a host restart may replay it immediately.
`deferred` retains the event without
a retry deadline, useful while waiting for operator configuration. A later wake
revisits deferred events. Acknowledgment immediately exposes subsequent work.
Events contain `id`, `companyId`, `resourceType`, `resourceId`, `action`, and
`createdAt`. Agent actions are `create`, `pause`, `resume`, and `terminate`;
project actions are `create`, `update`, and `archive`. Pending hires produce creation
after approval. Project updates include repository/workspace mutations and restoring
an archived project. Provider cleanup and retention policy belong to the plugin.
project actions are `create`, `update`, `archive`, and `delete`. Pending hires
produce creation after approval. Project updates include repository/workspace
mutations and restoring an archived project. Deletion is recorded in the same
transaction as removal and survives the project row. Earlier deletions cannot
be reconstructed. Provider cleanup and retention policy belong to the plugin.
Reads return at most one pending event per resource (default 50, maximum 100).
Creation is delivered before other events for that resource, even when its
backfilled ID is newer. Remaining events follow ID order. After acknowledging
an event, a later read exposes its successor. A failed
resource remains pending without blocking other resources; process the rest of
the batch independently. Progress is stored per plugin, survives worker restarts,
and is not a global sequence cursor. The delivery migration seeds existing hired
agents and all projects once, including archived projects. Pending hires require
approval; paused and terminated agents retain their current status intents.
This baseline represents current desired state, not reconstructed history.
The baseline includes archive for existing archived projects and update for restored projects whose
journal still ends at archive. Archiving does not authorize provider cleanup.
After that migration, capture stays forward-only; no later journal backfill runs.
backfilled ID is newer. Remaining events follow ID order. Failed or deferred
resources do not block independent resources. Acknowledgments are stored per
plugin, survive worker/host restarts, and are not a global sequence cursor.
The initial journal migration seeds existing hired agents and projects,
including archived projects; this is a desired-state baseline, not history.
Agent lifecycle participation (`onAgentLifecycle`) remains a separate contract:
acknowledging a resource event does not advance an agent lifecycle phase.
Delivery is at least once: concurrent reads or a crash after a provider operation
can repeat an event. Serialize polling and use stable company/event idempotency
keys, then acknowledge only after successful completion. Load current authorized
agent/project/workspace data before acting; the journal contains no configuration
snapshots, repository credentials, or deletion authority. For offline plugin tests,
seed `lifecycleEvents` with `createTestHarness().seed()`.
Delivery is at least once. Re-read current authorized state and make provider
operations idempotent; a worker can finish an external effect and exit before
Core commits its acknowledgment. Content-free events contain no repository
credentials or configuration snapshots. Deleted projects may return `null`.
Use stable resource identifiers and fence delayed provider requests when removing
resources. Neither the callback nor an acknowledgment proves mounts are unused.
Lifecycle polls can page past failed resources using the last returned event id as
`afterId`. Reset `afterId` at the start of every polling sweep: it is a page
cursor, never a persisted high-water mark. This retries failures and includes
transactions that commit later with lower ids.
Delivery uses the same process-local transaction signals as Core's other durable
queues. Startup replays committed work. Independent database writers and separate
active server processes need an explicit ownership/wake protocol; see
[database work signals](../DATABASE.md#transaction-aware-delivery-work-signals).
The existing `ctx.events.listLifecycle(companyId, limit?, afterId?)` and
`acknowledgeLifecycle(companyId, eventId)` remain available for manual consumers.
Do not mix automatic and manual acknowledgment for the same resources. Reads
return one pending event per resource (default 50, maximum 100). `afterId` is a
page cursor, never a durable high-water mark: restart pagination to revisit
failures and transactions that commit later with lower IDs. Offline SDK tests
can seed `lifecycleEvents` with `createTestHarness().seed()`.
## External object reference providers
+20
View File
@@ -36,6 +36,26 @@ See [Project Repository Checkouts](DEVELOPING.md#project-repository-checkouts) f
ignore rules, and reuse behavior. Responsible-user credential rules still apply.
A repository selection never delegates credentials.
Fresh tasks using the default repository workspace can clone the same authorized
remote into a company- and task-scoped source directory when an existing project
checkout contains another task's restricted workspace. The clone uses the run's
Git connection and keeps separate Git metadata. Source access checks still apply
before the task workspace is published. Low-trust review runs cannot use this
persistent clone fallback. This fallback does not copy unpublished
local changes or replace reused workspaces, explicit workspace selections, pinned
branches, or repositories that only exist on the local filesystem.
Configured branch templates must derive the branch from the task identifier, ID,
title, or slug. Literal or task-independent templates retain the source denial,
so a fresh clone cannot replace a selected local branch with a new empty branch.
New implicit Git workspace defaults record their project-source provenance.
An untyped checkout binding from an older task is ambiguous and keeps the denial,
including explicit checkout IDs and inherited parent sources. Admission rechecks
the current binding rather than inferring a default from the selected checkout ID.
Startup validation of these recorded defaults keeps the task's effective workspace
strategy. It does not substitute the agent's shared strategy or grant project writes.
Workspace close and reopen use the recorded isolated source. Both operations
verify its company, task, repository URL, and separate Git storage before use.
## Discovery and setup
The server checks company membership, grant ownership/status, and organization-grant
+32 -5
View File
@@ -16,15 +16,38 @@ a system warning in the task conversation. It remains local run-log data.
The hidden native coordinator writes each validated PRP event to the bound
run's existing event stream before it acknowledges the runner. The row keeps
the PRP `eventType`, source instance, source event ID, source sequence, protocol
schema version, and a SHA-256 digest of the canonical source envelope. Its
schema version, and a SHA-256 digest of the canonical stored envelope. Its
payload is `{ "prpEvent": <canonical PRP event> }`.
Native API tool events omit HTTP request and response bodies from durable history.
This includes serialized provider `contentItems`, legacy HTTP receipts and
`call_api` arguments. Saved receipts retain the operation and call IDs, success
flag, HTTP status and content type when present. The body becomes
`***REDACTED***`, with `apiPayloadRedacted: true` and `apiPayloadSha256`, a SHA-256
digest of the original payload. These digests distinguish duplicate events from
changed payloads; they cannot recover omitted bodies for debugging or replay.
The model receives the original authorized response. Credential-bearing mutation
receipts use encrypted storage separately from this run log.
Checkpoints and completion records apply the same redaction. Completion retries
compare stored and expected payloads through the control-plane port's idempotent
`normalizeReplayPayload` projection, so a saved redacted result can be confirmed
without restoring API bodies. Ports without a projection compare their original
payloads. Repeated redaction preserves the original digest and detects changed
private payloads.
The native runtime passes this projection through backend recovery to the Codex
driver. Recovery compares saved semantic results and turn fingerprints with
provider history through the same representation. A private body change retains
its distinct digest and fails recovery; an unchanged body does not require
restoring its plaintext into the checkpoint.
PostgreSQL JSONB cannot represent NUL (U+0000), which can occur in command
output such as Vite virtual-module paths. The run-event payload column uses a
lossless storage codec for these events: the JSONB projection renders NUL as
the literal `\u0000`, and the reserved `$paperclipRunEventJsonV1` field contains
the original serialized JSON as a doubly escaped string. Ordinary payloads
retain their existing representation. Drizzle reads restore the exact original
retain their existing representation. Drizzle reads restore the exact stored
payload before replay, hash validation, redaction, or API presentation. SQL
queries can still inspect ordinary routing fields in the projection; raw SQL
readers of the whole payload must apply `decodeRunEventPayload`. The column
@@ -297,11 +320,15 @@ section in the Observability contract.
Cancelled runs retain `resultJson.cancellation`: a closed `source` label
(`operator`, `queued_message`, `shutdown`, `provider`, `transport`,
`control_plane`, or `unknown`), whether the stop was expected, the initiator,
reason, and recording time. Recorded stop intent survives adapter completion.
`control_plane`, `controller_lease`, or `unknown`), whether the stop was expected,
the initiator, reason, and recording time. Recorded stop intent survives adapter
completion. `controller_lease` means the host stopped its own legacy adapter
after it lost the durable controller lease; the reason names a closed cause
(`renewal_rejected`, `renewal_deadline`, or `renewal_error`).
The local lifecycle event includes this evidence. Started cancellations without
an expected stop are also reported to Sentry; its cancellation diagnostics contain
only source, expectedness, and initiator type, never initiator IDs or reason text.
only source, expectedness, initiator type, and the closed lease-loss cause, never
initiator IDs or reason text.
Historical ambiguous cancellations stay `unknown` and do not authorize replay.
Provider tool-definition validation failures use
+49 -23
View File
@@ -3,7 +3,7 @@
`search_api` and `call_api` extend the native runner when an available dedicated
operation cannot express the requested work. Use `set_task_monitor` to schedule or clear a one-shot task check; after confirming
the receipt, finish with `yielded` and `continuation.kind: "monitor"` to await that
task’s timer. `call_api` still rejects monitor/execution-policy lifecycle writes.
task’s timer. The monitor workflow remains preferred; REST calls use the same route authorization as legacy agents.
Existing tools remain preferred;
agents do not have to search before using them. Only two tool definitions are
advertised. The API catalog is returned on demand, never injected into the
@@ -28,7 +28,7 @@ preparing any files. Existing dedicated tools remain available. Operators must
update the environment of each server process and restart it for deployment-level
changes; this environment switch is not a live settings API.
All company, run, work-mode, credential, and lifecycle checks below still apply.
All company, run, work-mode, credential, and route authorization checks below still apply.
## Discovery and requests
@@ -64,7 +64,10 @@ inspect its state rather than retrying it to obtain a smaller response.
Connection setup and stalled response reads time out after 30 seconds. An active
capture has a 10-minute total download deadline. Responses above 24 KiB stream
into a private temporary file, then into a company-owned asset. Memory stays
into a private temporary file, then into a company-owned asset scoped to the
issuing agent and responsible user (plus authorized board administrators).
Ordinary task or run visibility does not grant access to another actor’s API
snapshot. Explicit deliverables use the existing attachment/work-product flow. Memory stays
bounded by the inline prefix and stream buffers. Binary responses also become
assets; text previews are limited to 2,000 bytes.
@@ -163,23 +166,25 @@ failed to return a valid response.
The server revalidates the active native run, assigned task and actor, then
creates a server-held agent JWT bound to that company and run. Requests go
through the actual HTTP router with its authorization, validation and domain
audit behavior. An additional `runner.api_called` receipt attributes mutations
audit behavior. Skill-test runs retain the same task-scoped `skill_test` JWT
as legacy REST runs, including after later edits to the task mode. An additional `runner.api_called` receipt attributes mutations
to the run even where older route audit events omit that field.
The run and work mode are checked again after asynchronous file preparation, so
a stopped run cannot dispatch an upload prepared under its earlier binding.
Ask and pre-acceptance Plan permit reads through the escape hatch. Existing
dedicated-tool exceptions are unchanged. Runner-owned checkout, completion,
status/assignment transitions, approval decisions and execution-control actions
cannot be bypassed through generic calls. Routine creation, schedule/trigger
changes and manual/public routine execution require the existing scheduling
clients. Direct workspace runtime commands, runtime-slot stop/restart, case
automation retries and skill test-run controls also require their existing
execution clients. Gateway session credentials cannot enter generic results.
Routine metadata remains readable; annotation threads, comments and thread
resolution remain available through the fallback. API-only ordinary fields, such as a
task's `billingCode`, remain accessible even when a dedicated tool covers other
fields on that endpoint.
`call_api` is an authenticated REST transport, with the same endpoint and payload
permissions as a legacy agent using REST. It does not maintain a second denylist
for routines, runtime services, skill tests, recovery, invitations, secrets,
exports, lifecycle fields or approval routes. Existing HTTP routes enforce their
company/resource scope, ownership, grants, redaction, run requirements and board
or approval gates. A board-only route still denies an agent call. Dedicated tools
remain preferred for common workflows, including native completion and monitors.
Ask and pre-acceptance Plan retain their existing read restrictions and specific
mutation exceptions (task titles and conversational confirmation recording).
Protocol endpoints still require their existing clients. Active-run validation,
server-owned credentials, file containment, transfer bounds and replay handling
also remain in place. REST parity does not grant board identity or new permissions.
Mutation call IDs reserve a durable receipt in the run's existing `resultJson`
before dispatch. Replays return the recorded result. Reusing an ID with different
@@ -190,13 +195,34 @@ run. No database migration is needed.
Workspace uploads use the existing workspace resource containment checks,
no-symlink file opens covering every path component, and bounded descriptor reads.
Local uploads require Linux or macOS; authorized artifacts work on other hosts.
Lifecycle-sensitive endpoints require an inline JSON object, so a raw uploaded
JSON file cannot hide protected fields from policy checks. Artifacts must belong
to the bound company. Secret-value access, credential management, secret proposals
and company exports require their existing secure clients. Search describes these
operations as restricted. `call_api` rejects them before creating a replay receipt
or making an HTTP request. Safe secret metadata listing remains available.
Agent credentials are never returned to the model. Streaming, WebSocket, MCP and authentication
Artifacts must belong to the bound company and pass the same actor access checks
as downloads, before and after reading their bytes. Private API response snapshots
cannot be used as public company logos or bundled into company exports. An owner
can explicitly publish a copy through the existing attachment upload path.
Request bodies and uploads go
through the route's validation and authorization; the fallback does not reject
fields that an agent can supply through REST. Route-authorized responses normally use the bounded inline/artifact capture and
replay mechanism. Credential-bearing responses (secret values, issued keys,
invites, webhook secrets (including restored triggers) and gateway credentials) stay inline, with a 10 MiB
response bound. They never spill into plaintext files or saved response assets.
Their durable mutation receipts encrypt the response with the existing local
secret provider. Replays decrypt it only inside the authorized run; no HTTP
request repeats. A working secret store is checked before credential dispatch.
Other API responses retain the existing 24 KiB inline and 1 GiB capture limits.
API request and response bodies are omitted from persisted native tool events,
checkpoints and completion results. Saved events retain operation identity, HTTP
status and a payload digest for replay conflict detection. The model still receives
the original authorized HTTP response; this redaction affects durable history.
Completion retries compare expected and persisted events through the same
idempotent redaction projection. Repeated projection preserves the original
payload digest. Provider recovery uses the same projection to compare saved
completion results with provider history. Changed private bodies still conflict.
Restart preparation preserves the run's admitted REST credential scope, even
when the task mode changes. See [the run-log guide](run-log-events.md) for stored fields.
The server-issued REST credential for the bound run is never returned to the model.
Streaming, WebSocket, MCP and authentication
handshakes are documented as protocol operations requiring their existing clients.
## Catalog maintenance
+12 -4
View File
@@ -90,10 +90,18 @@ Only a board operator can record this repair. It preserves the current task
owner, conversation generation, status, and execution locks. It does not queue a
continuation or replay the stopped run; after repair, any new work still follows
the normal admission rules.
The board currently shows repair guidance and an Inspect run link, not a repair
form. Recording the decision is an operator API/runbook workflow; the recovery
API response contains the exact action and lease IDs. Provider access may require
an instance administrator or Cloud support. This change does not add a repair UI.
The original legacy run may be `succeeded` while required files still need
repair. Verified file-only repair accepts that terminal result and keeps it
unchanged. It still requires the retained-source record, exact remote stop
receipts, and recovered-file evidence. A successful result does not permit a
normal execution retry, and a queued or running source cannot be repaired this
way. Later saved messages can continue through ordinary admission after the
file hold clears.
The board shows repair guidance, an Inspect run link, and a Record file recovery
form for operators with runtime access. The form requires recovered-file evidence
and confirmation; the API verifies the original stop receipts. The operator API
also supports this workflow and returns the exact action and lease IDs. Provider
access may require an instance administrator or Cloud support.
Then use the provider's operator console to remove that exact retained
allocation when its files are no longer needed. Verify its immutable provider
allocation ID against the recorded lease before removal. The ordinary reusable
+8
View File
@@ -110,6 +110,14 @@ feedback-export-20260331T120000Z.zip
Exports are full by default. `traces/` keeps the Paperclip envelope, while `full-traces/` contains the richer per-trace bundle plus any recoverable adapter-native files.
Feedback text redaction preserves hostnames, dotted filenames, public schema IDs,
and authentication terms such as “bearer tokens.” Dotted text must have an encoded
JWT header to be masked as a token. Complete three-part signed tokens and
five-part encrypted tokens are masked, including tokens with short segments
and direct-encryption tokens with an empty encrypted-key segment.
Explicit credentials, secret fields, email addresses, and phone numbers remain
masked. The redaction summary counts text that was actually replaced.
```bash
# Custom server and output directory
npx paperclipai feedback export --api-base http://127.0.0.1:3000 --company-id <company-id> --out ./my-export
+25 -7
View File
@@ -62,7 +62,7 @@ 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
followed by one H2 backticked ID per product
sub-feature. Each capability contains these fields:
- **Review:** `baseline` or `operation-reviewed`.
@@ -90,14 +90,15 @@ 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.
Agent access: `available` — agent REST, CLI routine create and native call_api
under the enabled rollout and active-run/mode gates.
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.
Gaps: verify ownership and responsible-user resolution with a permitted agent
context; source presence alone does not qualify this operation.
```
## Keeping the maps synchronized
@@ -105,7 +106,7 @@ Gaps: default native create path; verify using the real permitted agent context.
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
capability is unchanged; update the affected cross-links together. Indexes discover recipes automatically. An API-only
change may update the companion without rewriting unchanged user instructions.
[maintain-verification-skill](../.agents/skills/maintain-verification-skill/SKILL.md)
@@ -121,7 +122,7 @@ Run the structural check after map changes:
node scripts/check-maps.mjs
```
It checks paired areas/IDs, indexes, required fields, and local references. It
It checks paired areas/IDs, navigation metadata, 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.
@@ -132,4 +133,21 @@ 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.
separate from generated `maps/generated/coverage.json`, which lists page references.
## Local authorship and generated indexes
Change only the recipes, access contracts and stories whose behavior or intent
changed. Feature recipes own navigation metadata; stories own small
`parameters.paperclip` annotations. Do not register entries or refresh counts in
shared READMEs, inventories, fingerprints or review journals.
`node scripts/storybook-catalog.mjs` validates and generates aggregate navigation,
Storybook data, verification routes and the page inventory. All outputs live in
ignored `maps/generated/`, `ui/storybook/generated/`, and the ignored Storybook
`preview.tsx` wrapper. Start/build and UI typechecking generate their own inputs.
A clean merged checkout therefore assembles both branches' changes automatically.
Git provides history and diffs. PRs, issues and CI artifacts retain review/run
evidence for the named revision. Capability associations do not create whole-file
review dependencies. Keep durable scenario limits in the affected recipe or story.
+49 -43
View File
@@ -4,51 +4,17 @@ This map accompanies the [feature map](../feature-map/README.md). It records API
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.
## Browse access contracts
## Areas
The same-named feature recipes define navigation and capability IDs. Run
`node scripts/storybook-catalog.mjs` for the generated
`maps/generated/agent-access-map.md` index, or browse the
[published feature guide](https://d1p6rlowie26tp.cloudfront.net/storybook/branches/master/?path=/story/overview-storybook-guide--coverage-guide).
Add or update the affected companion; there is no central registration or count.
| 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 |
Existing baseline source references describe the original inspection, not current
verification. Record new executed evidence in the PR, issue, or CI artifact with
its revision and scope. Do not refresh unrelated headers as bookkeeping.
## Using an entry
@@ -67,3 +33,43 @@ 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.
## Native REST transport
The `call_api` parity change reconciles affected baselines against
`58e16dbddfc9c8d0cf60867f9d9847f0feda055b` and the changes in this PR. Ordinary
REST operations use the same route authorization as legacy agent REST. Dedicated
tools remain optional for those operations; protocol endpoints still need their
existing clients. Board-only routes remain restricted for agent identity.
Native `search_api` / `call_api` requires operator rollout admission, a running
authorized native run, current task assignment and execution-run binding, company
and budget authority, task privacy, and a permitted work mode. Ask and Plan retain
mutation restrictions, and runs retain their admitted JWT scope during restart
recovery even when task mode changes. A waiting
agent does not gain independent native control just because a REST route exists.
Credential-bearing replies, including company exports and their legacy alias,
stay inline under a 10 MiB limit and use encrypted mutation receipts. Other saved
API snapshots are limited to the issuing actor and responsible user, plus authorized
administrators. Artifact uploads enforce the same access checks as downloads;
private snapshots are excluded from company exports and public company logos.
Explicit deliverables use the existing sharing path. Native event history,
checkpoints and completion records omit API bodies while preserving receipt
metadata and replay digests. Restored webhook secrets use the same encrypted
receipt and inline response policy as newly created webhook secrets.
Task image access requires the company boundary and the task permission;
skill-test and low-trust agents do not need company-wide browsing authority.
Completion replay applies the same idempotent projection to stored and expected
payloads; [the run-log guide](../../doc/run-log-events.md) describes its fields.
Sources: [API client](../../server/src/services/native-runtime/runner-api-client.ts),
[catalog](../../server/src/services/native-runtime/runner-api-catalog.ts),
[native authority](../../server/src/services/native-runtime/paperclip-runner-tool-authority.ts),
[credential storage classification](../../server/src/services/native-runtime/runner-api-sensitive-response.ts),
[snapshot access](../../server/src/services/asset-content-access.ts),
and [history redaction](../../server/src/services/native-runtime/runner-api-log-redaction.ts). The affected entries remain
`baseline` and `source-only`; this reconciliation does not certify every operation.
Targeted real-route proof lives in the
[API integration suite](../../server/src/services/native-runtime/runner-api.integration.test.ts),
including owned routines, skill tests, scoped secrets, proposals and private export replay.
+5 -3
View File
@@ -2,7 +2,9 @@
Product map: [Login, invitations, and access](../feature-map/access.md).
Review date: 2026-10-12. Source commit: `f981fa3cc10cb8663a87dec60345fbff46d54d0a`.
Review date: 2026-10-12. Source commit: `58e16dbddfc9c8d0cf60867f9d9847f0feda055b`.
Native REST transport reconciled in this change; see the
[shared transport contract](README.md#native-rest-transport).
This is a source-reviewed baseline of representative operations and known gaps.
Each capability needs operation-level review before its entire scope can be
@@ -43,8 +45,8 @@ 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.
Agent access: `partial` — REST / native `call_api` invite creation with the invite
permission; CLI access. Human acceptance and agent onboarding have distinct policies.
Policy: Company access plus action-specific grants; instance administration requires a
board administrator.
+3
View File
@@ -90,6 +90,9 @@ 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.
Company heartbeat history defaults to 200 rows and caps explicit limits at 1,000
in both the route and service. The response remains an array. Scope, visibility,
and secret redaction checks apply to the bounded result set.
## `routine-audit`
+56 -5
View File
@@ -2,7 +2,9 @@
Product map: [Hiring, agent configuration, and organization](../feature-map/agents.md).
Review date: 2026-10-12. Source commit: `f981fa3cc10cb8663a87dec60345fbff46d54d0a`.
Review date: 2026-10-12. Source commit: `58e16dbddfc9c8d0cf60867f9d9847f0feda055b`.
Native REST transport reconciled in this change; see the
[shared transport contract](README.md#native-rest-transport).
This is a source-reviewed baseline of representative operations and known gaps.
Each capability needs operation-level review before its entire scope can be
@@ -139,8 +141,8 @@ API: `present` — representative operation IDs:
- `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.
Agent access: `partial` — REST / native `call_api` resume under agent_config:update
change-grant authorization; pause and termination remain board-only.
Policy: Agent creation/configuration uses action grants, resource policies and change
consent; some controls require a board actor.
@@ -153,8 +155,8 @@ credentials/run context; inspect its result and applicable persistence/attributi
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.
Gaps: Resume has a generic native REST path. Pause and termination remain
enforced actor restrictions.
## `built-in`
@@ -187,3 +189,52 @@ provisioning resolves the runner, while unrelated reconciliation and same-harnes
edits retain existing execution. Verify explicit runner changes preserve compatible
saved settings; the general creation/access policy above still applies. This is
source-only evidence at the scoped commit, not a live provisioning result.
## `primary-agent`
Review: `baseline`.
API: `present` — GET and PUT /api/companies/{companyId}/primary-agent/me.
Agent access: `restricted` — this is the authenticated human's personal
preference. Agent keys and native call_api use agent identity and are denied by
the board gate; no dedicated agent selection tool is present.
Policy: Requires board user identity, company access and active membership,
except implicit-local board or instance administrator. Viewers may choose their
own primary. Selection requires a same-company readable, available agent and
is scoped to actor user ID; the request cannot select another user's preference.
Explicit null selection is rejected; leave/termination can clear an unavailable
choice. Initialization stays recorded so clearing does not silently replace it.
Evidence: `source-only` — reviewed on 2026-10-13 at
`60bc0d5fee9a6e48db08fc016521fee3d9f57d67`:
[routes](../../server/src/routes/primary-agent.ts),
[service](../../server/src/services/primary-agent.ts),
[provider](../../ui/src/context/PrimaryAgentProvider.tsx), and
[route tests](../../server/src/__tests__/primary-agent.test.ts).
Verification: `not-run` — select and read the preference as two company users;
assert isolation, wrong-company/unreadable targets, pending/terminated agent
rejection and agent-key denial. Verify replacement confirmation and fallback
precedence in the UI; inspect the cleared state after permitted leave/termination.
Gaps: No agent mutation path for another person's preference. Live human/agent
access is unverified; UI fixture callbacks do not establish persistence or task
and Chat default resolution.
## `grok-bot`
Review: `baseline`.
API: `present` — `POST /api/companies/{companyId}/grok-invitations`, operator-owned Grok invitations and agent-scoped `/grok-binding` setup, routine, verify, stop, recover and disconnect endpoints. Direct HTTPS `/mcp/runner` uses fixed named-agent OAuth. Grok tools expose durable assignment operations and task-bound upload/download grants.
Agent access: `available` — `paperclip_grok_*` through the dedicated agent grant. First-party Paperclip operations execute through the shared Rust Runner. The Bot retains its own apps; Paperclip workspace and third-party app tools are unavailable.
Policy: company/agent/client/resource/authorizer binding; current manage-agent permission for consent and subsequent calls; normal task ownership, controller lease, governance, pause, revocation and recorded budget checks. Execution and file transfers require current task-bound sessions. Secret credentials remain in encrypted secret storage and are redacted from HTTP logs.
Evidence: `source-only` — [routes](../../server/src/routes/grok-bot.ts), [shared authority](../../server/src/services/external-bot-authority.ts), [routine receipts](../../server/src/services/grok-bot/routine.ts) and [Runner broker](../../server/src/services/dot-runner-broker.ts). Temporary actual-client OAuth and an outbound routine wake are qualified separately; they do not prove this candidate’s acceptance.
Verification: `not-run` — deployed acceptance pending; focused protocol/authorization and actual Rust backend tests; run fresh/saved setup, assigned and proactive tasks, duplicate calls, stale sessions, restart, ambiguous delivery, stop and recovery through the real client on the serving managed candidate.
Gaps: deployed two-way work and unattended first-time onboarding remain unqualified; remote termination, provider transcript streaming and usage accounting are unavailable.
+46 -3
View File
@@ -2,7 +2,9 @@
Product map: [External chat and email conversations](../feature-map/chat-channels.md).
Review date: 2026-10-12. Source commit: `f981fa3cc10cb8663a87dec60345fbff46d54d0a`.
Review date: 2026-10-12. Source commit: `58e16dbddfc9c8d0cf60867f9d9847f0feda055b`.
Native REST transport reconciled in this change; see the
[shared transport contract](README.md#native-rest-transport).
This is a source-reviewed baseline of representative operations and known gaps.
Each capability needs operation-level review before its entire scope can be
@@ -33,6 +35,10 @@ own policy and access review.
Gaps: Provider installation and account enrollment are not available to an ordinary
agent actor.
Speko UI reconciliation (2026-10-13): experimental voice setup uses the same
board-managed endpoint boundary. Source review follows the merged voice runtime
and the UI integration; live provider qualification is still separate.
## `identity`
Review: `baseline`.
@@ -53,8 +59,8 @@ Verification: `not-run` — assert the documented agent denial with an owned tes
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.
Gaps: Identity linking requires a signed-in board user, rollout admission and
provider checks at the HTTP route. Native `call_api` preserves these permissions.
## `conversation`
@@ -81,6 +87,34 @@ remaining operations before qualifying the whole capability.
Gaps: Normal agent replies work through server delivery. Explicit endpoint publication
APIs are board management paths.
GitHub publication recovery (2026-10-14): assigned-agent `submit_review`, `comment`,
and `update_comment` calls reuse their run-, task-, endpoint-, and argument-bound
publication on an exact retry. Fresh gateway policy and provider authority remain
required. The durable worker resumes transient failures after restart and stops
at its retry cap, revoked authority, or a superseded head. A pending receipt is
not task completion. Source:
[publication service](../../server/src/services/chat-github-reviews.ts) and
[gateway](../../server/src/services/tool-gateway.ts). Verification uses
PostgreSQL-backed provider fixtures; this entry does not claim live provider
qualification for the new retry path.
Speko browser sessions use `POST /api/companies/{companyId}/voice-sessions`,
with GET inspection/notification and POST `/{sessionId}/end` operations below
that collection. These routes require board identity; ordinary agent credentials
cannot start a private voice session. Start and notification also require the
experimental chat-connectors gate. Signed provider callbacks use the separate
voice-webhook routes and their session capability. Evidence: `source-only` —
[voice routes](../../server/src/routes/voice-sessions.ts). No live browser answer
retrieval or telephone playback is established by the UI fixtures.
Slack's **Require at-mention** policy applies to channel messages and channel
thread replies, including queued work. DMs are exempt from mention checks;
endpoint availability, **Allow direct messages**, and sender authorization still
apply. Top-level DM replies retain their linear conversation destination. Source:
[admission](../../server/src/services/chat-channels.ts) and
[queued run policy](../../server/src/services/durable-chat-wakeup.ts). Live Slack
verification of this exemption remains separate from provider-fixture coverage.
New conversations resolve typed project/workspace defaults from their endpoint
and destination under the task-creation transaction. Defaults do not authorize
private sources: admission checks the linked user's authority and assigned agent.
@@ -142,3 +176,12 @@ to reply.
Endpoint/destination execution defaults use the same board-only management
boundary. Agents select an authorized workspace for their current task through
the [workspace APIs](workspaces.md), rather than editing channel configuration.
Speko callback preferences, incoming phone configuration/approval, and call
history use the company-scoped `voice-callbacks`, `voice-phone`, and
`voice-history` routes. Their UI controls do not grant agents board authority.
See [voice routes](../../server/src/routes/voice-sessions.ts); service-level
caller/session permissions and real provider delivery need separate verification.
GitHub review summary headings use the bot display name. Checks remain
independently scoped by GitHub App and endpoint/PR/commit identity.
+75 -5
View File
@@ -2,7 +2,9 @@
Product map: [Companies and portability](../feature-map/companies.md).
Review date: 2026-10-12. Source commit: `f981fa3cc10cb8663a87dec60345fbff46d54d0a`.
Review date: 2026-10-12. Source commit: `58e16dbddfc9c8d0cf60867f9d9847f0feda055b`.
Native REST transport reconciled in this change; see the
[shared transport contract](README.md#native-rest-transport).
This is a source-reviewed baseline of representative operations and known gaps.
Each capability needs operation-level review before its entire scope can be
@@ -97,8 +99,8 @@ API: `present` — representative operation IDs:
- `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.
Agent access: `partial` — Same-company CEO REST / native `call_api` / CLI exports
and eligible same-company imports.
Policy: Same-company CEO or board for identity/import operations; list/create/archive
convenience endpoint is board-gated.
@@ -111,5 +113,73 @@ credentials/run context; inspect its result and applicable persistence/attributi
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.
Gaps: Exports use inline credential delivery and encrypted mutation receipts.
New-company/ZIP import flows retain their board and transport constraints.
## `decision-models`
Review: `baseline`.
API: `present` — GET and PUT /api/companies/{companyId}/decision-model;
POST /api/companies/{companyId}/decision-model/test;
GET /api/companies/{companyId}/decision-model/availability;
GET /api/companies/{companyId}/decision-model/history.
Agent access: `partial` — same-company REST and admitted native call_api
availability/history reads where policy allows. Settings and the fixed Test
action require board identity. Native rollout/run gates follow the shared
[transport contract](README.md#native-rest-transport).
Policy: Settings access requires board and company access; non-managers receive
no settings or choices. Configuration and tests additionally require connection
management authority (owner/admin, instance admin, or tools:manage_connections).
History requires company_scope:read and redacts task/run links without issue:read.
Background sponsorship and budget admission remain separate service checks.
Evidence: `source-only` — reviewed on 2026-10-13 at
`60bc0d5fee9a6e48db08fc016521fee3d9f57d67`:
[routes](../../server/src/routes/decision-models.ts),
[service](../../server/src/services/decision-models.ts), and
[connection authority](../../server/src/routes/ai-connections.ts).
Verification: `not-run` — read history with an allowed company actor and an actor
without task access; check link redaction. Reject agent configuration/tests and
board mutations without connection-management permission. Verify settings and
bounded test receipts with an owned simulated provider.
Gaps: No agent settings/test path; permitted history does not delegate management.
Live native and agent-credential reads remain unverified.
## `fast-responses`
Review: `baseline`.
API: `present` — GET and PUT /api/companies/{companyId}/fast-response;
GET /api/companies/{companyId}/fast-response/models;
GET /api/companies/{companyId}/fast-response/availability;
POST /api/companies/{companyId}/fast-response/test;
GET /api/companies/{companyId}/fast-response/history.
Agent access: `partial` — same-company REST and admitted native call_api history
reads where policy allows, subject to the shared
[transport contract](README.md#native-rest-transport).
Settings, model selection, availability and test controls require board identity.
Policy: Board and company access gate configuration surfaces. Updates, models
and tests additionally require connection-management authority. History requires
company_scope:read; task/run links require issue:read. The experiment, provider
account, sponsorship and budget controls still gate actual acknowledgements.
Evidence: `source-only` — reviewed on 2026-10-13 at
`60bc0d5fee9a6e48db08fc016521fee3d9f57d67`:
[routes](../../server/src/routes/fast-responses.ts),
[service](../../server/src/services/fast-responses.ts), and
[connection authority](../../server/src/routes/ai-connections.ts).
Verification: `not-run` — inspect history and redacted task links as an allowed
company actor. Reject agent settings/models/availability/tests and unauthorized
board mutations. Use a simulated provider to inspect a saved configuration,
success receipt, timeout and recorded usage.
Gaps: No agent configuration/test path. An acknowledgement is not completed task
work. Live native, provider and agent access remain unverified.
@@ -181,6 +181,14 @@ own policy and access review.
Gaps: Provider endpoint, represented agent and linked sender are operator choices today.
Internal recovery: Telegram discovery walks bounded pages at startup. Configuration
commits only queue the changed connection; durable maintenance rows supply retry deadlines. Inactive subscription
repair is parked until an endpoint or connection change. This creates no agent
management permission or new API. Local database-backed provider-fixture tests in
[channel integration](../../server/src/__tests__/chat-channels.integration.test.ts)
cover recovery, rollback, retries and idle query silence; they do not establish
live provider or agent access.
## `failure`
Review: `baseline`.
+18 -7
View File
@@ -2,7 +2,9 @@
Product map: [Tool gateways and access profiles](../feature-map/gateways-profiles.md).
Review date: 2026-10-12. Source commit: `f981fa3cc10cb8663a87dec60345fbff46d54d0a`.
Review date: 2026-10-12. Source commit: `58e16dbddfc9c8d0cf60867f9d9847f0feda055b`.
Native REST transport reconciled in this change; see the
[shared transport contract](README.md#native-rest-transport).
This is a source-reviewed baseline of representative operations and known gaps.
Each capability needs operation-level review before its entire scope can be
@@ -65,8 +67,8 @@ 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.
Agent access: `partial` — Agent REST / native `call_api` for scoped session creation
and revocation; existing MCP client protocol and assigned native app tools.
Policy: Named gateway/profile administration and credentials are board tools:admin;
agent sessions/tool use use separate scoped authority.
@@ -79,8 +81,16 @@ credentials/run context; inspect its result and applicable persistence/attributi
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.
Gaps: Scoped sessions remain agent/run-bound. MCP requires its existing protocol
client; named gateways and gateway-token management retain board permissions.
Discovery collapses identical descriptors with the same gateway name across
providers, including native assigned-tool startup and fresh searches. Conflicting
definitions remain an error. Distinct names and the normal invocation grants,
approvals and revocation checks remain independent. Regression coverage lives in
[gateway tests](../../server/src/__tests__/tool-gateway.test.ts) and
[assigned-tool tests](../../server/src/services/native-runtime/assigned-mcp-tools.test.ts);
these fixtures do not certify a live external-client journey.
## `tokens`
@@ -103,8 +113,9 @@ Verification: `not-run` — assert the documented agent denial with an owned tes
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.
Gaps: Gateway-token management requires board tools:admin at the HTTP route.
A grant to use an app does not create this authority; native `call_api` preserves
the denial.
## `activity`
+34
View File
@@ -11,6 +11,14 @@ for format, permission checks, evidence and maintenance.
## `views`
The issue-list API accepts optional `includeAgentCreatedTasks`; false restricts
independent results to human creation before search/pagination. Omission retains
existing agent/API behavior. `includeParticipatedTasks=true` requires a board user
and retains only that authenticated user's existing participation as a creation
visibility exception. Company/private-task access checks still apply. Collection
preferences and hierarchy presentation are browser state, not additional authority.
Source-reviewed behavior; live agent access verification remains separate.
Review: `baseline`.
API: `present` — representative operation IDs:
@@ -119,3 +127,29 @@ remaining operations before qualifying the whole capability.
Gaps: General company search and dedicated task search are different result sets; use
the appropriate one.
## `toasts`
Review: `baseline`.
API: `present` — GET /api/companies/{companyId}/events/ws (WebSocket upgrade); viewer-specific
`toastEligible` metadata on authorized events. No notification mutation endpoint.
Agent access: `not-applicable` — toast presentation is a human browser concern.
Agent-authenticated event subscriptions retain authorization but do not qualify
for human toasts. Agent task mutations may notify participating humans.
Policy: Company membership and task/run read checks precede human participation
checks. Creator, current human assignee, commenter, deliberate actor, or explicit
user mention qualifies; agent ownership and responsible-user attribution alone do
not. See [toast semantics](../../doc/TOASTS.md).
Evidence: `source-only` — [socket projection](../../server/src/realtime/live-events-ws.ts)
and [eligibility](../../server/src/realtime/task-toast-eligibility.ts).
Verification: `not-run` — Connect two users and an agent; assert per-user eligibility without
losing authorized cache updates. Deny revoked membership and private task access.
Confirm relevance lookup failure yields a quiet authorized event.
Gaps: Browser recipes and regression sources are not deployment acceptance proof.
@@ -88,6 +88,14 @@ Review: `baseline`.
API: `present` — representative operation IDs:
- `GET /api/health`.
- `GET /api/liveness` and `HEAD /api/liveness` — public process startup status
and build commit only; no database readiness or workspace identity.
Liveness is anonymous and runs before actor/session resolution. Hostname and
signed-bootstrap endpoint validation still apply. It grants no instance control
authority. [Liveness tests](../../server/src/__tests__/liveness.test.ts) cover idle
drain, invalid ambient credentials, unavailable SQL, and startup recovery with
local Express fixtures; no live provider or agent access is claimed.
Agent access: `partial` — REST health plus local CLI doctor.
+59
View File
@@ -88,6 +88,39 @@ testing an existing agent; interactive account login additionally requires a
board user and owner-bound session. An agent's right to hire is not login or
instance-environment administration authority.
For fresh managed Codex Auto setup, the wizard's explicit Connect path can call
`POST /api/environments/{environmentId}/probe?companyId={companyId}` before
selected-runtime testing, then refresh scoped adapter discovery. This reuses the
existing board instance-admin/local-implicit probe gate; `agents:create` alone
is insufficient. A 403, absent proof, changed configuration, missing response
identity or unconfirmed cleanup remains visible. No probe is added to creation
or discovery, no agent/company grant is broadened, and provider authentication
errors never cause an automatic runner switch.
Native setup derives outer sandbox isolation from the server-resolved execution
target, as task execution does. This is an internal transport choice, not a
request/configuration permission. Local and SSH setup keep Codex isolation;
caller-supplied environment flags do not authorize an external sandbox. Existing
company, account, probe and registration-cleanup gates still apply.
The bounded hello probe retains read-only permissions and no dynamic tools. Its
trusted launch skips project-instruction discovery in the new, empty setup
workspace. This grants no filesystem or networking permission and does not
change instruction discovery for ordinary task execution.
Scoped source review: 2026-10-13, exact baseline
`1a0ca66242121e39d88455aa2b52a07acc4a07d9` plus the privately composed onboarding
correction. [Wizard controls](../../ui/src/components/OnboardingWizard.test.tsx)
and [existing Product E2E observer controls](../../tests/runner-e2e/first-task.test.ts)
exercise mocked allowed/denied setup and sticky unknown cost coverage. They do
not prove live actor authorization or provider execution. The explicit manual
`confirmation-replies.runner-codex.daytona.task-card-accept` case requires an
eligible immutable OCI target and the existing probe authority, two identified
setup leases and separately authorized paid/cleanup reservations. Its fixture
neither prequalifies the environment nor creates the agent. Actual Cloud named
snapshot binding, warm/cold signup and live allowed/denied agent checks remain
`not-run`.
Evidence: `source-only` —
[implementation](../../ui/src/components/OnboardingWizard.tsx#L279) at the reviewed
commit above.
@@ -135,6 +168,20 @@ remaining operations before qualifying the whole capability.
Gaps: Task creation is agent-accessible where permitted; scheduling/readiness does not
follow from successful creation.
The Codex first-task fixture's operator cost guard uses the existing board
agent-configuration PATCH before admitting work. This is not evidence of agent
permission to update its runtime; the listed agent-context checks remain not-run.
Scoped source review: 2026-10-13, the first-task asset correction against
`ea6c8eb5e16d61111968f633a66748b397b64a3e`. The existing
[first-task instructions](../../server/src/onboarding-assets/first-task/skills/first-task/SKILL.md)
send file-producing work through the child's own execution and existing
dependency/block controls. Native `register_deliverable` retains its current-task
binding; this adds no cross-task file-registration authority or permission.
Document-only work may use the existing child-document API inline, and plan-only
approval does not authorize implementation. The existing asset tests check
wording only. The literal baseline live attempt failed child-file delivery and
completion reporting; revised live authorization and execution remain `not-run`.
## `resume`
@@ -164,3 +211,15 @@ Scoped source review of [draft restoration](../../ui/src/components/OnboardingWi
preserves harness/runner intent and invalidates obsolete setup-test results after
a selection change. Browser draft continuity is not API or live-agent evidence,
and opening a saved Legacy agent does not apply new-agent defaults.
The initial matching route opening preserves the authorized saved wizard step
on bare and company-prefixed reloads. Explicit new-company or changed-company
openings retain their navigation override and clear foreign company resource
IDs. [Existing component controls](../../ui/src/components/OnboardingWizard.test.tsx)
exercise these presentation and account boundaries. This scoped correction adds
no server draft API, agent grant or proof of live actor authorization. The
managed first-task eval still reloads before Get started and remains a separate
live acceptance gate. The existing mocked-login browser case also checks the
same company-scoped active session and saved selection through route reopening
and a real reload, with one login start and no pending-login hire. These fixture
assertions do not prove server authorization or live credential use.
+6 -3
View File
@@ -2,7 +2,9 @@
Product map: [Pipelines, review queues, and learnings](../feature-map/pipelines.md).
Review date: 2026-10-12. Source commit: `f981fa3cc10cb8663a87dec60345fbff46d54d0a`.
Review date: 2026-10-12. Source commit: `58e16dbddfc9c8d0cf60867f9d9847f0feda055b`.
Native REST transport reconciled in this change; see the
[shared transport contract](README.md#native-rest-transport).
This is a source-reviewed baseline of representative operations and known gaps.
Each capability needs operation-level review before its entire scope can be
@@ -31,8 +33,9 @@ credentials/run context; inspect its result and applicable persistence/attributi
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.
Gaps: Configuration and case-automation retry/rerun have native `call_api` REST
paths under company, active-agent-run, case and target-pipeline write checks. The
route and service retain retry/rerun eligibility and dispatch policy.
## `items`
+9
View File
@@ -111,3 +111,12 @@ 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.
Repository attachment also writes a durable skill import binding in its transaction.
Agent-created bindings derive their refresh person from authenticated responsible-user
context. Project selection does not grant runtime credentials or override private
project skill access. Verify automatic import and denial with the actual agent identity.
Workspace creation, update and deletion require project:write_workspace through
the shared authorization evaluator in addition to project read access. Repository
attachment does not bypass skill-import policy for its background discovery.
+63 -14
View File
@@ -2,7 +2,9 @@
Product map: [Recovery](../feature-map/recovery.md).
Review date: 2026-10-12. Source commit: `f981fa3cc10cb8663a87dec60345fbff46d54d0a`.
Review date: 2026-10-12. Source commit: `58e16dbddfc9c8d0cf60867f9d9847f0feda055b`.
Native REST transport reconciled in this change; see the
[shared transport contract](README.md#native-rest-transport).
This is a source-reviewed baseline of representative operations and known gaps.
Each capability needs operation-level review before its entire scope can be
@@ -42,7 +44,8 @@ API: `present` — representative operation IDs:
- `POST /api/issues/{id}/recovery-actions/resolve`.
Agent access: `partial` — Eligible agent REST / CLI; native generic mutation restricted.
Agent access: `partial` — Eligible agent REST / native `call_api` / CLI under
source-bound recovery authority.
Policy: Task/run visibility, run ownership and source/action policy; workspace export
retry and some operator controls require board.
@@ -55,8 +58,20 @@ credentials/run context; inspect its result and applicable persistence/attributi
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.
Gaps: Eligible resolutions use native `call_api`. The route retains owner and
management authority, active-run/source-trust checks, board-only outcomes and
reconciliation controls.
Scoped source review: 2026-10-13, recovery correction against
`ea6c8eb5e16d61111968f633a66748b397b64a3e`. The
[recovery service](../../server/src/services/recovery/service.ts) reuses the
existing completed-onboarding handoff validator. It checks the source company,
onboarding origin, Done parent, assignee and Done child, with no unfinished
siblings, before exempting the report from the issue-terminal backstop. Other
terminal work and process-death/controller ownership checks remain enforced.
This internal wake handling adds no recovery-resolution or cross-company agent
authority. Real PostgreSQL regressions cover allowed and rejected bindings;
revised live agent authorization and callback delivery remain `not-run`.
## `source-action`
@@ -67,13 +82,25 @@ API: `present` — representative operation IDs:
- `GET /api/issues/{id}/recovery-actions`.
- `POST /api/issues/{id}/recovery-actions/resolve`.
Agent access: `partial` — Eligible agent REST / CLI; source-bound recovery state.
Agent access: `partial` — Eligible agent REST / native `call_api` / CLI; source-bound
recovery state.
Policy: Task/run visibility, run ownership and source/action policy; workspace export
retry and some operator controls require board. Completion or cancellation of a
task does not clear its exact unresolved native workspace owner hold. Physical
owner release still requires the [operator stop-verification procedure](../../doc/native-workspace-finalization-recovery.md).
For a resolved legacy action that retains a file hold, the same resolution API
supports source-only file repair. Board runtime management and recovery-resolution
authority are required. The request identifies the exact source action/run and
records recovered-file evidence; the server verifies the original stop receipt.
It preserves the current task status and does not wake or replay the agent. The
task form fails closed without permission or source bindings. Agent Chat retains
the file diagnosis while this hold exists. The
[repair route regressions](../../server/src/__tests__/workspace-restore-repair-route.test.ts)
and [file form](../../ui/src/components/WorkspaceFileRecovery.test.tsx) cover the
local contract; they do not independently recover files or qualify a live provider.
Evidence: `source-only` — [implementation](../../server/src/routes/issues.ts#L9478) at
the reviewed commit above. Exact owner hold retention in the
[recovery state helper](../../server/src/services/native-runtime/native-workspace-finalization-recovery-state.ts)
@@ -89,8 +116,8 @@ physical copyback, and cleanup after the receipt is cleared. Exercise this
sequence in a disposable instance; automatic cleanup must use the system actor
and must not create reader participation. No live recovery proof is claimed.
Gaps: Need operation-level eligibility and a real native binding for permitted recovery
actions; do not route around lifecycle authority.
Gaps: Permitted resolutions use native `call_api` under existing eligibility
and ownership checks. Source/action policy determines whether continuation is allowed.
## `exhaustion`
@@ -124,23 +151,45 @@ Review: `baseline`.
API: `present` — representative operation IDs:
- `POST /api/issues/{id}/recovery-actions/retry-workspace-export`.
- `POST /api/issues/{id}/recovery-actions/resume-workspace-finalization`.
- `POST /api/issues/{id}/recovery-actions/resolve` for retained-source file repair.
- `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.
Policy: Export retry and branch reconciliation require board runtime management.
Retained legacy file-only repair requires the board, exact stopped-source receipts,
and recovered-file evidence. It can record repair for a successful legacy turn
without changing its result or authorizing replay. Queued and running sources
remain denied. Source-only reconciliation regressions cover this boundary.
Physical-owner stop confirmation uses the separate `runtime:confirm_owner_stop`
action. It requires active company owner/admin membership, trusted local board
access, or instance administration. Agents and ordinary runtime managers are denied.
The exact source task, running native run, accepted result and owner receipt must
match; active copyback locks, live local writers, and newer runs prevent admission.
An authorized administrator must first verify through the deployment platform that
the exact controller and all copyback children stopped, then attest that evidence.
Elapsed time, an expired coordinator lease or a lost advisory connection is not proof.
Only the exact owner receipt is released; normal reconciliation performs export and
commitment without another provider turn or bypassing existing task waits.
Evidence: `source-only` — [implementation](../../server/src/routes/issues.ts#L9478) at
the reviewed commit above.
Evidence: `source-only` — [route](../../server/src/routes/issues.ts),
[administrator authorization](../../server/src/services/authorization.ts), and
[owner admission](../../server/src/services/native-runtime/native-workspace-owner-recovery.ts)
reviewed for this change. Local authorization, route, UI and finalization regressions
cover member/agent denial, exact-owner admission and the real reconciler preserving
monitor and approval waits. This is not live provider-stop proof.
Verification: `not-run` — assert the documented agent denial with an owned test fixture;
Verification: `not-run` for live agent/deployment execution — 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.
Gaps: Export retry and branch reconciliation require board runtime:manage at
their HTTP routes. The exact-owner operator fallback additionally requires
runtime:confirm_owner_stop. Native call_api preserves these agent denials.
Automatic managed-cloud recovery uses independently verified, signed platform
proof through the finalization reconciler; agents cannot attest owner shutdown.
## `unknown-outcome`
+34 -15
View File
@@ -2,7 +2,9 @@
Product map: [Routines, schedules, and triggers](../feature-map/routines.md).
Review date: 2026-10-12. Source commit: `f981fa3cc10cb8663a87dec60345fbff46d54d0a`.
Review date: 2026-10-12. Source commit: `58e16dbddfc9c8d0cf60867f9d9847f0feda055b`.
Native REST transport reconciled in this change; see the
[shared transport contract](README.md#native-rest-transport).
This is a source-reviewed baseline of representative operations and known gaps.
Each capability needs operation-level review before its entire scope can be
@@ -18,8 +20,8 @@ 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.
Agent access: `available` — Agent REST / native `call_api` / 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.
@@ -32,8 +34,9 @@ credentials/run context; inspect its result and applicable persistence/attributi
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.
Gaps: No dedicated production manage_routine binding; generic `call_api` provides
the permitted REST path. Creation needs a responsible user resolved from the parent
issue or company default.
## `triggers`
@@ -44,7 +47,8 @@ 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.
Agent access: `available` — Owned-routine agent REST / native `call_api` / CLI trigger
commands.
Policy: Agents may read company routines but only create/manage routines assigned to
themselves; trigger secrets need secure handling.
@@ -57,8 +61,17 @@ credentials/run context; inspect its result and applicable persistence/attributi
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.
Gaps: No dedicated production trigger-management binding; generic `call_api`
provides the permitted REST path. Credential replies use inline delivery and encrypted
mutation receipts rather than shared response assets.
The host-only `GET /api/instance/task-drain?idleSleepSafety=1&scheduledWake=1`
extension reports the earliest supported future routine deadline under an owned
idle hold. It requires signed Cloud control authority; company agents and tenant
admin tokens cannot use it. It does not grant routine management or execution
authority. See the [hosting protocol](../../doc/idle-sleep-safety.md#scheduled-routine-wake-protocol)
and [route authorization tests](../../server/src/__tests__/instance-settings-routes.test.ts).
These are local contract checks, not a live provider sleep/wake qualification.
## `run-now`
@@ -68,7 +81,8 @@ API: `present` — representative operation IDs:
- `POST /api/routines/{id}/run`.
Agent access: `partial` — Owned-routine agent REST / CLI routine run.
Agent access: `partial` — Owned-routine agent REST / CLI run; native `call_api` from
an authorized active run.
Policy: Agents may read company routines but only create/manage routines assigned to
themselves; trigger secrets need secure handling.
@@ -81,8 +95,8 @@ credentials/run context; inspect its result and applicable persistence/attributi
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.
Gaps: Scheduled/waiting native agents cannot independently call this operation:
native authority requires a running bound run. A separate control binding remains absent.
## `history`
@@ -117,8 +131,7 @@ 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.
Agent access: `available` — Owned-routine agent REST / native `call_api` / CLI.
Policy: Agents may read company routines but only create/manage routines assigned to
themselves; trigger secrets need secure handling.
@@ -131,5 +144,11 @@ credentials/run context; inspect its result and applicable persistence/attributi
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.
Gaps: Pause/archive mutations have a generic native REST path under routine
ownership rules. Plugin-managed routine rules remain separate.
Execution resolves referenced project skills against agent/responsible-user access,
then saves immutable version selections in the heartbeat execution context. New runs
resolve latest installed content; resumed runs retain selections and recheck access.
An unavailable explicit reference produces an actionable configuration error.
Live agent execution across an upstream update remains required acceptance evidence.
+62 -7
View File
@@ -2,7 +2,9 @@
Product map: [Runs, harnesses, and model accounts](../feature-map/runs-adapters.md).
Review date: 2026-10-12. Source commit: `f981fa3cc10cb8663a87dec60345fbff46d54d0a`.
Review date: 2026-10-12. Source commit: `58e16dbddfc9c8d0cf60867f9d9847f0feda055b`.
Native REST transport reconciled in this change; see the
[shared transport contract](README.md#native-rest-transport).
This is a source-reviewed baseline of representative operations and known gaps.
Each capability needs operation-level review before its entire scope can be
@@ -28,8 +30,8 @@ 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.
Agent access: `partial` — Agent company-model REST / native `call_api` discovery and
bound runtime context; adapter/account inventories remain board-only.
Policy: Run/cost visibility and agent configuration policy; adapter installation/account
login/session control require board/admin.
@@ -58,6 +60,11 @@ and explicit overrides follow the [shared runner contract](../../packages/shared
Claude follows its qualified rollout described above. The board inventory does not grant a
native agent an equivalent discovery binding. See
[probe restrictions](./execution-environments.md#probe) for acquiring qualification.
An absent forced-Kubernetes environment is an unqualified sandbox target, never
a local target. Discovery and automatic creation keep the Legacy path without
provisioning it; explicit Paperclip selection returns qualification guidance.
The existing execution path owns lazy environment creation. Saved runners remain
unchanged. This is source/control evidence, not live Kubernetes qualification.
## `validation`
@@ -67,8 +74,8 @@ 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.
Agent access: `partial` — Permitted agent-creation validation through REST / native
`call_api` / CLI; account login requires its operator.
Policy: Run/cost visibility and agent configuration policy; adapter installation/account
login/session control require board/admin.
@@ -94,6 +101,26 @@ or Legacy CLI check cannot replace that runtime evidence. Missing dependencies,
credentials, invalid models and incompatible settings fail without silently
changing runners. Account login remains board/owner-bound.
For a linked Codex subscription with server-resolved managed credential provenance,
setup checks the resolved owner and stages a private probe copy before local or
remote isolation. Without a selected API key, an unbound linked `CODEX_HOME` is
rejected with explicit Legacy
or managed-account guidance. Caller configuration cannot supply that provenance. Selected `CODEX_API_KEY` and
`OPENAI_API_KEY` authentication skips unrelated subscription reads and refresh
bindings, matching task materialization. The fake-credential controls verify key
precedence without changing the account source or exposing either credential.
The general native
home materializer retains its no-follow symlink guard. Refresh still targets the
checked account source, and confirmed bounded retirement removes its private
copy. Unconfirmed retirement retains the existing cleanup block and owned state.
Failures before probe handoff remove only the owned temporary preparation root;
local daemon resolution occurs before credential staging. Once a probe is handed
off, unconfirmed retirement still retains its recovery state.
[Existing fake-credential setup controls](../../server/src/services/native-runtime/setup-readiness.test.ts)
exercise linked/regular sources and failure cleanup. This adds no credential-read
API, agent login authority or cross-company account access. Its source-only
evidence does not qualify a live permitted/denied agent operation.
Verification for this scope remains `not-run`: use an admitted agent REST/CLI
validation path, assert missing grants and cross-company targets/accounts are
denied, then prove the useful task/follow-up separately. `hire_agent` inherits its
@@ -147,8 +174,26 @@ Verification: `not-run` — assert the documented agent denial with an owned tes
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.
Gaps: Task-session listing and execution-context reset require board agent
management at their HTTP routes. Native `call_api` preserves these denials; native
continuation remains server-owned.
Scoped source-only evidence: [configuration changes](../../server/src/services/agent-configuration.ts)
and [native execution/recovery](../../server/src/services/native-runtime/native-session-executor.ts)
retain existing execution on unrelated edits and use recorded run configuration
for active/recovered runs. Explicit runner changes use revisions and session
invalidation. Verify saved configuration, current versus historical run identity,
restart and follow-up without granting session-reset authority to an agent.
Scoped source review: 2026-10-13, the recovery correction against
`ea6c8eb5e16d61111968f633a66748b397b64a3e` reuses
[completed onboarding handoff validation](../../server/src/services/chat-completion-delivery.ts)
before applying the issue-terminal backstop. The company, parent origin/status,
assignee, completed child and remaining children must match. Only that backstop
is suppressed for the validated report; process-death and controller/native
ownership checks still apply. No agent gains session or recovery control.
PostgreSQL regressions cover valid native/Legacy callbacks and rejected bindings;
revised live execution and actor authorization remain `not-run`.
Scoped source-only evidence: [configuration changes](../../server/src/services/agent-configuration.ts)
and [native execution/recovery](../../server/src/services/native-runtime/native-session-executor.ts)
@@ -169,3 +214,13 @@ Scoped Verification: `not-run` — verify allowed/denied access using the actual
actor independently from the credential-free ownership controls. This correction
adds no account-setup, cleanup-override or session-reset authority. The real native
readiness/recovery fixtures and installed provider acceptance remain separate gates.
Scoped shutdown source review: 2026-10-14, against literal
`651a3de64fc943216cc414b64b1443809f9499da`. The suspension barrier bounds remote
state reads by its remaining deadline and rejects late proof. Intentional
[provider ingress shutdown](../../server/src/realtime/runner-prp-outbound.ts)
joins physical socket closure and retires the connection owner before endpoint
release. Unconfirmed termination stays blocked. Existing fake-peer and delayed
read controls are source evidence; this changes no actor, company, account or
session-reset permission. Operation-level verification remains `not-run` and
the failed Test setup does not qualify successful live cleanup.
+23 -13
View File
@@ -2,7 +2,9 @@
Product map: [Secrets, personal credentials, and proposals](../feature-map/secrets.md).
Review date: 2026-10-12. Source commit: `f981fa3cc10cb8663a87dec60345fbff46d54d0a`.
Review date: 2026-10-12. Source commit: `58e16dbddfc9c8d0cf60867f9d9847f0feda055b`.
Native REST transport reconciled in this change; see the
[shared transport contract](README.md#native-rest-transport).
This is a source-reviewed baseline of representative operations and known gaps.
Each capability needs operation-level review before its entire scope can be
@@ -18,8 +20,8 @@ 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.
Agent access: `partial` — Agent REST / native `call_api` metadata catalog and secret
proposals; company secret administration remains board-only.
Policy: Board secret administration, active-run/self/report proposal policy, and scoped
secret broker bindings; personal secret values belong to their user.
@@ -32,8 +34,8 @@ credentials/run context; inspect its result and applicable persistence/attributi
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.
Gaps: Native transport preserves board-only administration. Bound value retrieval
is a separate scoped operation described under runtime-delivery.
## `user-secrets`
@@ -69,8 +71,8 @@ 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.
Agent access: `partial` — Active-run agent REST / native `call_api` with redaction;
approval/rejection remains board-only.
Policy: Board secret administration, active-run/self/report proposal policy, and scoped
secret broker bindings; personal secret values belong to their user.
@@ -83,8 +85,8 @@ credentials/run context; inspect its result and applicable persistence/attributi
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.
Gaps: No dedicated production proposal tool is required for the REST path.
Native calls retain active-run, scope and skill-test JWT restrictions.
## `vault-import`
@@ -120,8 +122,8 @@ 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.
Agent access: `available` — Authorized environment/broker delivery and scoped agent
REST / native `call_api` value retrieval.
Policy: Board secret administration, active-run/self/report proposal policy, and scoped
secret broker bindings; personal secret values belong to their user.
@@ -134,5 +136,13 @@ credentials/run context; inspect its result and applicable persistence/attributi
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.
Server-only instance secrets are excluded from this path. They belong to the
company, owning agent, and installed lifecycle plugin. The existing local lifecycle
callback can save them through the native secret service; there is no agent API
for their values. Source: [native secret coordinator](../../server/src/services/agent-instance-secrets.ts)
and [scope/denial tests](../../server/src/__tests__/agent-instance-secrets.test.ts).
No live agent execution is claimed for this exclusion.
Gaps: Values remain restricted to the bound agent and active run. Credential
responses stay inline and use encrypted mutation receipts; they are not saved as
plaintext response assets. Dedicated scenario read_secret_value remains unbound.
+49 -5
View File
@@ -2,7 +2,9 @@
Product map: [Skill discovery, authoring, and policy](../feature-map/skills.md).
Review date: 2026-10-12. Source commit: `f981fa3cc10cb8663a87dec60345fbff46d54d0a`.
Review date: 2026-10-12. Source commit: `58e16dbddfc9c8d0cf60867f9d9847f0feda055b`.
Native REST transport reconciled in this change; see the
[shared transport contract](README.md#native-rest-transport).
This is a source-reviewed baseline of representative operations and known gaps.
Each capability needs operation-level review before its entire scope can be
@@ -122,8 +124,8 @@ 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.
Agent access: `available` — Permitted agent REST / native `call_api` creation, control
and history; no dedicated CLI test command found.
Policy: Company skill policy by action/resource plus platform invariants; test execution
additionally requires task-assignment authority.
@@ -137,5 +139,47 @@ credentials/run context; inspect its result and applicable persistence/attributi
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.
Gaps: No dedicated native orchestration binding; generic REST calls retain
skills.test policy, task-assignment authorization, responsible-user intersection and
admitted skill-test JWT scope.
Project-source API additions: GET `/api/companies/{companyId}/skill-sources/project-repositories`,
POST `/api/companies/{companyId}/skill-sources/adopt-project` with `workspaceId`, and
PATCH `/api/companies/{companyId}/skill-sources/{sourceId}/settings` with expected revision
and update/connection preferences. `trackingRef` accepts a branch or explicit ref;
`"HEAD"` keeps default-branch tracking. GET `/api/companies/{companyId}/skill-sources/{sourceId}/branches`
returns a bounded branch list and the default branch, with optional `connectionId` for
connection repair. It requires source access and `skills.edit`, and reads only through
the caller's authorized GitHub grant. Saving validates the requested ref before changing
an independent source; active project bindings must be edited through their
project configuration. Responses identify branch, connection, or retry repair and distinguish
queued imports from imports under an active worker lease. Native API discovery uses the OpenAPI registration.
Project-derived read/use permission follows current project authorization, with access
through either originating project. File/version reads, source metadata, mutations,
editable copies, tests and runtime delivery retain that boundary. Unattended refresh
uses the revalidated setup identity and connection, not the requesting agent's token.
These additions need actual permitted/denied agent-run acceptance; service tests alone
are not live credential proof.
Direct GitHub source imports share the project setup-identity boundary. API-key
agents may import permitted public content, but their responsible-user field
does not authorize unattended credential use. They need human connection repair
for automatic refresh. Authenticated agent runs derive the setup person from
the persisted active run. Legacy agent activity without a matching run cannot
recover a refresh person. Route and database tests cover these distinctions;
this addition makes no new live-provider acceptance claim.
Initial project imports check skills.import before provider reads; denied jobs
do not retry automatically. Deferred jobs remain durable behind per-project and
company admission limits. Scheduled refresh compares immutable tree identity and
uses a persistent work allowance; manual refresh still requires its existing
policy/access checks. These limits grant no content or execution access.
Agent repository setup preserves the active run's selected GitHub connection/grant
IDs. Missing selections require human repair; the worker never searches the
responsible person's other grants for an agent-created source.
Initial automatic imports reserve company work credits before provider reads.
Failures retain the reservation; completed jobs cannot replenish the queue's
work allowance. Jobs remain durable and resume as company credits refill.
+5 -3
View File
@@ -2,7 +2,9 @@
Product map: [Steering and queued messages](../feature-map/steering.md).
Review date: 2026-10-12. Source commit: `f981fa3cc10cb8663a87dec60345fbff46d54d0a`.
Review date: 2026-10-12. Source commit: `58e16dbddfc9c8d0cf60867f9d9847f0feda055b`.
Native REST transport reconciled in this change; see the
[shared transport contract](README.md#native-rest-transport).
This is a source-reviewed baseline of representative operations and known gaps.
Each capability needs operation-level review before its entire scope can be
@@ -80,8 +82,8 @@ Verification: `not-run` — assert the documented agent denial with an owned tes
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.
Gaps: Steering requires a board user at the HTTP route. Native `call_api`
preserves this denial and cannot impersonate the steering user.
## `interrupt`
+7 -4
View File
@@ -3,7 +3,9 @@
Product map: [Delegation, dependencies, and
signoff](../feature-map/task-coordination.md).
Review date: 2026-10-12. Source commit: `f981fa3cc10cb8663a87dec60345fbff46d54d0a`.
Review date: 2026-10-12. Source commit: `58e16dbddfc9c8d0cf60867f9d9847f0feda055b`.
Native REST transport reconciled in this change; see the
[shared transport contract](README.md#native-rest-transport).
This is a source-reviewed baseline of representative operations and known gaps.
Each capability needs operation-level review before its entire scope can be
@@ -43,8 +45,8 @@ API: `present` — representative operation IDs:
- `PATCH /api/issues/{id}`.
Agent access: `available` — Native set_dependencies for current task; agent REST under
mutation/checkout policy.
Agent access: `available` — Native set_dependencies for the current task; agent REST
/ native `call_api` under mutation and checkout policy.
Policy: Task visibility/mutation, task-assignment and ownership policy; review audience
independent; tree controls board-only.
@@ -58,7 +60,8 @@ credentials/run context; inspect its result and applicable persistence/attributi
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.
Gaps: Dedicated set_dependencies is current-task scoped. Generic `call_api`
forwards blockedByIssueIds to the REST route and retains its ownership checks.
## `signoff`
+24 -10
View File
@@ -2,7 +2,9 @@
Product map: [Task creation and lifecycle](../feature-map/tasks.md).
Review date: 2026-10-12. Source commit: `f981fa3cc10cb8663a87dec60345fbff46d54d0a`.
Review date: 2026-10-12. Source commit: `58e16dbddfc9c8d0cf60867f9d9847f0feda055b`.
Native REST transport reconciled in this change; see the
[shared transport contract](README.md#native-rest-transport).
This is a source-reviewed baseline of representative operations and known gaps.
Each capability needs operation-level review before its entire scope can be
@@ -35,6 +37,17 @@ narrower/different APIs.
## `organize`
The issue-list API accepts optional `includeAgentCreatedTasks`; false restricts
independent results to human creation before search/pagination. Omission retains
existing agent/API behavior. `includeParticipatedTasks=true` requires a board user
and retains only that authenticated user's existing participation as a creation
visibility exception. Company/private-task access checks still apply. Collection
preferences and hierarchy presentation are browser state, not additional authority.
Source-reviewed behavior; live agent access verification remains separate.
All `chat_channel` origins count as bot-created for creation visibility, including
human-initiated conversations. Existing inbox participation remains independent.
Review: `baseline`.
API: `present` — representative operation IDs:
@@ -67,8 +80,8 @@ 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.
Agent access: `available` — Native set_task_title/reassign_task/set_dependencies and
`call_api` for REST-authorized fields; agent REST.
Policy: Company/task visibility, assignment/change policy, active-run checkout ownership
and lifecycle rules. A legacy run can assign its own task to a human without
@@ -89,8 +102,8 @@ regressions in [ownership tests](../../server/src/__tests__/issue-agent-mutation
cover a human handoff and stop enforcement for other actors, runtimes and targets;
they use mocked services and do not claim live execution proof.
Gaps: Native fallback blocks status/assignment/dependency policy fields. Dedicated tools
differ in scope and supported fields.
Gaps: Dedicated tools differ in scope and fields. Generic `call_api` forwards
status, assignment and dependency fields to existing route authorization.
## `discussion`
@@ -115,8 +128,9 @@ credentials/run context; inspect its result and applicable persistence/attributi
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.
Gaps: Other-task comments and active-task progress have separate scopes. Generic
`call_api` forwards explicit reopen/resume/interrupt fields to the existing route
checks; it cannot impersonate a user.
## `completion`
@@ -127,7 +141,7 @@ API: `present` — representative operation IDs:
- `PATCH /api/issues/{id}`.
Agent access: `available` — Native paperclip_finish/paperclip_block through runner
protocol; legacy agent REST disposition.
protocol; agent REST / native `call_api` disposition under route permissions.
Policy: Company/task visibility, assignment/change policy, active-run checkout ownership
and lifecycle rules.
@@ -140,5 +154,5 @@ credentials/run context; inspect its result and applicable persistence/attributi
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.
Gaps: The server governs whether a reported result becomes done/review/blocked.
Generic lifecycle PATCH uses existing REST authorization, checkout and approval rules.
+26 -5
View File
@@ -2,7 +2,9 @@
Product map: [Execution workspaces, services, and files](../feature-map/workspaces.md).
Review date: 2026-10-12. Source commit: `f981fa3cc10cb8663a87dec60345fbff46d54d0a`.
Review date: 2026-10-12. Source commit: `58e16dbddfc9c8d0cf60867f9d9847f0feda055b`.
Native REST transport reconciled in this change; see the
[shared transport contract](README.md#native-rest-transport).
This is a source-reviewed baseline of representative operations and known gaps.
Each capability needs operation-level review before its entire scope can be
@@ -37,6 +39,24 @@ workspace write authority. Accepting a new pending choice advances its binding
revision; superseded retries fail while current-choice retries remain idempotent.
Binding revisions and request keys fence retries;
selection applies at the next normal admission without interrupting a live run.
Fresh standard-trust tasks with an implicit repository default can use an owned
remote clone when the shared default source fails the restricted-task workspace
guard. This does not grant access to the private local checkout or its Git metadata.
The normal admitted Git identity must already authorize the configured remote.
Creation of a fallback source is unavailable for explicit, parent/channel, reused
or low-trust selections, or branch templates without a task-derived placeholder;
an existing verified owned source remains reusable. Literal branch selections
retain the original denial without cloning or replacing their unpublished commits.
New implicit Git defaults record project-source provenance. Untyped explicit,
inherited and older ambiguous checkout bindings retain the denial; admission reads
the current company-scoped binding before considering the fallback.
Local paths, unsupported transports and credential-bearing URLs are not fallback
sources. Company/task/remote bindings, real paths, Git storage and the exact origin
are revalidated for reuse, cleanup and reopening. A failed save removes only the
owned task worktree. The [isolated-source service](../../server/src/services/isolated-remote-workspace-source.ts)
and its local regression tests establish source and lifecycle boundaries; live
agent/provider qualification remains separate.
Writable aliases must also be compatible with current and retained physical
source projects' trust boundaries. Incompatible choices are rejected before
dispatch; a projectless alias cannot bypass required sandbox containment.
@@ -119,8 +139,8 @@ 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.
Agent access: `available` — Authorized agent REST / native `call_api` / CLI runtime
service controls and existing stdio MCP controls.
Policy: Company/project/workspace visibility and runtime authority; active run, trust
preset and task ownership where required.
@@ -134,8 +154,9 @@ credentials/run context; inspect its result and applicable persistence/attributi
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.
Gaps: No dedicated production control_workspace_service binding. Generic native
calls retain runtime trust and workspace/task scope checks. Optional MCP availability
must be recorded.
## `files-git`
Loaded 100 of 1176 files, more files were not shown because too many files have changed in this diff. Show more