diff --git a/.agents/skills/create-external-bot-integration/SKILL.md b/.agents/skills/create-external-bot-integration/SKILL.md new file mode 100644 index 00000000000..6694d9643cb --- /dev/null +++ b/.agents/skills/create-external-bot-integration/SKILL.md @@ -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. diff --git a/.agents/skills/create-external-bot-integration/agents/openai.yaml b/.agents/skills/create-external-bot-integration/agents/openai.yaml new file mode 100644 index 00000000000..8614fc0219e --- /dev/null +++ b/.agents/skills/create-external-bot-integration/agents/openai.yaml @@ -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." diff --git a/.agents/skills/create-external-bot-integration/references/conformance-tests.md b/.agents/skills/create-external-bot-integration/references/conformance-tests.md new file mode 100644 index 00000000000..c079fc4c457 --- /dev/null +++ b/.agents/skills/create-external-bot-integration/references/conformance-tests.md @@ -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 . 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 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: + ingressCommit: + appImageDigest: + runnerArtifactDigest: +environment: +client: actual-provider # or scripted +startingState: +identities: + run: + assignment: + session: + lease: + controllerBefore: + controllerAfter: + processFingerprintBefore: + processFingerprintAfter: +interventions: [] +observed: +evidence: +cleanup: +outcome: PASS # FAIL / BLOCKED / UNVERIFIED / NOT_APPLICABLE +limits: +``` + +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. diff --git a/.agents/skills/create-external-bot-integration/references/dot-case-study.md b/.agents/skills/create-external-bot-integration/references/dot-case-study.md new file mode 100644 index 00000000000..d544d11f85b --- /dev/null +++ b/.agents/skills/create-external-bot-integration/references/dot-case-study.md @@ -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": "" }` + 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. diff --git a/.agents/skills/create-external-bot-integration/references/onboarding-and-prompts.md b/.agents/skills/create-external-bot-integration/references/onboarding-and-prompts.md new file mode 100644 index 00000000000..c6a2f34fea9 --- /dev/null +++ b/.agents/skills/create-external-bot-integration/references/onboarding-and-prompts.md @@ -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 in . + +Add or reuse the private plugin for this exact server 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: . +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 only, send Paperclip operations through + for . 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. diff --git a/.agents/skills/create-external-bot-integration/references/release-contract.md b/.agents/skills/create-external-bot-integration/references/release-contract.md new file mode 100644 index 00000000000..25da66f587d --- /dev/null +++ b/.agents/skills/create-external-bot-integration/references/release-contract.md @@ -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. diff --git a/.agents/skills/create-external-bot-integration/references/runner-architecture.md b/.agents/skills/create-external-bot-integration/references/runner-architecture.md new file mode 100644 index 00000000000..93c6176a6b7 --- /dev/null +++ b/.agents/skills/create-external-bot-integration/references/runner-architecture.md @@ -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. diff --git a/.agents/skills/create-external-bot-integration/references/troubleshooting-and-deployment.md b/.agents/skills/create-external-bot-integration/references/troubleshooting-and-deployment.md new file mode 100644 index 00000000000..df851f386af --- /dev/null +++ b/.agents/skills/create-external-bot-integration/references/troubleshooting-and-deployment.md @@ -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 --plain`, with +`--resume ` 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. diff --git a/.agents/skills/create-verification-skill/SKILL.md b/.agents/skills/create-verification-skill/SKILL.md index 782513a549b..1897be5cdcb 100644 --- a/.agents/skills/create-verification-skill/SKILL.md +++ b/.agents/skills/create-verification-skill/SKILL.md @@ -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-/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 `, 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 diff --git a/.agents/skills/fix-slow-queries/SKILL.md b/.agents/skills/fix-slow-queries/SKILL.md new file mode 100644 index 00000000000..b268fd36471 --- /dev/null +++ b/.agents/skills/fix-slow-queries/SKILL.md @@ -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. diff --git a/.agents/skills/fix-slow-queries/agents/openai.yaml b/.agents/skills/fix-slow-queries/agents/openai.yaml new file mode 100644 index 00000000000..98064d747fc --- /dev/null +++ b/.agents/skills/fix-slow-queries/agents/openai.yaml @@ -0,0 +1,3 @@ +interface: + display_name: "Fix Slow Queries" + short_description: "Trace cloud SQL hotspots through local proof and green PRs" diff --git a/.agents/skills/fix-slow-queries/references/cloud-discovery.md b/.agents/skills/fix-slow-queries/references/cloud-discovery.md new file mode 100644 index 00000000000..05a2d6e5a71 --- /dev/null +++ b/.agents/skills/fix-slow-queries/references/cloud-discovery.md @@ -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. diff --git a/.agents/skills/fix-slow-queries/references/local-proof.md b/.agents/skills/fix-slow-queries/references/local-proof.md new file mode 100644 index 00000000000..bc9d217f62a --- /dev/null +++ b/.agents/skills/fix-slow-queries/references/local-proof.md @@ -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. diff --git a/.agents/skills/maintain-storybook/SKILL.md b/.agents/skills/maintain-storybook/SKILL.md index 5735eb5e56b..7fbb804bf0a 100644 --- a/.agents/skills/maintain-storybook/SKILL.md +++ b/.agents/skills/maintain-storybook/SKILL.md @@ -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//`. 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---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. diff --git a/.agents/skills/maintain-verification-skill/SKILL.md b/.agents/skills/maintain-verification-skill/SKILL.md index 8d261ef3fb4..c30385aa8d8 100644 --- a/.agents/skills/maintain-verification-skill/SKILL.md +++ b/.agents/skills/maintain-verification-skill/SKILL.md @@ -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 diff --git a/.agents/skills/review-storybook/SKILL.md b/.agents/skills/review-storybook/SKILL.md index cdc1bc07bc6..603b903a433 100644 --- a/.agents/skills/review-storybook/SKILL.md +++ b/.agents/skills/review-storybook/SKILL.md @@ -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 diff --git a/.agents/skills/setup-code-maintenance-bot/SKILL.md b/.agents/skills/setup-code-maintenance-bot/SKILL.md new file mode 100644 index 00000000000..ed0fcc1d1ce --- /dev/null +++ b/.agents/skills/setup-code-maintenance-bot/SKILL.md @@ -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](), +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. diff --git a/.agents/skills/setup-code-maintenance-bot/agents/openai.yaml b/.agents/skills/setup-code-maintenance-bot/agents/openai.yaml new file mode 100644 index 00000000000..5243bd89424 --- /dev/null +++ b/.agents/skills/setup-code-maintenance-bot/agents/openai.yaml @@ -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." diff --git a/.agents/skills/setup-code-maintenance-bot/references/paperclip-api.md b/.agents/skills/setup-code-maintenance-bot/references/paperclip-api.md new file mode 100644 index 00000000000..2c6bc30df2c --- /dev/null +++ b/.agents/skills/setup-code-maintenance-bot/references/paperclip-api.md @@ -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": "", + "method": "", + "connectionId": "", + "grantId": "" +} +``` + +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":""}`. + 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":[""]} +``` + +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": "", + "description": "", + "assigneeAgentId": "", + "projectId": "", + "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":""} +``` + +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. diff --git a/.agents/skills/setup-code-maintenance-bot/references/run-instructions.md b/.agents/skills/setup-code-maintenance-bot/references/run-instructions.md new file mode 100644 index 00000000000..d382ae12e81 --- /dev/null +++ b/.agents/skills/setup-code-maintenance-bot/references/run-instructions.md @@ -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 , targeting , in project . +Goal: . + +Read and apply . +Skill source/version policy: . +Scope: . Exclusions: . + +Bound this run to