Commit Graph
1658 Commits
Author SHA1 Message Date
de9ab8e7e0 perf(runner): compile the TypeScript surface once per build (#15853)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - Pull requests to this repository run a large CI matrix. The slowest
check sets the time a contributor waits for a green run.
> - After #15849 hid the verifier's downloads behind package staging,
the `Build` lane is still the slowest check in five of the eight fully
green PR runs created after that merge (535s to 581s; the top server
shard is 529s to 560s in the other three). `Build` is about 100s of
setup, 160s to 176s of `pnpm build`, and 265s to 312s of the public
install verifier.
> - Inside `pnpm build`, every package after `@paperclipai/shared` waits
on the Runner: its `build` script takes 76s to 80s, and for 65s of that
it is the only job running. The chain runs `build:typescript` three
times: once directly, then again inside `check:semantic-contracts` and
`check:runner-workflow-traceability`, which rebuild first so they work
standalone. The server's `prepare:runner-vendor` then runs the whole
Runner build a second time, so the job pays for four redundant
TypeScript passes.
> - Each pass is two `tsc` projects, the eval-kernel rebuild, and the
schema checks, 7s to 8s on the CI runner. The dist they rebuild is the
dist the first pass just wrote; nothing between the passes changes it.
> - This pull request calls the two check scripts directly after the
chain's own `build:typescript`, the way `generate-replay-goldens.mjs
--check` already does in the same line. The standalone `check:*` scripts
keep their rebuild.
> - The benefit is about 30s off the `Build` job's critical path, about
15s off the Typecheck job and every Docker or release build that runs
the server build, with no change to what is checked.

## Linked Issues or Issue Description

**Describe the enhancement**

The `Build` PR check is the slowest check in most green PR runs. Its
`pnpm build` step compiles the Runner's TypeScript surface four times:
three passes inside one Runner `build`, and a second full Runner `build`
from the server's `prepare:runner-vendor`. Only the first pass produces
a dist that the later steps read; the other three rewrite the same
output.

**Why is this needed**

The slowest check decides the wall-clock time of every PR run. In the
eight fully green PR runs created after 2026-10-11 04:10Z, `Build`
topped five of them at 535s to 581s. The Runner build sits alone on the
`pnpm build` critical path for about 65s, and the server build repeats
it. From the job logs of four of those runs, the second and third
`build:typescript` passes cost 7s to 8s each, in both Runner builds, so
about 30s per job.

**Proposed solution**

In the Runner's `build` script, replace `pnpm run
check:semantic-contracts && pnpm run check:runner-workflow-traceability`
with `node scripts/generate-semantic-contracts.mjs --check && node
scripts/check-runner-workflow-traceability.mjs`. Both scripts read
`dist/`, which `build:typescript` wrote earlier in the same chain, and
the steps between them are `--check` runs that write nothing to `dist/`.
Add a guard test so the chain compiles TypeScript exactly once and both
checks still run after it.

**Alternatives considered**

- Skip the server's `prepare:runner-vendor` rebuild when `pnpm -r build`
already built the Runner. That rebuild is what makes `pnpm --filter
@paperclipai/server build` correct standalone (the Dockerfile uses it),
and the server's build-script test pins the command. A freshness check
would be a larger semantic change; this PR shrinks the rebuild instead
of removing it, and the next cycle can measure what remains.
- Make `tsc` incremental across the passes. It would still re-run the
schema checks and the eval-kernel build each time, and would add
build-info files to the package.
- Change `check:semantic-contracts` and
`check:runner-workflow-traceability` themselves to stop rebuilding. They
are documented standalone commands (`pnpm --dir
packages/paperclip-runner check:semantic-contracts` in the capability
docs) and must work from a stale dist; unchanged here.

## What Changed

- `packages/paperclip-runner/package.json`: the `build` script runs
`node scripts/generate-semantic-contracts.mjs --check` and `node
scripts/check-runner-workflow-traceability.mjs` directly, after its own
`build:typescript`, instead of the `check:semantic-contracts` and
`check:runner-workflow-traceability` wrappers that rebuild first. Every
other step, its order, and the standalone `check:*` scripts are
unchanged.
- `server/src/__tests__/server-package-build-script.test.ts`: a new test
in the suite that already pins the server's Runner vendoring reads the
Runner's `build` script, resolves every `pnpm run` step, and asserts
that exactly one step compiles TypeScript (directly or through a
wrapper), that both check scripts are in the chain, and that both come
after `build:typescript`. It fails against the previous script with
`expected [ 'build:typescript', …(2) ] to deeply equal [
'build:typescript' ]`.

## Verification

- `pnpm --filter @paperclipai/server exec vitest run
src/__tests__/server-package-build-script.test.ts`: 9 pass (1 new). With
the `package.json` change stashed, the new test fails as described above
and the other 8 pass.
- In `packages/paperclip-runner`, the new chain without the cargo step
(`check:protocol-manifest`, `build:typescript`,
`check:capability-contract`, `check:capability-inventory`,
`check:protocol-coverage`, `generate-semantic-contracts.mjs --check`,
`check-runner-workflow-traceability.mjs`, `generate-replay-goldens.mjs
--check`, `generate-semantic-action-catalog.mjs --check`) exits 0:
`Runner stress traceability passed: 44 findings, 12 workflows, 1
explicit exclusion.` and `Replay golden snapshots and parity summaries
are current.` Cargo is not installed on the host that produced this PR,
so `build:binary` was not run locally; it is unchanged and runs in this
PR's `Build` job.
- `pnpm run build:typescript` alone takes 5.8s to 5.9s on this host, so
each removed pass is in the range the CI logs show.
- This PR's own `Build` job runs `pnpm build` from the branch checkout,
so its log shows the new chain in both Runner builds. Expected on that
job: `pnpm build` about 130s to 146s (was 160s to 176s on the four
measured runs), `Build` about 505s to 551s (was 535s to 581s).

**Measured on the four post-#15849 `master` runs that motivated this
PR** (`Build` job logs):

| Run | `pnpm build` | Runner build in `pnpm -r build` | Extra
`build:typescript` passes in it | Runner rebuild in server build | Extra
passes in it |
| --- | --- | --- | --- | --- | --- |
| 38112764439 | 169s | 76s | 04:51:52 and 04:52:00 (about 14s) |
04:53:12 to 04:53:41 | 04:53:26 and 04:53:34 (about 15s) |
| 38111191543 | 176s | 79s | 04:22:40 and 04:22:48 (about 14s) |
04:24:04 to 04:24:34 | 04:24:18 and 04:24:26 (about 15s) |
| 38110914319 | 160s | 75s | 04:19:07 and 04:19:14 (about 14s) |
04:20:25 to 04:20:53 | 04:20:39 and 04:20:46 (about 14s) |
| 38110897745 | 172s | 80s | 04:15:16 and 04:15:25 (about 15s) |
04:16:41 to 04:17:11 | 04:16:55 and 04:17:03 (about 15s) |

## Risks

- Low risk. The same two checks run against the same dist, in the same
position in the chain. The only difference is that the dist is not
rewritten twice between them.
- If a future step between `build:typescript` and the two checks starts
writing to `dist/`, the checks would read that output instead of a fresh
rebuild. The steps there today (`check:capability-contract`,
`check:capability-inventory`, `check:protocol-coverage`) are `--check`
runs that only compare generated spec files.
- The standalone `check:semantic-contracts` and
`check:runner-workflow-traceability` scripts still rebuild first, so
documented usage is unchanged.
- The guard test lives in the server's suite because that suite already
pins the Runner vendoring contract and runs in the server shards on
every PR.

## Model Used

- Claude (Anthropic), model ID `claude-fable-5-1`, running as a
Paperclip agent through the Claude local adapter with tool use (shell,
file edits, GitHub CLI). The agent collected the CI data, made the
change, ran the tests, and wrote this description.

## Checklist

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

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

Co-authored-by: devinfoley <139239+devinfoley@users.noreply.github.com>
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-10 22:27:38 -07:00
Devin FoleyandPaperclip b36960b758 fix(server): permit verified question-delivery history to sleep (#15851)
Treat completed question-response deliveries as history only after their exact same-company handoff finishes. Preserve missing evidence, retries, accounting debt, and idle-sleep fences.

Add a concurrent all-state question history index with interrupted-build repair. Keep migrations serialized without waiting snapshots that deadlock concurrent index builds.

Validated by 118 focused sleep tests, six migration/snapshot tests, full repository typecheck, all CI gates, and Apex 5/5.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-10 21:47:55 -07:00
Devin FoleyandPaperclip 07f3536e37 fix(connections): discover Sentry OAuth through its MCP resource (#15837)
Correct Sentry OAuth discovery and cover new and saved client registration.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-10 17:10:23 -07:00
DottaandPaperclip a7dd5284b5 feat: add company fast-response acknowledgements (#15748)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Human messages start agent work through task, chat, and
external-channel intake.
> - Agent startup can delay the first visible response.
> - A small direct model call can acknowledge the request while normal
work starts.
> - This response must remain separate from evidence that the agent
answered or completed work.
> - This pull request adds optional company-wide fast responses with
durable receipts, access checks, and cost accounting.
> - Users receive prompt acknowledgement without changing the agent
execution path.

## Linked Issues or Issue Description

**Subsystem affected**

Cross-cutting: database, shared contracts, server orchestration,
connections, and UI.

**Problem or motivation**

Users can wait for an agent to start before they receive a contextual
response. Generic progress messages do not confirm what the user asked.
An acknowledgement must not falsely complete work or satisfy an
unanswered turn.

**Proposed solution**

Add a disabled-by-default experimental fast-response model using an
existing shared API connection. Generate one short acknowledgement for
each accepted human turn. Use the existing agent identity and external
publication outboxes. Retain platform provenance and account for the
inference independently.

**Alternatives considered**

Running the acknowledgement through the agent runtime adds startup
latency. Restricting implementation to OpenRouter leaves other existing
API connections unsupported. This change supports all existing API
connections and uses OpenRouter for live verification.

**Roadmap alignment**

This extends existing agent communication and connection settings.
ROADMAP.md and open pull requests were checked. No duplicate
fast-response implementation was found. The maintainer supplied the
feature plan directly.

## What Changed

- Add Experimental fast responses to instance settings. Keep the feature
off by default. Enforce the flag at intake, dispatch, and publication.
- Move Decision model and Fast response setup to company Settings →
Connections when the experiment is enabled. Place Connections below
Environments. Separate the model sections with clear headings and a
divider. Keep Decision model in General when the experiment is off.
Route Costs setup links to the available settings page.
- Make the acknowledgement prompt a multiline template string. Ask for a
brief, positive response in the user’s language.

- Add settings, connection/model selection, sponsorship, fixed-sample
testing, and Costs history.
- Add a Vercel AI SDK text service for existing native, routed, Bedrock,
and local API connections.
- Add durable per-turn requests, a bounded worker, a three-second
admission deadline, and one inference attempt.
- Integrate task creation, task and agent chat, steering, queued
follow-ups, experimental board chat, shared chat intake, and email.
- Preserve receipt provenance and exclude receipts from completion,
recovery, interaction resolution, and agent wakeups.
- Recheck authorization, source validity, real replies, budgets, and
destination binding before publication. Preserve accounting for
suppressed or uncertain outcomes.
- Add provider contracts, database race tests, channel outbox tests, UI
tests, Stories, and documentation. Keep decision-model execution
unchanged.

## Verification

- Local `pnpm -r typecheck`, `pnpm build`, and UI token gates pass after
rebase. The UI typecheck and build also pass after the final navigation
fixes. All 37 focused navigation tests pass. The first full local `pnpm
test:run` invocation reported seven chat failures. All seven passed in
isolated reruns after fixture updates and host cleanup. This invocation
was stopped after the full final-head CI suite passed.
- Initial local database tests hit macOS shared-memory exhaustion. A
diagnostic confirmed `shmget: No space left on device` with the system
limit of 32 IDs. Three abandoned, unattached PostgreSQL IPC headers were
reclaimed. The isolated rerun passed all 31 fast-response and channel
tests. The two additional Slack regression cases also passed in a
separate rerun. No active database was stopped.
- UI token gates pass. Provider contract tests cover all supported API
connection types. Fast-response tests cover uniqueness, authorization,
budgets, expiry, cancellation, restart, real-reply races, and the
experimental flag.
- The test drive verified that disabling the experiment hides
Connections and redirects its direct URL. Enabling it restores the saved
OpenRouter setup. After restart on the final commit, the OpenRouter
settings sample returned “Sure, I’ll take care of fixing the border
around the settings panel.” in 428 ms. It used 260 input and 31 output
tokens and recorded $0.0000576 in reported cost.
- Earlier live OpenRouter verification produced a receipt in 1.013
seconds for a new task. The real agent then supplied its substantive
answer. A separate settings test took 1.34 seconds, used 246 input and
23 output tokens, and recorded $0.0000361.
- Live Slack verification on final commit
`24016fa525961ebc7a4acffdc5019ce123970549` passed for a fresh initial
task and a follow-up in a disposable bot DM. The initial acknowledgement
appeared 2.405 seconds after the Slack message and 1.413 seconds after
durable acceptance; the follow-up appeared in 2.322 seconds and 1.160
seconds respectively. The recorded generation/settlement durations were
898 ms and 697 ms. The initial call used 291 input / 39 output tokens
and cost $0.00006705; the follow-up used 281 / 47 and cost $0.00007035.
- The Slack acknowledgements retained the assigned agent identity and
`origin: fast_response`, source-turn references, and no fabricated run
ID. A status snapshot after the initial receipt showed the task still
`in_progress` with its real execution run. The agent then read the CSV
fixture and correctly reported two ready items, two blockers, and their
owners. Both replies stayed in the originating DM, and no duplicate
generic working message followed the delivered contextual
acknowledgements. The `new` command started a fresh conversation session
without generating a fast response.
- An earlier eligible Slack turn generated a response but suppressed
publication. Its reported cost was retained, generic progress remained,
and the real agent completed the requested result. This is recorded
separately from the two delivered acknowledgements; the history did not
expose a precise suppression reason.
- Slack verification used real signed provider events, the existing
intake/publication paths, and a user-approved temporary webhook-only
HTTPS tunnel. Subscriptions were limited to direct-message events. The
test bot was paused and the tunnel stopped afterward. Live
channel/group-thread and GitHub journeys remain unverified; their mocked
tests cover intake, destination binding, publication, and continued
underlying work.
- Greptile reviewed final commit
`24016fa525961ebc7a4acffdc5019ce123970549` at 5/5. Both new review
findings are fixed and all threads are resolved. [Final-head CI
run](https://github.com/paperclipai/paperclip/actions/runs/38060015730)
passed. This includes grouped server/chat/workspace tests, serialized
suites, runner checks, browser journeys, typecheck, build, release
registry, policy, and the canary dry run.
- Manual check: enable Experimental fast responses. Open company
Settings → Connections. Select a shared API connection and model. Save
and use Test response. Submit a task message and confirm that its
receipt does not complete the task.

## Risks

- The migration adds receipt and configuration tables plus accounting
references. It uses idempotent statements and follows the current
migration sequence.
- A slow provider, authorization change, or real-agent reply can
suppress an acknowledgement. Existing progress feedback remains
available.
- Unknown provider billing retains a reservation until reconciliation.
External deliveries with uncertain outcomes must not be blindly
repeated.
- Live Slack initial-task and follow-up DM journeys pass. Live Slack
channel/group-thread and GitHub journeys remain unverified. The PR
remains a draft and records these gaps. Final-head repository CI and
automated review pass.

## Model Used

OpenAI Codex, based on GPT-6, with reasoning, repository tools, code
execution, and browser interaction. The runtime does not expose an exact
model snapshot ID or context-window size; these are not asserted.

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-10 13:09:17 -05:00
lorenzozane 0e37a385e6 fix(pi-local): avoid embedding model catalogue in errors (#13628)
<!-- Write all pull request text in Simplified Technical English
(ASD-STE100): short sentences, one instruction per sentence, simple
approved vocabulary, and the active voice. -->

## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - The pi-local adapter discovers and validates models before it starts
a local Pi process
> - An unavailable-model error included model IDs from the discovered
catalogue
> - Repeating those IDs made persisted and rendered failures noisy and
exposed substitute choices
> - This pull request keeps the requested model, reports the available
count, and points to the existing lookup command
> - The benefit is a concise error without changing model discovery or
matching

## Linked Issues or Issue Description

Fixes #13612

## What Changed

- Replace model catalogue interpolation in unavailable-model errors with
the requested model, normalized model count, and `pi --list-models`.
- Add a regression test with 13 discovered models and exact
error-message matching.

## Verification

- `pnpm exec vitest run
packages/adapters/pi-local/src/server/models.test.ts`
- `pnpm exec vitest run packages/adapters/pi-local/src/server/*.test.ts`
- `pnpm --filter @paperclipai/adapter-pi-local typecheck`
- `git diff --check`

All listed checks pass locally. The test suite uses a temporary Pi
executable and verifies that model IDs are not appended to the error.

## Risks

Low risk. Only unavailable-model error wording changes. Model discovery,
matching, valid model execution, and failure handling remain unchanged.
Full repository CI was not run locally because the host uses Node
22.22.1 and the repository declares Node >=24.11.0.

> For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and
discuss it in `#dev` before opening the PR. Feature PRs that overlap
with planned core work may need to be redirected — check the roadmap
first. See `CONTRIBUTING.md`.

## Model Used

OpenAI GPT-5.6 Luna (`gpt-5.6-luna`); tool-assisted code execution. The
context window size is not exposed in this session.

## Checklist

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

> - Paperclip is the open source app people use to manage AI agents for
work
> - Paperclip adapters start each agent in its selected workspace
> - Paperclip can realize a different workspace path for local and
remote runs
> - The OpenCode CLI prefers its inherited `PWD` when no `--dir` option
is present
> - The process `cwd` option does not update the inherited `PWD` value
> - This pull request passes the realized workspace to OpenCode with
`--dir`
> - The benefit is that OpenCode sessions and tools use the workspace
that Paperclip selected

## Linked Issues or Issue Description

No matching issue exists.

Refs #8287. That earlier pull request describes the realized remote
workspace path. It does not make the OpenCode CLI use that path.

I searched open and closed issues and pull requests for `opencode
--dir`, `opencode cwd PWD`, and `opencode workspace directory`. I found
no duplicate.

**What happened?**

Paperclip gives the OpenCode process the correct operating system `cwd`.
However, the adapter does not pass OpenCode's `--dir` option. OpenCode
uses `process.env.PWD` before `process.cwd()` when `--dir` is absent. A
server `PWD` that differs from the realized workspace can therefore
place the OpenCode session and its tools in the wrong directory.

**Expected behavior**

OpenCode must use the workspace that Paperclip realized for the run. An
explicit `--dir` in `extraArgs` must remain valid and must not be
duplicated.

**Steps to reproduce**

1. Start the Paperclip server from directory A.
2. Configure an OpenCode agent with directory B, or realize directory B
on a remote execution target.
3. Start a run without a manual `--dir` value in `extraArgs`.
4. Inspect the OpenCode session directory or run a directory-sensitive
tool.
5. Before this change, OpenCode can use directory A from the inherited
`PWD`.
6. After this change, OpenCode receives `--dir B`.

**Paperclip version or commit**

`b38d6ddb811b3ff3145ff5df60174eb9e7313fe6`

**Deployment mode**

Self-hosted server. The same adapter path is used in local development
and remote execution.

**Installation method**

Built from source.

**Agent adapter(s) involved**

OpenCode.

**Database mode**

Not database-related.

**Additional context**

OpenCode v1.17.13 defines `--dir` and uses the inherited `PWD` as its
fallback root. See the [OpenCode run command
source](https://github.com/anomalyco/opencode/blob/10c894bdeef3618f5666fb506ef7f9491bb964d8/packages/opencode/src/cli/cmd/run.ts#L333-L339).

## What Changed

- Add the realized execution workspace as `--dir` for OpenCode runs.
- Preserve an explicit `--dir` or `--dir=...` value from `extraArgs`.
- Stop option detection at the first `--` terminator.
- Extend the remote execution tests for realized, explicit, and
post-terminator directory arguments.

## Verification

- `pnpm exec vitest run packages/adapters/opencode-local/src` passed: 7
files and 40 tests.
- `pnpm --filter @paperclipai/adapter-opencode-local typecheck` passed.
- `pnpm --filter @paperclipai/adapter-opencode-local build` passed.
- `pnpm -r typecheck` passed for all 31 selected workspace projects.
- `pnpm build` passed for all selected workspace projects.
- `git diff --check` passed.

I also ran `pnpm test:run`. It completed with 334 test files passing and
2 test files failing. It reported 3,790 passing tests and 4 skipped
tests. The two failures are in `issue-monitor-scheduler.test.ts` and
`workspace-runtime.test.ts`. Each failure reproduces on the unchanged
base commit after this pull request is removed. Neither test imports or
covers the OpenCode adapter.

## Risks

- The behavior change is limited to OpenCode run arguments.
- A custom old OpenCode binary that does not support `--dir` will reject
the option. The current official OpenCode v1.17.13 CLI supports it.
- An explicit operator `--dir` remains authoritative. The adapter does
not add a duplicate option because OpenCode's parser converts repeated
string options to an array.
- This change does not modify schemas, migrations, APIs, telemetry, or
user data.

> For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and
discuss it in `#dev` before opening the PR. Feature PRs that overlap
with planned core work may need to be redirected — check the roadmap
first. See `CONTRIBUTING.md`.

## Model Used

OpenAI Codex based on GPT-5. The runtime did not expose a more specific
model ID or context-window size. The agent used high-depth reasoning,
repository access, shell execution, and GitHub tools.

## Checklist

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

Co-authored-by: commitperclip-bot <305974387+commitperclip-bot@users.noreply.github.com>
2026-10-10 10:46:21 -05:00
DottaandPaperclip d6e6d1c78a Stream OpenCode immediately, scope reasoning to turns, and deduplicate instructions (#15708)
## Thinking Path

> - Paperclip helps people manage AI agents and observe their work.
> - The native runner carries provider output into the task transcript.
> - OpenCode sends incremental text in `message.part.delta` events.
> - The driver ignored those events and waited for a full part snapshot.
Accepted chats also waited after lifecycle verification was complete.
> - This pull request forwards each valid chunk as it arrives and
removes unnecessary isolated startup work.
> - Valid chunks reach Paperclip sooner without changing completion or
permission rules. The matched browser experiment below does not
establish a reliable end-to-end latency improvement.

## Linked Issues or Issue Description

**What happened?**

The native OpenCode driver withheld text until OpenCode sent a full
snapshot. A local delayed-provider probe with the pinned OpenCode
1.18.34 runtime showed a 1,496 ms gap between the first native text
delta and the first Paperclip text delta (1,510 ms from provider text).

**Expected behavior**

Forward valid assistant text and reasoning deltas immediately. Preserve
repeated identical tokens, message roles, turn ownership, and final
response selection.

**Steps to reproduce**

Send an empty text part, then text deltas, and withhold the final full
snapshot. The new fixture requires the consumer to acknowledge its first
text delta before releasing the snapshot. The previous driver cannot
pass this handshake.

**Paperclip version or commit**

Baseline: `011e5669bad61c435a4745fb10812bef70376841`. The patch is
rebased onto current master.

**Deployment mode**

Local native OpenCode 1.18.34 on macOS arm64. Live diagnostics use
`openrouter/deepseek/deepseek-v4-flash-0731`. These are narrow
diagnostics, not full Product E2E qualification.

## What Changed

- Keep the macOS verified OpenCode launch pathname until child exit,
with guarded reuse and cleanup on failed launches. This fixes a
reproduced asynchronous executable-lifetime failure.
- Dispatch accepted queued chats immediately after lifecycle readiness
commits, through normal scheduler admission. Preserve ready state if
dispatch fails.
- Validate native OpenCode model access with the real hello probe
without a redundant catalog scan. Keep legacy adapter discovery
unchanged and isolate unspecified native probe directories.
- Map incremental text and reasoning to the existing canonical event
path, using observed part and message identities.
- Keep additive chunks without IDs distinct. Preserve ID-based event
deduplication.
- Clear current streaming part metadata when a new turn starts. Reject
mismatched session/message identities and unknown parts or fields.
- Disable automatic updates, remote model refreshes, and default plugins
in each isolated OpenCode process. Keep assigned MCP tools and default
model reasoning intact.
- Retain the latest cumulative text/reasoning part while its message
role is unknown, including completion metadata after more than 100
chunks.
- Expose `startTurn({ message, reasoningMode: "disabled" })` for one
OpenCode/OpenRouter turn. Carry the selection in the durable command
through Rust and the proxy. An omitted/default option restores provider
defaults on the next turn, including warm and recovered sessions. There
is no environment-level setting or automatic selection policy.
- Group optional Rust turn inputs in `CodexTurnOptions` and dispatch
through `start_turn_with_options`; retain `start_turn` for defaults.
Future turn settings can be added without another feature-specific
method.
- Expose a native-session capability for per-turn reasoning and reject
explicit unsupported selections before dispatch, including direct ACPX
and Codex backends. Runnerd checks the durable selected model as well as
the provider.
- Remove duplicate agent instructions from the shared OpenCode proxy
task envelope for all users. Send one system copy on every turn,
including prepared and resumed turns, because OpenCode reads the latest
user message’s system field. Preserve task constraints and completion
contracts.
- Document startup and streaming behavior. Add regression coverage for
role ordering, repeated chunks, final snapshot deduplication, and stale
turns.

## Verification

### Lower-load browser retry — 2026-10-10

**All 8/8 trials succeeded. In this batch, median Send → first visible
reply fell from 30.586 s to 12.476 s (59.2% lower).** Four fresh-agent
trials per variant, phase order before/after/after/before with two
trials per phase. Every adjacent-phase pair favored the candidate,
although one difference was only 0.301 s. This is evidence for the
readiness/probe changes on this host, not a production percentile or a
guarantee across providers.

| Phase/trial | Variant | Send → reply (s) | Observed ready → run (s) |
Session open → turn start (s) | Model requests |
|---|---|---:|---:|---:|---:|
| 0/0 | before | 45.042 | 25.337 | 3.629 | 2 |
| 0/1 | before | 13.689 | 0.000 | 2.443 | 2 |
| 1/0 | after | 14.696 | 0.000 | 2.526 | 1 |
| 1/1 | after | 13.389 | 0.000 | 2.470 | 2 |
| 2/0 | after | 10.871 | 0.000 | 2.706 | 2 |
| 2/1 | after | 11.564 | 0.004 | 2.443 | 2 |
| 3/0 | before | 41.582 | 21.518 | 2.376 | 2 |
| 3/1 | before | 19.589 | 9.753 | 2.707 | 1 |

Observed ready-to-run median: **15.636 s → 0 s**; zero means execution
began by the first ready observation, not literally zero latency.
Polling interval is nominally 250 ms plus HTTP time.
Session-open-to-turn-start includes controller handling, not just child
startup. All eight ran within the existing startup timeouts; no timeout
or reasoning policy was changed. Host load at fixture creation stayed
**5.47–8.73 on 18 CPUs**, versus 68.9–100.8 in the prior campaign. No
builds/tests ran concurrently with measurement.

Same merged source **b0a0158729a7913882a0e756fe7e27228d72bf53**, release
runner, rebuilt static UI, OpenCode **1.18.34**, model
**openrouter/deepseek/deepseek-v4-flash-0731**, provider-default
reasoning, and empty isolated workspaces in both variants. Only the
readiness worker and explicit-model verification source were toggled;
the launch-lifetime fix and all proxy streaming changes were held
constant. Thus this does not separately measure the original streaming
changes. One browser per phase, two fresh companies/agents/chats per
phase. Measurement begins at capture-phase Send click and ends on
visible Hi text plus two animation frames. Status/thinking is excluded;
emoji can arrive just after the first text. Successful screenshots
inspected. Each variant had three two-request turns using
`paperclip_finish` and one one-request turn; no status lookup was
observed. Reported usage includes settlement after the first visible
reply.

Runner SHA-256
`57f658c220eecd2370ffd3333cd7e5d06d16bb2798af0cf43c84e01c8207c1c3`;
proxy
`bcc02fda2bf35b38a116cd880841aa6c534f6e0b497a96d97369a1e06dcc72ac`;
rebuilt UI tree
`eee238f2eda628c4e8c3660707986da4f8dd9100c814e26938fce3756df2eae4`
(sorted relative path, NUL, binary per-file SHA-256). Worker/probe
variant source hashes are unchanged from the preserved comparison below.
Measured turn cost **$0.00612574**, plus verification probes not
included in that figure. All eight attempts retained; all source/proxy
files restored and test supervisors exited.

Current commit validation: **53 successful CI checks, 4 skipped, zero
failing; Greptile 5/5 on b0a0158729 with no actionable findings.** The
previous 20 targeted post-merge tests passed. No source edit was made
for this rerun. Earlier failed and inconclusive cohorts below remain
historical evidence and are not pooled with this batch.


### Master update and failure diagnosis — 2026-10-09

Merged `origin/master` at `417db14e7d` into this branch without
conflicts; pushed merge commit
`b0a0158729a7913882a0e756fe7e27228d72bf53`. The incoming changes do not
alter OpenCode process startup or its timeout budgets. Historical
measurements below remain attributed to their original commits.

The four last-campaign failures never issued `turn.start`, so these were
**cold-session admission failures, not model replies failing**. Two
retained `session.open` commands eventually completed after controller
timeout/cleanup had begun. The other two ended with the inner
`thread/start` response timeout, and their diagnostics recorded OpenCode
startup retries. Startup event timestamps are buffered publication times
and must not be interpreted as exact process-spawn times.

On the merged source, two credential-free startup-only checks used the
real pinned OpenCode 1.18.34, empty temporary workspaces, a placeholder
key, and **no model turns**:

- Existing pinned executable: spawn at 1.083 s; failed health
attempt/retry at 11.311 s and 21.914 s; third process healthy at 32.210
s; session opened at **35.168 s**.
- Verified private executable path: snapshot preparation took **0.497
s**; process spawned at 1.588 s; healthy at 9.967 s; session opened at
**11.120 s**.

These are sequential diagnostic samples, not evidence that one
executable path is faster. Host load was **56.5–64.5 on 18 logical
CPUs**. The local health wait permits 10 s per attempt and the driver
retries up to three times; the outer controller's cold admission budget
is 30 s, and the Rust facade also waits 30 s for a response. Thus
retries plus setup/session creation can outlast the caller's budget. The
isolated 35.168 s success demonstrates that a session can eventually
open yet fail the app's admission deadline. Heavy load aggravates the
timing; its exact contribution is not isolated. No timeout was increased
and no new model-latency claim is made.

Merge validation: **20/20 targeted lifecycle-policy and heartbeat
run-completion tests passed**, including temporary PostgreSQL cases. The
first sandbox invocation skipped database cases; the authorized local-DB
rerun executed all 20. The package-manager launcher could not verify its
version via the unreachable registry, so validation used the
already-installed Vitest binary. Full CI/review subsequently passed on
this merge commit; see the October 10 retry above. Older results below
apply to their named commits.


### Follow-up: reproduced macOS launch failure — 2026-10-09

The retry exposed a startup bug rather than only host-load noise. The
macOS proxy deleted the private verified executable path immediately
after asynchronous spawn. A credential-free test of the actual pinned
OpenCode `--version` reproduced a fast SIGKILL and a 15-second timeout
in three immediate-cleanup attempts; three deferred-cleanup controls
succeeded. The timeout was killed by the diagnostic's own deadline. This
experiment does not establish the OS-internal reason for the fast
SIGKILL.

Commit `c30451e0ebf3f74e9ef70d37bbe4d9fe7fb56359` retains the private
launch path until child exit, cleans failed spawns, and waits for forced
shutdown before reuse. Source descriptor authentication, ownership,
mode, inode checks, and the prohibition on ambient executable fallback
remain. Overlapping reuse fails closed. The existing synchronous shell
test was changed to exercise the actual asynchronous boundary.

**Verification:** 59 focused proxy/driver tests passed; runner
TypeScript check passed. All six subsequent real OpenCode version
launches succeeded without timeout (4.11, 4.33, 5.73, 6.91, 4.95, 6.70
seconds). The native Rust binary is unchanged from the retry; no model
calls were made by these diagnostics.

Retained interrupted retry: before 42.56/18.69 seconds; after one
180-second timeout (`provider_process_exited` / health SIGKILL) and one
37.33-second success. The latter overlapped the credential-free
diagnostic and is not a clean matched timing. The next phase was stopped
before Send to diagnose the reproduced bug. Reported measured-turn cost:
$0.0016874, verification probes additional. These attempts are not
pooled with other campaigns.

<!-- launch-fixed-proof:start -->
**Completed retry, stopped by the declared failure rule after 6 of 8
planned trials. No reliable end-to-end speedup demonstrated.** At commit
`c30451e0ebf3f74e9ef70d37bbe4d9fe7fb56359`, the launch fix above was
held constant in both variants; only the readiness handoff and
explicit-model verification path changed. Planned phase order:
before/after/after/before, two fresh agents/chats per phase, one new
browser per phase. The second after phase had two consecutive failures,
so the final before phase was not run.

| Phase/trial | Variant | Send → first visible reply | Observed ready →
run | Outcome |
|---|---|---|---|---|
| 0/0 | before | No reply within 180 s | 2.777 s | session.open timeout
|
| 0/1 | before | 47.654 s | 9.383 s | Succeeded |
| 1/0 | after | 50.051 s | 0.087 s | Succeeded |
| 1/1 | after | No reply within 180 s | 0.151 s | session.open timeout |
| 2/0 | after | No reply within 180 s | 3.337 s | session.open timeout |
| 2/1 | after | No reply within 180 s | 1.434 s | session.open timeout |

Both successful screenshots show “Hi 👋”. Timing starts at the browser's
capture-phase Send click and ends at the first visible answer text plus
two animation frames; the first fragment can be “Hi” before the emoji
arrives. Thinking/status text is not counted. All four failures were
`runner_local_connect_failed: PRP command session.open timed out`
(`native_session_interrupted`), before a reply; none reported the
earlier health-stage SIGKILL. They are retained, not discarded as
outliers. One success per variant does not support a speedup estimate or
median comparison. Observed ready-to-run median was **6.080 s before
(n=2) vs 0.793 s after (n=4)**; this is sampled every nominal 250 ms
plus HTTP latency and is a lower bound, not precise tracing. Host load
at fixture creation ranged **68.9–100.8 on 18 logical CPUs**, a
substantial confound that worsened over the campaign. No local
build/test was run concurrently with this campaign.

Provenance: pinned OpenCode **1.18.34**, model
**openrouter/deepseek/deepseek-v4-flash-0731**, default reasoning in
both variants, empty synthetic workspaces and isolated probe homes.
Release runner SHA-256
`57f658c220eecd2370ffd3333cd7e5d06d16bb2798af0cf43c84e01c8207c1c3`;
current proxy SHA-256
`bcc02fda2bf35b38a116cd880841aa6c534f6e0b497a96d97369a1e06dcc72ac`;
built UI tree SHA-256
`7f0c2b7f586cb753408351574b2239e22311944add99af4f6f3562cd6d47bbcb`. This
holds the rebuilt runner and static UI constant. Provider-reported
measured turn cost **$0.00120649**; verification probes are additional.
Including the earlier interrupted retry, this follow-up reports
**$0.00289389** in measured turn usage; missing usage is not assumed
free. Prior cohorts remain separate below.

Validation on `c30451e0e`: **59 focused tests passed**, runner
TypeScript check passed, **6/6 real credential-free pinned OpenCode
launches passed**, fresh Greptile **5/5 with zero unresolved threads**.
CI: **51 success, 4 skipped, 1 failed**. The failed native compilation
job never reached compilation: Docker's auth endpoint timed out during
Buildx setup, then failed the same way on one retry
([job](https://github.com/paperclipai/paperclip/actions/runs/37994181674/job/114039737503)).
Full local checks were not rerun while measuring. The PR remains draft:
the launch defect is reproduced and fixed, but cold session startup
still exceeds the controller's admission budget on this host. Raising
that budget would not establish a faster first response.
<!-- launch-fixed-proof:end -->

### Readiness investigation and live rerun — 2026-10-09

**Measured queue fix; no reliable end-to-end speedup claim. Keep this PR
in draft.** Accepted chats could wait for the periodic queue sweep after
verification had already committed `ready`. The lifecycle worker now
dispatches through the existing scheduler immediately after that commit.
The normal company, pause, budget, concurrency, and task-ownership
checks still apply. Dispatch failure preserves readiness and leaves
recovery to the queue sweep.

Native OpenCode verification also avoids enumerating the full model
catalog before running its real hello request. Identifier validation
remains. Authentication failures, unavailable models, and timeouts still
prevent readiness. An unspecified local probe directory uses an empty
temporary directory.

**Queue-only experiment:** four before and four after attempts, in
before/after/after/before server phases, two fresh agents per phase.
Median observed ready-to-start delay fell from **19.429 s to 0.058 s**.
State polling was nominally 250 ms plus HTTP time, so the latter means
within observation resolution; it is not a precise 58 ms latency claim.
After timings were 100.20, 65.29, 63.78, and 76.97 seconds. Before had
one 59.65-second success and three 120-second response timeouts (one
provider health SIGKILL, one late success, one still running after
settlement and canceled). These censored results do not support a
success-only median speedup comparison. Focused tests overlapped the
last baseline phase, which further limits total-time interpretation.
Reported measured-turn cost: $0.0055383; verification probes and
incomplete/canceled usage are additional.

**Final matched experiment:** built static UI in both variants to avoid
pre-Send Vite compilation; current proxy, release runner, selected
model, default reasoning, and explicitly isolated empty probe
cwd/HOME/XDG held constant. Both worker handoff and model-probe changes
vary. Fresh browser/company/agent/chat per attempt. ABBA order, two
attempts per variant, 180-second response limit declared before the
batch, four-turn bound. Same Send-to-rendered-Hi metric as the earlier
experiment.

| Order | Variant | Send → visible Hi | Created → execution | Observed
ready → execution | Outcome |
| --- | --- | ---: | ---: | ---: | --- |
| 1 | Before | 62.66 s | 23.467 s | 2.830 s | Succeeded |
| 2 | After | >180 s | 14.200 s | Within polling resolution | Provider
health SIGKILL |
| 3 | After | >180 s | 13.877 s | Within polling resolution | Provider
initialization timeout |
| 4 | Before | >180 s | 144.256 s | 14.067 s | Still running after
settlement; canceled |

Only one of four attempts produced a timed reply. **There is no valid
overall speedup estimate from this batch.** The dispatch delay is
removed, but provider startup failures and heavy shared-host load
remain. A recorded host sample was load 93.55 on 18 logical CPUs. This
is a confound, not proof that every failure was caused by host load.
Provider-reported measured-turn cost was $0.00032752, with no reported
usage for the other three attempts; verification probes are additional.

Retained earlier setup attempts: one shared-memory startup failure
before model calls, and a separate development-UI batch with a
60.06-second baseline followed by a navigation timeout before Send.
These attempts are retained separately, not counted as successful
response timings. No live attempts were silently dropped.

Provenance: source base `53580f8fbd40b963f3fb7ba5172ff3ede2e9ef1f`,
measured patch committed as `40b54eafb`, then rebased as
`c590770dcc2bb1debce14037935a7031e5c3c1ac`. **These live timings predate
the rebase.** Source and binary hashes are retained below. The inner
harness label `after` selects the identical current proxy in every
attempt; the outer campaign handoff label is the actual before/after
variant. Owned benchmark processes stopped and original proxy restored.

<!-- readiness-check-status:start -->
Post-rebase validation at `c590770dcc2bb1debce14037935a7031e5c3c1ac`:

- Full local `pnpm -r typecheck`: **passed**, including the native
release build (1,098.6 seconds on the loaded host).
- Focused lifecycle and adapter tests: **26 passed**. The 14 database
integration tests did not run locally because their hard-coded 20-second
database setup hook timed out. A retry with a CLI timeout override
encountered the same explicit hook limit. The earlier pre-rebase focused
batch passed 77 tests; these results are not substituted for post-rebase
execution.
- Local `pnpm test:run` was started, then stopped to avoid duplicating
CI on the saturated host. Local `pnpm build` was not run separately.
**Current-head CI passed Typecheck + Release Registry, Build, all
general and serialized test groups, Rust checks, both runner Vitest
groups, and all eight browser E2E shards.** The last general shard
passed 1,179 tests (72 files).
- Fresh [Greptile
review](https://github.com/paperclipai/paperclip/pull/15708#issuecomment-6085742217):
**5/5**, reviewed this exact head, no actionable defect.
- Final CI rollup: **49 success, 4 skipped, 4 failure**. The failures
are [Compile isolated native
Runner](https://github.com/paperclipai/paperclip/actions/runs/37990274515/job/114024329242),
[Docker context
integrity](https://github.com/paperclipai/paperclip/actions/runs/37990274623/job/114024196511),
[Canary Dry
Run](https://github.com/paperclipai/paperclip/actions/runs/37990274623/job/114024196424),
and the dependent `ci / verify` aggregate. All three root failures are
Docker Hub HTTP 429 / unauthenticated pull-rate limits while fetching
Node base images. The native-image job was retried once and hit the same
limit. No source compiler/test failure was reported by those gates. CI
maintainers need authenticated pulls or to rerun after the registry
limit clears.
- Owned benchmark servers stopped. Local validation commands completed
or were stopped. The PR remains a draft: user-visible speed/reliability
is not qualified, and the Docker-dependent CI gates are not green.
<!-- readiness-check-status:end -->

<details><summary>Sanitized readiness evidence with all attempts and
source hashes</summary>

```json
{"campaign":{"order":["before","after","after","before"],"trialsPerPhase":1,"maxMeasuredTurns":4,"maxCampaignUsd":1,"sourceHead":"53580f8fbd40b963f3fb7ba5172ff3ede2e9ef1f","reasoning":"provider default, no override","proxySha256":"6691475ed55f10179ec6ee0023a1f6462982f763848da7cd5b1d0baf38633b04","purpose":"Final matched comparison of both optimizations; distinct from earlier queue-only campaign.","responseTimeoutMs":180000,"timeoutRationale":"Declared before this final campaign because earlier unchanged baselines sometimes exceeded 120 seconds; earlier timeouts remain retained.","ui":{"mode":"built static UI","treeSha256":"7f0c2b7f586cb753408351574b2239e22311944add99af4f6f3562cd6d47bbcb"},"priorCampaign":"combined-proof stopped after a development-UI navigation timeout before Send; no failed attempts erased."},"complete":true,"statistics":{"before":{"attempted":2,"successfulMeasurements":1,"medianTtfrMs":62657.2000002861,"rangeTtfrMs":[62657.2000002861,62657.2000002861],"medianObservedReadyToRunMs":8448.5,"medianRunStartToVisibleMs":37290.199951171875},"after":{"attempted":2,"successfulMeasurements":0,"medianTtfrMs":null,"rangeTtfrMs":null,"medianObservedReadyToRunMs":0.0,"medianRunStartToVisibleMs":null}},"measuredTurnCostUsd":0.00032752,"costCoverage":"Provider-reported measured chat turns only; harness verification probes are additional and not included.","readinessMetricLimit":"First observed ready state sampled every 250 ms plus HTTP duration; clamped to zero if execution started before the observation. This is a lower bound on ready-to-start delay, not a precise sub-millisecond metric.","results":[{"phase":0,"trial":0,"handoff":"before","ttfrMs":62657.2000002861,"answer":"Hi","statuses":["succeeded"],"error":null,"runErrorCode":null,"providerHealthKilled":false,"queueMs":23467.0,"queuedBeforeObservedReady":true,"observedVerificationMsAfterFixture":26390.0,"observedReadyToRunMs":2830.0,"readyAndStartedInSameSample":false,"runStartToVisibleMs":37290.199951171875,"usage":[{"model":"openrouter/deepseek/deepseek-v4-flash-0731","costUsd":0.00032752,"costUsdExact":"0.000327520","inputTokens":26864,"outputTokens":46,"cachedInputTokens":0,"cacheWriteTokens":0,"usageSource":"per_run","costStatus":"reported"}],"workerSha256":"02adc7e1162fb60439869cec62b75d8fb22fec71155f80535c8e00211cde8326"},{"phase":1,"trial":0,"handoff":"after","ttfrMs":null,"answer":null,"statuses":["failed"],"error":"TimeoutError: page.waitForFunction: Timeout 180000ms exceeded.","runErrorCode":"provider_process_exited","providerHealthKilled":true,"queueMs":14200.0,"queuedBeforeObservedReady":true,"observedVerificationMsAfterFixture":24028.0,"observedReadyToRunMs":0,"readyAndStartedInSameSample":true,"runStartToVisibleMs":null,"usage":[{}],"workerSha256":"ceffb90a6bc97ffaaf8ec7d0267c7bfa7738d321aaf2a618b5efb9b114bc88e7"},{"phase":2,"trial":0,"handoff":"after","ttfrMs":null,"answer":null,"statuses":["failed"],"error":"TimeoutError: page.waitForFunction: Timeout 180000ms exceeded.","runErrorCode":"provider_initialize_timeout","providerHealthKilled":false,"queueMs":13877.0,"queuedBeforeObservedReady":true,"observedVerificationMsAfterFixture":18107.0,"observedReadyToRunMs":0,"readyAndStartedInSameSample":true,"runStartToVisibleMs":null,"usage":[{}],"workerSha256":"ceffb90a6bc97ffaaf8ec7d0267c7bfa7738d321aaf2a618b5efb9b114bc88e7"},{"phase":3,"trial":0,"handoff":"before","ttfrMs":null,"answer":null,"statuses":["running"],"error":"TimeoutError: page.waitForFunction: Timeout 180000ms exceeded.","runErrorCode":null,"providerHealthKilled":false,"queueMs":144256.0,"queuedBeforeObservedReady":true,"observedVerificationMsAfterFixture":136901.0,"observedReadyToRunMs":14067.0,"readyAndStartedInSameSample":false,"runStartToVisibleMs":null,"usage":[{}],"workerSha256":"02adc7e1162fb60439869cec62b75d8fb22fec71155f80535c8e00211cde8326"}],"hostLoadSample":{"at":"2026-10-09T20:48:40.031Z","parallelism":18,"load":[93.546875,82.68017578125,75.9091796875]},"measuredChangesCommit":"40b54eafb","postRebaseCommit":"c590770dcc2bb1debce14037935a7031e5c3c1ac","postRebaseLimit":"Live benchmark predates the rebase. No post-rebase live result is claimed.","variantSourceHashes":{"before":{"server/src/modules/agent-lifecycle/application/worker.ts":"02adc7e1162fb60439869cec62b75d8fb22fec71155f80535c8e00211cde8326","packages/adapters/opencode-local/src/server/test.ts":"4c10bacb55f2c7589e7b5c79d74781206ae075db8955f5b998065d6db3c0335a","server/src/adapters/registry.ts":"4a858763f69947d5745c7b8cb251a62fa404bc9683ade0ffb76282ed12761394"},"after":{"server/src/modules/agent-lifecycle/application/worker.ts":"ceffb90a6bc97ffaaf8ec7d0267c7bfa7738d321aaf2a618b5efb9b114bc88e7","packages/adapters/opencode-local/src/server/test.ts":"cd2ea3d51c3f1b4fb42261be701fb7f6b85704ad8e641e6db73d7c58e47364d3","server/src/adapters/registry.ts":"4a858763f69947d5745c7b8cb251a62fa404bc9683ade0ffb76282ed12761394"}},"model":"openrouter/deepseek/deepseek-v4-flash-0731","prompt":"Reply with Hi and an emoji and nothing else.","runnerBinary":{"profile":"release","sha256":"6134c17debda14a76da69ac9631a2d10dad482ebd58dbc9a4e4480ed652211c4"},"probeIsolation":"Explicit empty cwd and HOME/XDG folders under the synthetic fixture workspace in BOTH variants. No server checkout or ambient provider home is used for the hello request.","comparisonLabelNote":"Inner run.mts variant after selects the identical current proxy in every trial; outer campaign readinessHandoff controls before/after source changes."}
```

Queue-only campaign:

```json
{"campaign":{"order":["before","after","after","before"],"trialsPerPhase":2,"maxMeasuredTurns":8,"maxCampaignUsd":1,"sourceHead":"53580f8fbd40b963f3fb7ba5172ff3ede2e9ef1f","reasoning":"provider default, no override","proxySha256":"6691475ed55f10179ec6ee0023a1f6462982f763848da7cd5b1d0baf38633b04"},"complete":true,"statistics":{"before":{"attempted":4,"successfulMeasurements":1,"medianTtfrMs":59654.5,"rangeTtfrMs":[59654.5,59654.5],"medianObservedReadyToRunMs":19429.0,"medianRunStartToVisibleMs":8843.5},"after":{"attempted":4,"successfulMeasurements":4,"medianTtfrMs":71128.7000002861,"rangeTtfrMs":[63778.90000009537,100195.59999990463],"medianObservedReadyToRunMs":58.0,"medianRunStartToVisibleMs":26542.849975585938}},"measuredTurnCostUsd":0.0055383,"costCoverage":"Provider-reported measured chat turns only; harness verification probes are additional and not included.","readinessMetricLimit":"First observed ready state sampled every 250 ms plus HTTP duration; clamped to zero if execution started before the observation. This is a lower bound on ready-to-start delay, not a precise sub-millisecond metric.","results":[{"phase":0,"trial":0,"handoff":"before","ttfrMs":59654.5,"answer":"Hi 👋","statuses":["succeeded"],"error":null,"queueMs":50590.0,"observedReadyToRunMs":25709.0,"readyAndStartedInSameSample":false,"runStartToVisibleMs":8843.5,"usage":[{"model":"openrouter/deepseek/deepseek-v4-flash-0731","costUsd":0.00087852,"costUsdExact":"0.000878520","inputTokens":25644,"outputTokens":264,"cachedInputTokens":28416,"cacheWriteTokens":0,"usageSource":"per_run","costStatus":"reported"}],"workerSha256":"02adc7e1162fb60439869cec62b75d8fb22fec71155f80535c8e00211cde8326"},{"phase":0,"trial":1,"handoff":"before","ttfrMs":null,"answer":null,"statuses":["failed"],"error":"TimeoutError: page.waitForFunction: Timeout 120000ms exceeded.","queueMs":41651.0,"observedReadyToRunMs":14656.0,"readyAndStartedInSameSample":false,"runStartToVisibleMs":null,"usage":[{}],"workerSha256":"02adc7e1162fb60439869cec62b75d8fb22fec71155f80535c8e00211cde8326"},{"phase":1,"trial":0,"handoff":"after","ttfrMs":100195.59999990463,"answer":"Hi 🙂","statuses":["succeeded"],"error":null,"queueMs":65893.0,"observedReadyToRunMs":116.0,"readyAndStartedInSameSample":false,"runStartToVisibleMs":33243.60009765625,"usage":[{"model":"openrouter/deepseek/deepseek-v4-flash-0731","costUsd":0.00075782,"costUsdExact":"0.000757820","inputTokens":27014,"outputTokens":175,"cachedInputTokens":26368,"cacheWriteTokens":0,"usageSource":"per_run","costStatus":"reported"}],"workerSha256":"ceffb90a6bc97ffaaf8ec7d0267c7bfa7738d321aaf2a618b5efb9b114bc88e7"},{"phase":1,"trial":1,"handoff":"after","ttfrMs":65288.60000038147,"answer":"Hi 👋","statuses":["succeeded"],"error":null,"queueMs":43511.0,"observedReadyToRunMs":0,"readyAndStartedInSameSample":true,"runStartToVisibleMs":21227.60009765625,"usage":[{"model":"openrouter/deepseek/deepseek-v4-flash-0731","costUsd":0.00085326,"costUsdExact":"0.000853260","inputTokens":25166,"outputTokens":250,"cachedInputTokens":28160,"cacheWriteTokens":0,"usageSource":"per_run","costStatus":"reported"}],"workerSha256":"ceffb90a6bc97ffaaf8ec7d0267c7bfa7738d321aaf2a618b5efb9b114bc88e7"},{"phase":2,"trial":0,"handoff":"after","ttfrMs":63778.90000009537,"answer":"Hi 👋","statuses":["succeeded"],"error":null,"queueMs":39218.0,"observedReadyToRunMs":0,"readyAndStartedInSameSample":true,"runStartToVisibleMs":23479.89990234375,"usage":[{"model":"openrouter/deepseek/deepseek-v4-flash-0731","costUsd":0.000839,"costUsdExact":"0.000839000","inputTokens":27068,"outputTokens":238,"cachedInputTokens":26368,"cacheWriteTokens":0,"usageSource":"per_run","costStatus":"reported"}],"workerSha256":"ceffb90a6bc97ffaaf8ec7d0267c7bfa7738d321aaf2a618b5efb9b114bc88e7"},{"phase":2,"trial":1,"handoff":"after","ttfrMs":76968.80000019073,"answer":"Hi 👋","statuses":["succeeded"],"error":null,"queueMs":46257.0,"observedReadyToRunMs":185.0,"readyAndStartedInSameSample":false,"runStartToVisibleMs":29605.800048828125,"usage":[{"model":"openrouter/deepseek/deepseek-v4-flash-0731","costUsd":0.00030582,"costUsdExact":"0.000305820","inputTokens":24694,"outputTokens":32,"cachedInputTokens":1792,"cacheWriteTokens":0,"usageSource":"per_run","costStatus":"reported"}],"workerSha256":"ceffb90a6bc97ffaaf8ec7d0267c7bfa7738d321aaf2a618b5efb9b114bc88e7"},{"phase":3,"trial":0,"handoff":"before","ttfrMs":null,"answer":null,"statuses":["succeeded"],"error":"TimeoutError: page.waitForFunction: Timeout 120000ms exceeded.","queueMs":100979.0,"observedReadyToRunMs":3872.0,"readyAndStartedInSameSample":false,"runStartToVisibleMs":null,"usage":[{"model":"openrouter/deepseek/deepseek-v4-flash-0731","costUsd":0.00190388,"costUsdExact":"0.001903880","inputTokens":25524,"outputTokens":852,"cachedInputTokens":55808,"cacheWriteTokens":0,"usageSource":"per_run","costStatus":"reported"}],"workerSha256":"02adc7e1162fb60439869cec62b75d8fb22fec71155f80535c8e00211cde8326"},{"phase":3,"trial":1,"handoff":"before","ttfrMs":null,"answer":null,"statuses":["running"],"error":"TimeoutError: page.waitForFunction: Timeout 120000ms exceeded.","queueMs":129391.0,"observedReadyToRunMs":24202.0,"readyAndStartedInSameSample":false,"runStartToVisibleMs":null,"usage":[{}],"workerSha256":"02adc7e1162fb60439869cec62b75d8fb22fec71155f80535c8e00211cde8326"}]}
```
</details>

### Matched live browser latency evidence — 2026-10-09

**Conclusion: the overall first-response speedup is not established.**
Twelve successful real browser runs produced a lower after median, but
the updated path won only 3 of 6 adjacent pairs. Median paired
improvement was -0.17 seconds (effectively tied). Do not treat the
deterministic streaming-forwarding improvement as proof that this PR
fixes end-to-end first-response latency.

- **Actual path:** local Paperclip browser → real server/database →
current optimized Rust runner → pinned OpenCode 1.18.34 → OpenRouter
`deepseek/deepseek-v4-flash-0731`. Default reasoning in both variants;
no disabled-reasoning override.
- **Prompt:** `Reply with Hi and an emoji and nothing else.` Fresh
company, agent, chat, and per-turn native provider process for each
trial; same QA fixture instructions and selected model.
- **Comparison:** current product/runner at
`53580f8fbd40b963f3fb7ba5172ff3ede2e9ef1f` held constant. The baseline
substitutes the exact `opencode-app-server-proxy.ts`,
`opencode-proxy-task-envelope.ts`, and `opencode-server-driver.ts`
contents from pre-PR `41fec8c8921f9fb19c13fe11e2c9b71bf1017317`. This
isolates those changed modules; it is not an entire old-checkout
comparison.
- **Metric:** browser capture-phase Send click to a rendered `Hi`
markdown answer plus two animation frames, with a screenshot of the
answer. Thinking, tool labels, and status indicators do not count. This
is a DOM/render measurement, not instrumented compositor pixel timing.
- **Order/bound:** predeclared `before, after, after, before` repeated
three times; six trials per variant; 120-second response timeout; $1
campaign guard. All 12 measured trials returned `Hi` and an emoji and
finished successfully; none omitted.
- **Result:** before median **48.08 s** (37.42–66.40); after median
**42.50 s** (27.68–63.32). The 11.6% lower median alone is not
persuasive evidence of a reliable improvement given the mixed paired
results and broad overlap.
- **Remaining delay:** retained queue timestamps for 10/12 trials show
**9.76–41.65 seconds from run creation to execution start**. This is
before the OpenCode path changed here. Its cause is not established by
this benchmark. The final two queue reads were unavailable after
automatic server shutdown; all twelve primary browser timings were
retained.
- **Cost:** $0.010517369 provider-reported across the 12 measured turns;
$0.011371499 including the successful setup pilot. This is separate from
the older diagnostics listed below.
- **Retained setup attempts:** two failures before Send (composer
locator and transpiler helper); one baseline startup failure before any
observed model request (`SIGKILL` while probing OpenCode health); one
successful current-code pilot whose selector missed the visible reply.
These are retained separately, not silently included/excluded as valid
timings. The measured batch used the corrected selector and the same
release binary for both variants.
- **Limits:** local development server and headless Chromium on macOS
arm64, small sample, variable queue timing/provider routing/cache. This
does not qualify production/cloud performance or isolate the
contributions of each changed module. Server, browser, and owned runs
were stopped; original proxy build artifact restored; no product source
files changed for this experiment.

| Pair | Before: Send → visible Hi | After: Send → visible Hi | Faster
variant |
| --- | ---: | ---: | --- |
| 1 | 66.40 s | 27.68 s | After |
| 2 | 37.42 s | 28.00 s | After |
| 3 | 39.75 s | 55.22 s | Before |
| 4 | 47.32 s | 63.32 s | Before |
| 5 | 48.85 s | 29.79 s | After |
| 6 | 51.31 s | 61.07 s | Before |

<details>
<summary>Sanitized measurement records, source/binary hashes, usage, and
retained attempt classification</summary>

```json
{"manifest":{"candidate":"53580f8fbd40b963f3fb7ba5172ff3ede2e9ef1f","baseline":"41fec8c8921f9fb19c13fe11e2c9b71bf1017317","comparison":"Same current product and runner; replace the three OpenCode proxy/driver source modules with exact pre-PR contents for baseline. Reasoning uses defaults in both.","model":"openrouter/deepseek/deepseek-v4-flash-0731","prompt":"Reply with Hi and an emoji and nothing else.","samplesPerVariant":6,"order":["before","after","after","before","before","after","after","before","before","after","after","before"],"maxTurnMs":120000,"maxCostUsd":1,"variants":{"before":{"sources":{"src/cli/opencode-app-server-proxy.ts":"e9b46c937d7ce3b51dc44181a2a3ad82befda9ebe184adf80c0a6b30da140fd6","src/cli/opencode-proxy-task-envelope.ts":"fc23f8a515c2c4d1551f6b95e5b38e6254849dec23f7396e76b646e170a6e006","src/drivers/opencode/opencode-server-driver.ts":"99de415e8fc3bb5fb6f8d7512d751c4c37d2aa77a18b0546b9fb232f1a6fb6c5"},"bundleSha256":"6dd8726e72545341f6772e54ec5aeb6264dec74db67290df44930d87135efb6b"},"after":{"sources":{"src/cli/opencode-app-server-proxy.ts":"fa800e9bccce02f05f1af83e225d3b5a1300d0a7d4c35ac548f400d6c0a83f79","src/cli/opencode-proxy-task-envelope.ts":"5c387614fc9832322686326b8482eb00d88699d491b05cf59cadcd94a41194ea","src/drivers/opencode/opencode-server-driver.ts":"a944f3bf7f1bf897daec3a5dc2aa34ee9d1a2133efcb3cf150b002095a0ec586"},"bundleSha256":"6691475ed55f10179ec6ee0023a1f6462982f763848da7cd5b1d0baf38633b04"}},"runnerBinary":{"profile":"release","sha256":"6134c17debda14a76da69ac9631a2d10dad482ebd58dbc9a4e4480ed652211c4"},"metric":"Browser Send capture-phase click to visible Hi answer, sampled on animation frames, plus two paint opportunities. Excludes reasoning/tool/status text.","setupAttempts":["setup-failure-1","setup-failure-2","startup-failure-3","pilot-selector-failure"]},"summary":{"before":{"attempts":6,"measured":6,"medianMs":48083.050000190735,"minMs":37420.5,"maxMs":66397.69999980927,"totalCostUsd":0.004945229,"toolCalls":[4,1,0,0,0,1]},"after":{"attempts":6,"measured":6,"medianMs":42504.049999952316,"minMs":27680.099999904633,"maxMs":63320.90000009537,"totalCostUsd":0.00557214,"toolCalls":[0,1,0,4,0,1]},"medianReductionPercent":11.602841334350234,"medianPairedImprovementMs":-168.59999990463257,"reportedCampaignCostUsdIncludingPilot":0.011371498999999998},"pairs":[{"indices":[0,1],"beforeMs":66397.69999980927,"afterMs":27680.099999904633,"improvementMs":38717.59999990463},{"indices":[2,3],"beforeMs":37420.5,"afterMs":27997,"improvementMs":9423.5},{"indices":[4,5],"beforeMs":39751.60000038147,"afterMs":55217.199999809265,"improvementMs":-15465.599999427795},{"indices":[6,7],"beforeMs":47318.90000009537,"afterMs":63320.90000009537,"improvementMs":-16002.0},{"indices":[8,9],"beforeMs":48847.2000002861,"afterMs":29790.900000095367,"improvementMs":19056.300000190735},{"indices":[10,11],"beforeMs":51311.7000002861,"afterMs":61072.40000009537,"improvementMs":-9760.699999809265}],"trials":[{"index":0,"variant":"before","startedAt":"2026-10-09T19:15:23.172Z","measurementError":null,"ttfrMs":66397.69999980927,"domMs":66390.59999990463,"answer":"Hi 👋","runCount":1,"statuses":["succeeded"],"usage":[{"model":"openrouter/deepseek/deepseek-v4-flash-0731","costUsd":0.002612595,"costUsdExact":"0.002612595","inputTokens":55962,"outputTokens":1344,"cachedInputTokens":83456,"cacheWriteTokens":0,"usageSource":"per_run","costStatus":"reported"}],"bundleSha256":"6dd8726e72545341f6772e54ec5aeb6264dec74db67290df44930d87135efb6b","toolCalls":["paperclip_get_task_context","paperclip_comment_on_task","paperclip_finish","paperclip_finish"],"eventCounts":{"turn.started":1,"tool.execution.started":4,"item.delta":1,"turn.completed":1},"eventTimes":{"session.started":"2026-10-09T19:15:58.194Z","turn.submitted":"2026-10-09T19:15:58.311Z","turn.started":"2026-10-09T19:15:59.063Z","firstTextDelta":"2026-10-09T19:16:36.039Z","turn.completed":"2026-10-09T19:16:36.118Z"},"completedRunDurationsMs":[42915.0]},{"index":1,"variant":"after","startedAt":"2026-10-09T19:16:36.598Z","measurementError":null,"ttfrMs":27680.099999904633,"domMs":27636.599999904633,"answer":"Hi","runCount":1,"statuses":["succeeded"],"usage":[{"model":"openrouter/deepseek/deepseek-v4-flash-0731","costUsd":0.00030429,"costUsdExact":"0.000304290","inputTokens":26845,"outputTokens":28,"cachedInputTokens":0,"cacheWriteTokens":0,"usageSource":"per_run","costStatus":"reported"}],"bundleSha256":"6691475ed55f10179ec6ee0023a1f6462982f763848da7cd5b1d0baf38633b04","toolCalls":[],"eventCounts":{"turn.started":1,"item.delta":3,"turn.completed":1},"eventTimes":{"session.started":"2026-10-09T19:17:00.717Z","turn.submitted":"2026-10-09T19:17:00.841Z","turn.started":"2026-10-09T19:17:01.508Z","firstTextDelta":"2026-10-09T19:17:05.934Z","turn.completed":"2026-10-09T19:17:06.205Z"},"completedRunDurationsMs":[14435.0]},{"index":2,"variant":"after","startedAt":"2026-10-09T19:17:08.762Z","measurementError":null,"ttfrMs":27997,"domMs":27984.599999904633,"answer":"Hi 👋","runCount":1,"statuses":["succeeded"],"usage":[{"model":"openrouter/deepseek/deepseek-v4-flash-0731","costUsd":0.00101016,"costUsdExact":"0.001010160","inputTokens":27544,"outputTokens":366,"cachedInputTokens":26624,"cacheWriteTokens":0,"usageSource":"per_run","costStatus":"reported"}],"bundleSha256":"6691475ed55f10179ec6ee0023a1f6462982f763848da7cd5b1d0baf38633b04","toolCalls":["paperclip_finish"],"eventCounts":{"turn.started":1,"tool.execution.started":1,"item.delta":1,"turn.completed":1},"eventTimes":{"session.started":"2026-10-09T19:17:26.192Z","turn.submitted":"2026-10-09T19:17:26.305Z","turn.started":"2026-10-09T19:17:26.936Z","firstTextDelta":"2026-10-09T19:17:40.688Z","turn.completed":"2026-10-09T19:17:40.826Z"},"completedRunDurationsMs":[17763.0]},{"index":3,"variant":"before","startedAt":"2026-10-09T19:17:41.376Z","measurementError":null,"ttfrMs":37420.5,"domMs":37364.40000009537,"answer":"Hi 👋","runCount":1,"statuses":["succeeded"],"usage":[{"model":"openrouter/deepseek/deepseek-v4-flash-0731","costUsd":0.000693018,"costUsdExact":"0.000693018","inputTokens":24236,"outputTokens":282,"cachedInputTokens":27648,"cacheWriteTokens":0,"usageSource":"per_run","costStatus":"reported"}],"bundleSha256":"6dd8726e72545341f6772e54ec5aeb6264dec74db67290df44930d87135efb6b","toolCalls":["paperclip_finish"],"eventCounts":{"turn.started":1,"tool.execution.started":1,"item.delta":1,"turn.completed":1},"eventTimes":{"session.started":"2026-10-09T19:18:12.381Z","turn.submitted":"2026-10-09T19:18:12.616Z","turn.started":"2026-10-09T19:18:13.441Z","firstTextDelta":"2026-10-09T19:18:21.746Z","turn.completed":"2026-10-09T19:18:22.262Z"},"completedRunDurationsMs":[29216.0]},{"index":4,"variant":"before","startedAt":"2026-10-09T19:18:23.000Z","measurementError":null,"ttfrMs":39751.60000038147,"domMs":39705.7000002861,"answer":"Hi 👋","runCount":1,"statuses":["succeeded"],"usage":[{"model":"openrouter/deepseek/deepseek-v4-flash-0731","costUsd":0.000265747,"costUsdExact":"0.000265747","inputTokens":26123,"outputTokens":77,"cachedInputTokens":0,"cacheWriteTokens":0,"usageSource":"per_run","costStatus":"reported"}],"bundleSha256":"6dd8726e72545341f6772e54ec5aeb6264dec74db67290df44930d87135efb6b","toolCalls":[],"eventCounts":{"turn.started":1,"item.delta":1,"turn.completed":1},"eventTimes":{"session.started":"2026-10-09T19:19:01.000Z","turn.submitted":"2026-10-09T19:19:01.163Z","turn.started":"2026-10-09T19:19:01.893Z","firstTextDelta":"2026-10-09T19:19:07.169Z","turn.completed":"2026-10-09T19:19:07.384Z"},"completedRunDurationsMs":[15843.0]},{"index":5,"variant":"after","startedAt":"2026-10-09T19:19:10.050Z","measurementError":null,"ttfrMs":55217.199999809265,"domMs":55204.89999961853,"answer":"Hi 🙂","runCount":1,"statuses":["succeeded"],"usage":[{"model":"openrouter/deepseek/deepseek-v4-flash-0731","costUsd":0.00030421,"costUsdExact":"0.000304210","inputTokens":4294,"outputTokens":28,"cachedInputTokens":22543,"cacheWriteTokens":0,"usageSource":"per_run","costStatus":"reported"}],"bundleSha256":"6691475ed55f10179ec6ee0023a1f6462982f763848da7cd5b1d0baf38633b04","toolCalls":[],"eventCounts":{"turn.started":1,"item.delta":1,"turn.completed":1},"eventTimes":{"session.started":"2026-10-09T19:19:59.877Z","turn.submitted":"2026-10-09T19:19:59.990Z","turn.started":"2026-10-09T19:20:00.713Z","firstTextDelta":"2026-10-09T19:20:07.290Z","turn.completed":"2026-10-09T19:20:07.658Z"},"completedRunDurationsMs":[15104.0]},{"index":6,"variant":"after","startedAt":"2026-10-09T19:20:09.550Z","measurementError":null,"ttfrMs":63320.90000009537,"domMs":63313.09999990463,"answer":"Hi 👋","runCount":1,"statuses":["succeeded"],"usage":[{"model":"openrouter/deepseek/deepseek-v4-flash-0731","costUsd":0.00260723,"costUsdExact":"0.002607230","inputTokens":137971,"outputTokens":951,"cachedInputTokens":1024,"cacheWriteTokens":0,"usageSource":"per_run","costStatus":"reported"}],"bundleSha256":"6691475ed55f10179ec6ee0023a1f6462982f763848da7cd5b1d0baf38633b04","toolCalls":["paperclip_comment_on_task","paperclip_get_task_context","paperclip_comment_on_task","paperclip_finish"],"eventCounts":{"turn.started":1,"tool.execution.started":4,"item.delta":1,"turn.completed":1},"eventTimes":{"session.started":"2026-10-09T19:20:59.730Z","turn.submitted":"2026-10-09T19:20:59.859Z","turn.started":"2026-10-09T19:21:00.501Z","firstTextDelta":"2026-10-09T19:21:19.416Z","turn.completed":"2026-10-09T19:21:19.608Z"},"completedRunDurationsMs":[26519.0]},{"index":7,"variant":"before","startedAt":"2026-10-09T19:21:20.519Z","measurementError":null,"ttfrMs":47318.90000009537,"domMs":47246.800000190735,"answer":"Hi 👋","runCount":1,"statuses":["succeeded"],"usage":[{"model":"openrouter/deepseek/deepseek-v4-flash-0731","costUsd":0.000257965,"costUsdExact":"0.000257965","inputTokens":4700,"outputTokens":71,"cachedInputTokens":21407,"cacheWriteTokens":0,"usageSource":"per_run","costStatus":"reported"}],"bundleSha256":"6dd8726e72545341f6772e54ec5aeb6264dec74db67290df44930d87135efb6b","toolCalls":[],"eventCounts":{"turn.started":1,"item.delta":1,"turn.completed":1},"eventTimes":{"session.started":"2026-10-09T19:22:03.924Z","turn.submitted":"2026-10-09T19:22:04.439Z","turn.started":"2026-10-09T19:22:04.772Z","firstTextDelta":"2026-10-09T19:22:09.915Z","turn.completed":"2026-10-09T19:22:10.343Z"},"completedRunDurationsMs":[16702.0]},{"index":8,"variant":"before","startedAt":"2026-10-09T19:22:11.124Z","measurementError":null,"ttfrMs":48847.2000002861,"domMs":48802.59999990463,"answer":"Hi 🎉","runCount":1,"statuses":["succeeded"],"usage":[{"model":"openrouter/deepseek/deepseek-v4-flash-0731","costUsd":0.000327654,"costUsdExact":"0.000327654","inputTokens":44796,"outputTokens":32,"cachedInputTokens":0,"cacheWriteTokens":0,"usageSource":"per_run","costStatus":"reported"}],"bundleSha256":"6dd8726e72545341f6772e54ec5aeb6264dec74db67290df44930d87135efb6b","toolCalls":[],"eventCounts":{"turn.started":1,"item.delta":1,"turn.completed":1},"eventTimes":{"session.started":"2026-10-09T19:22:57.182Z","turn.submitted":"2026-10-09T19:22:57.281Z","turn.started":"2026-10-09T19:22:57.988Z","firstTextDelta":"2026-10-09T19:23:02.915Z","turn.completed":"2026-10-09T19:23:03.035Z"},"completedRunDurationsMs":[9541.0]},{"index":9,"variant":"after","startedAt":"2026-10-09T19:23:03.579Z","measurementError":null,"ttfrMs":29790.900000095367,"domMs":29748.800000190735,"answer":"Hi 👋","runCount":1,"statuses":["succeeded"],"usage":[{"model":"openrouter/deepseek/deepseek-v4-flash-0731","costUsd":0.00034054,"costUsdExact":"0.000340540","inputTokens":24710,"outputTokens":59,"cachedInputTokens":1792,"cacheWriteTokens":0,"usageSource":"per_run","costStatus":"reported"}],"bundleSha256":"6691475ed55f10179ec6ee0023a1f6462982f763848da7cd5b1d0baf38633b04","toolCalls":[],"eventCounts":{"turn.started":1,"item.delta":2,"turn.completed":1},"eventTimes":{"session.started":"2026-10-09T19:23:28.840Z","turn.submitted":"2026-10-09T19:23:28.954Z","turn.started":"2026-10-09T19:23:29.666Z","firstTextDelta":"2026-10-09T19:23:35.306Z","turn.completed":"2026-10-09T19:23:35.531Z"},"completedRunDurationsMs":[12732.0]},{"index":10,"variant":"after","startedAt":"2026-10-09T19:23:37.247Z","measurementError":null,"ttfrMs":61072.40000009537,"domMs":61061.300000190735,"answer":"Hi 👋","runCount":1,"statuses":["succeeded"],"usage":[{"model":"openrouter/deepseek/deepseek-v4-flash-0731","costUsd":0.00100571,"costUsdExact":"0.001005710","inputTokens":25307,"outputTokens":368,"cachedInputTokens":28160,"cacheWriteTokens":0,"usageSource":"per_run","costStatus":"reported"}],"bundleSha256":"6691475ed55f10179ec6ee0023a1f6462982f763848da7cd5b1d0baf38633b04","toolCalls":["paperclip_finish"],"eventCounts":{"turn.started":1,"tool.execution.started":1,"item.delta":1,"turn.completed":1},"eventTimes":{"session.started":"2026-10-09T19:24:33.721Z","turn.submitted":"2026-10-09T19:24:33.832Z","turn.started":"2026-10-09T19:24:34.601Z","firstTextDelta":"2026-10-09T19:24:43.135Z","turn.completed":"2026-10-09T19:24:43.278Z"},"completedRunDurationsMs":[17387.0]},{"index":11,"variant":"before","startedAt":"2026-10-09T19:24:44.710Z","measurementError":null,"ttfrMs":51311.7000002861,"domMs":51300.5,"answer":"Hi 👋","runCount":1,"statuses":["succeeded"],"usage":[{"model":"openrouter/deepseek/deepseek-v4-flash-0731","costUsd":0.00078825,"costUsdExact":"0.000788250","inputTokens":24316,"outputTokens":356,"cachedInputTokens":27648,"cacheWriteTokens":0,"usageSource":"per_run","costStatus":"reported"}],"bundleSha256":"6dd8726e72545341f6772e54ec5aeb6264dec74db67290df44930d87135efb6b","toolCalls":["paperclip_finish"],"eventCounts":{"turn.started":1,"tool.execution.started":1,"item.delta":1,"turn.completed":1},"eventTimes":{"session.started":"2026-10-09T19:25:31.347Z","turn.submitted":"2026-10-09T19:25:31.463Z","turn.started":"2026-10-09T19:25:32.208Z","firstTextDelta":"2026-10-09T19:25:39.405Z","turn.completed":"2026-10-09T19:25:39.563Z"},"completedRunDurationsMs":[15446.0]}],"additionalAttempts":[{"attempt":"setup-1","stage":"before_send","result":"non-editable composer locator","modelRequestObserved":false},{"attempt":"setup-2","stage":"before_send","result":"transpiler helper absent in browser","modelRequestObserved":false},{"attempt":"startup-pilot-before","runnerProfile":"debug","result":"no visible reply within 120s; OpenCode health startup SIGKILL; retained infrastructure failure","modelRequestObserved":false},{"attempt":"selector-pilot-after","runnerProfile":"debug","result":"Hi reply succeeded; browser selector missed it; no valid TTFR","providerReportedCostUsd":0.00085413}],"queueTimingCoverage":{"measuredTrials":10,"totalTrials":12,"records":[{"index":0,"runs":[{"createdAt":"2026-10-09T19:15:28.998Z","startedAt":"2026-10-09T19:15:53.558Z","queuedMs":24560.0}]},{"index":1,"runs":[{"createdAt":"2026-10-09T19:16:38.520Z","startedAt":"2026-10-09T19:16:54.157Z","queuedMs":15637.0}]},{"index":2,"runs":[{"createdAt":"2026-10-09T19:17:10.587Z","startedAt":"2026-10-09T19:17:23.561Z","queuedMs":12974.0}]},{"index":3,"runs":[{"createdAt":"2026-10-09T19:17:43.807Z","startedAt":"2026-10-09T19:17:53.564Z","queuedMs":9757.0}]},{"index":4,"runs":[{"createdAt":"2026-10-09T19:18:28.113Z","startedAt":"2026-10-09T19:18:54.011Z","queuedMs":25898.0}]},{"index":5,"runs":[{"createdAt":"2026-10-09T19:19:12.343Z","startedAt":"2026-10-09T19:19:53.993Z","queuedMs":41650.0}]},{"index":6,"runs":[{"createdAt":"2026-10-09T19:20:14.258Z","startedAt":"2026-10-09T19:20:53.866Z","queuedMs":39608.0}]},{"index":7,"runs":[{"createdAt":"2026-10-09T19:21:23.019Z","startedAt":"2026-10-09T19:21:54.298Z","queuedMs":31279.0}]},{"index":8,"runs":[{"createdAt":"2026-10-09T19:22:14.671Z","startedAt":"2026-10-09T19:22:53.933Z","queuedMs":39262.0}]},{"index":9,"runs":[{"createdAt":"2026-10-09T19:23:06.155Z","startedAt":"2026-10-09T19:23:23.941Z","queuedMs":17786.0}]}],"limitation":"The server shut down before a final API read; queue timing is retained for the first ten trials only."},"conclusion":"No reliable end-to-end speedup established. The after median is lower, but only three of six adjacent matched pairs were faster; median paired improvement is approximately zero. The deterministic streaming-forwarding fix remains separately supported.","limitations":["Local dev server and headless Chromium on macOS arm64; six fresh chats per variant; not a production/cloud latency guarantee.","Current product and current release runner held constant; only three OpenCode modules replaced by their exact pre-PR contents for baseline.","Default model reasoning unchanged; no no-reasoning override or decision policy.","Upstream routing/cache and queue time vary; trials run serially in predeclared counterbalanced ABBA order.","Render proxy: capture-phase Send click to visible nonempty Hi markdown, then two animation frames; screenshot verifies the rendered answer. This is not instrumented compositor pixel timing.","Two setup-only failures, one startup failure, and one invalid-measurement successful pilot are retained separately, not silently treated as successful timings."],"reproducibility":{"harnessSha256":"f93996b306c7d31c19bfcb9cc197653f867944ffb900d81a23a34f831e17c0c5","variantBuilderSha256":"4e88a7bbdc0de5d72601194ebe3b96d9c6f6eda5a33d8e0f00cf2d5d14db34c2","analyzerSha256":"2d129177a1b8033f768aad3c82dc8fff70ba0ba76e7270b2d8612ee760d4aaf4"}}
```

</details>

- Latest options-struct refactor: 33 provider tests and 86 backend tests
passed. Four port-dependent fixtures initially failed inside the sandbox
and passed with loopback access. Latest check snapshot: 51 successes, 4
skips, and 2 failures (`ci / e2e` and `ci / e2e shard (5/8)`). This
latency experiment does not make the PR merge-ready.

- Focused TypeScript suites passed: OpenCode driver, per-turn reasoning,
prepared-context recovery, proxy envelope, live sessions, Codex context
control, and native instruction measurements. The real runnerd/proxy
integration test confirms disabled followed by default in the same
session. A stale staged binary initially hid the new parameter;
rebuilding the release runner resolved it.
- Capability-guard regression suites passed all 53 tests; the real
runner/proxy boundary still accepts the per-turn selection. Both
OpenRouter and non-OpenRouter real runner/proxy cases passed, along with
62 existing OpenCode fixture tests. Runner TypeScript build passed after
the final correction.
- Affected Rust modules passed: 33 provider tests and 86 durable backend
tests. Malformed or unsupported reasoning selections do not dispatch a
provider turn or poison admission state.
- Pinned OpenCode 1.18.34 with a local OpenRouter-compatible fixture
sent three successive provider requests with reasoning omitted,
`enabled: false`, then omitted. Each request contained one copy of the
agent instructions. No paid provider call was needed.
- The reconstructed first-turn task envelope shrank from 4,356 to 460
characters. This is a payload-size measurement, not a claimed token or
latency reduction. Existing stored conversation history is not
rewritten.
- Prior head `8c07fe2e70267a7c8a3118f1071eca73ecdc6c8a`: all 53 checks
passed, with four intentional skips. Greptile is 5/5 with no open
findings. One bounded retry cleared first-test timeouts, a legacy
signoff lease failure, and CI runner shutdowns. The timed-out suites
also passed locally (14 auth-signal tests, 40 device-login tests, and
the runner resume case).
- Known reported diagnostic usage totals about $0.0029. Two prematurely
closed baseline warm-turn attempts are excluded from latency comparisons
and their usage is not fully captured; background provider usage is also
not fully accounted. No further paid runs are active.
- `pnpm -r typecheck`: passed. Runner TypeScript typechecks and build
also passed after the review correction.
- `pnpm test:run`: attempted and stopped after a reproducible failure in
the untouched Codex recovery test `archives a damaged prior epoch before
completing guarded same-task replacement with real runnerd`
(`server/src/services/native-runtime/native-session-resume.test.ts:1072`).
It returns `needs_review` / failed instead of done / succeeded,
including when rerun alone. The broad local suite is not green. The two
initial collection failures disappeared after building; their isolated
rerun passed all 1,565 tests.
- `pnpm build`: passed.
- Pinned real OpenCode plus a delayed local provider: first native delta
to Paperclip delta fell from 1,496 ms to less than 1 ms at millisecond
measurement resolution. This isolates forwarding delay, not
network/model inference.
- Two live driver samples after the patch reached first text in
2.28–2.62 seconds including session startup. Baseline first responses
took 12.37–13.43 seconds. Small unmatched samples had different
reasoning/cache outcomes, so these are observations, not an attributed
speedup ratio.
- Full compiled runnerd protocol diagnostic: completed with `Hi 👋`;
first assistant delta at 9.19 seconds and cleanup complete at 9.44
seconds. The seeded mock-control-plane harness used 27,512 input tokens
across two provider requests, split into 13,521 and 13,991. The extra
`answer_status_question` call posted `Hi 👋` to the mock task in 12 ms,
then caused another model request. A reconstruction contains 25 tools
(35.3k JSON characters), 12.8k system characters, and a 4.4k task
envelope; 3.9k instruction characters appear in both system and task
context. Provider-reported cost was $0.00073976; the pricing-table
estimate was $0.00395332. This is one integration diagnostic, not a
production latency claim.
- A separate full-runner sample with existing lazy tool discovery also
completed, but took 14.64 seconds through cleanup and called
`paperclip_finish`. Its usage ledger recorded 12,888 input and 11,776
cached-input tokens, with $0.00096344 provider-reported cost. This did
not establish a latency improvement, so the default tool exposure was
not changed.
- Four direct OpenRouter requests separately measured default reasoning
at 2.45/3.90 seconds to first text and disabled reasoning at 0.66/0.53
seconds. Default reasoning remains unchanged; disabling it requires the
explicit per-turn option.

## Risks

- Immediate readiness dispatch changes scheduling timing. It uses
existing admission checks and preserves the periodic sweep as recovery.
- Native model verification relies on the real request rather than
catalog enumeration. The final live batch had provider startup failures;
overall speed and reliability are not qualified.
- Incremental chunks without IDs cannot safely be deduplicated by
content. Repeated identical chunks are valid. Known-ID duplicates remain
suppressed.
- OpenCode uses its bundled model catalog plus the explicit
selected-model entry. New remote catalog metadata will not refresh
during isolated startup.
- Default provider plugins are disabled. This runner supplies
credentials and assigned MCP tools through its own controlled
configuration.
- Disabled reasoning is supported only on the OpenCode/OpenRouter path
and requires a compatible model. It applies to one turn and is not an
automatic latency policy.
- The matched live browser sample is small and does not establish a
reliable end-to-end improvement. It includes local queueing/startup and
browser rendering, but does not qualify production or remote sandbox
latency.

## Model Used

OpenAI GPT-6 (Codex). Tool use, code editing, and command execution were
used. The session does not expose a more specific model ID or
context-window size. Live diagnostic target: DeepSeek
`deepseek/deepseek-v4-flash-0731` through OpenRouter and OpenCode
1.18.34.

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-10 07:15:41 -05:00
Devin FoleyandPaperclip eedf25655b test(adapter-utils): publish bridge queue fixtures atomically (#15792)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Remote agents send API requests through a callback bridge queue.
> - Queue readers reserve memory from each published file's measured
size.
> - Several tests wrote directly into visible queue files while the
reader was active.
> - A reader could measure an empty file and then reject its completed
contents with HTTP 503.
> - This pull request makes those fixtures use the existing atomic
publisher and proves the race without timing guesses.

## Linked Issues or Issue Description

**What happened?**

The public readiness run
[38035333062](https://github.com/paperclipai/paperclip/actions/runs/38035333062)
failed the schema-discovery bridge test. It expected HTTP 200 but
received 503. The same test logged `Bridge envelope exceeded the
configured size limit.`

The fixture wrote requests directly to visible `.json` files. If a
writer completed between the reader's size measurement and bounded read,
the reader correctly rejected the changed file. The production gateway
and filesystem queue client already publish complete files by renaming a
temporary file.

**Expected behavior**

Queue fixtures must publish requests with the same atomic contract as
the production writer. Schema assertions must observe completed
responses. The runtime must still reject a request that grows beyond the
size reserved for its read.

**Steps to reproduce**

Create an empty visible request file. Have the worker measure its size.
Complete the write before the bounded read. The new deterministic
regression produces the exact error and HTTP 503, with no handler
dispatch. A separate publication test polls during an incomplete write
and verifies that the real atomic writer keeps it invisible.

**Paperclip version or commit**

The failing run used `de042e79efbb7bb88e9716835407882e3ebab188`. The
same fixture and reader are present in the base of this PR,
`7e10dbe652ef0104f0a688a196fe8ea47b6f4b8e`.

**Deployment mode**

Local filesystem fixtures in the adapter-utils readiness tests. No
external provider is required.

Related PRs #15003 and #15696 address shutdown listing and idle polling.
This is a separate fixture-publication race. This PR does not adopt or
change their runtime work.

## What Changed

- Use the existing filesystem queue client's atomic publisher at seven
live-worker publication sites in five tests.
- Wait for all seven schema responses within the existing single
five-second bound, then assert the GET response and all six denials.
Worker shutdown remains cleanup for that test.
- Add a deterministic incomplete-write publication regression and a real
worker regression for the bounded reader's existing HTTP 503 recovery.
- Keep intentional malformed fixtures, dedicated drain assertions,
runtime limits and runtime source unchanged. Test comments explain the
publication contract; no product documentation changes are needed.

## Verification

- Full bridge file: 68/68 tests passed on Node 25.6.1.
- Seven focused publication, schema, authorization, drain and recovery
cases passed.
- Negative control: replacing the fixture helper with a direct write
makes the publication test fail in milliseconds with the exact
bounded-reader error. Restoring atomic publication passes.
- Broader adapter-utils run: 1,690 passed, 12 skipped, one unchanged
GitHub-launcher identity test exceeded its existing five-second limit.
That exact case passed unchanged in isolation. This is not claimed as a
full aggregate pass; no timeout or launcher source was changed.
- Full workspace `pnpm -r typecheck` and `pnpm build` passed.
- Independent review passed all 68 bridge tests and adapter-utils
typecheck, plus three negative controls: both forms of direct
publication fail, and removing the bounded read fails the expected-503
regression. The original source was restored and targeted positives
passed again.
- Hosted [CI
38038772400](https://github.com/paperclipai/paperclip/actions/runs/38038772400)
passed at `aa4bcd8c1729e8ce098f2eb0143502ab34237d01`, including the full
workspaces-b suite that originally failed. The PR has 53 successful
checks and two expected Storybook skips.
- Greptile scored that same commit 5/5; independent source review is
approved, no review threads remain open, and GitHub reports no merge
conflicts.

## Risks

This change only affects tests. The new filesystem spy is limited to its
own temporary directory and is restored in `finally`. A producer
regression must still fail the publication test. The schema test retains
all authorization checks and a single five-second response bound. The
bridge's size limits, failure recovery, request handling and shutdown
policy are unchanged.

## Model Used

OpenAI GPT-6 through Codex, with reasoning, repository tools and
independent agent review. The exact service model identifier and
context-window size are not exposed in this session.

## Checklist

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

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-10 01:55:29 -07:00
Devin FoleyandPaperclip caa7895f9a fix(opencode): report timeouts without claiming deadline expiry (#15789)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - The OpenCode adapter reports the outcome of a local or remote
execution.
> - A provider can report a timeout before the configured execution
deadline.
> - The adapter treated every timeout as proof that the configured
deadline expired.
> - This pull request uses a generic timeout message and retains the
resolved policy.
> - Operators can compare the run duration with its actual configured
limit without a false cause claim.

## Linked Issues or Issue Description

**What happened?**

A remote execution can return `timedOut: true` after a short interval
while the sandbox policy is four hours. OpenCode reported `Timed out
after 14400s`. It also dropped the resolved policy on that result. Run
finalization then used the raw `timeoutSec: 0` configuration, so
diagnostics incorrectly reported an unlimited timeout.

**Expected behavior**

Keep the timeout outcome. Report the resolved policy separately from the
failure message. Do not infer which timer fired from the provider's
boolean or stderr.

**Steps to reproduce**

Call the OpenCode adapter with a sandbox execution target and
`timeoutSec: 0`. Return a timed-out process result before four hours.
Inspect the message and the policy that finalization sends to the
run-failure collector. The new tests reproduce this with local fixtures
and an in-memory Sentry transport.

**Paperclip version or commit**

Reproduced on `de042e79efbb7bb88e9716835407882e3ebab188`.

**Deployment mode**

Legacy OpenCode execution on a local instance or remote sandbox.

Refs #14832 for related timeout result preservation; this PR does not
change session state. Related PRs #14964, #15659 and #15715 cover
silent-run limits, gateway requests and OpenCode v2 support. They do not
fix this policy/message path.

## What Changed

- Retain the complete existing timeout resolution on both OpenCode
result branches.
- Report `OpenCode execution timed out` without copying provider output
into exception text.
- Document that configured policy and the existing `timeoutFired`
outcome field do not prove timer origin.
- Test policy overrides, sandbox defaults, opt-out, ordinary exits, real
local timer expiry, cleanup and real Sentry SDK delivery.

## Verification

- 142 focused adapter, stop-metadata and diagnostic tests passed on Node
25.6.1.
- The real Sentry SDK contract suite passed 11/11 with the audited
optional peer 10.71.0 and an in-memory transport. The new test runs the
actual adapter, finalization policy merge and collector. It verifies
that raw HTML and credential canaries stay out of the event and
unrelated captures stay isolated.
- Full workspace `pnpm -r typecheck` and `pnpm build` passed. All hosted
CI checks passed on `f4df5cba1d2223d444559de960bbf88dfa985bbf` (54
passed, 2 expected skips).
- The local aggregate is not a pass: 15 existing PostgreSQL fixture
cases initially failed because this fresh macOS install lacked bundled
ICU symlinks. The dependency's existing hydration script repaired the
isolated install; all 15 affected cases then passed with real
PostgreSQL. No test or production source was changed for that setup
issue. The aggregate was stopped after hosted test coverage passed; it
is incomplete, not a local full-suite pass. All owned test processes
exited.
- Greptile scored this exact head 5/5 with no review threads.
Independent review found no issues. It ran 58 positive cases and adapter
typechecking. Three negative controls failed as expected when it
restored the old producer, removed timeout policy, or copied raw stderr
into the message.

## Risks

The timeout message changes for local and remote OpenCode runs. The
resolved policy is additive result data. The numeric timeout, grace
period, process result, retry rules, session handling, cleanup and
recovery behavior are unchanged. This fixes reporting and does not
identify or fix an upstream provider timeout. No schema change or
migration is required.

## Model Used

OpenAI GPT-6 through Codex, with reasoning, repository tools and
independent agent review. The exact service model identifier and
context-window size are not exposed in this session.

## Checklist

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

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-10 01:18:17 -07:00
32745f4e84 feat(issues): keep follow-up parents and show the creation source (#15762)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - Agents delegate work by creating follow-up tasks through the issue
API, the CLI, and the chat `create_task` tool
> - An agent can omit `parentId` when it creates a follow-up from an
ordinary execution task. The API accepts the task as a top-level task.
The task hierarchy does not show where the task came from, even though
the run provenance is recorded
> - The operator must read run history to learn why the task exists.
This is slow and it hides delegated work from the parent task
> - This pull request keeps the parent link for delegated follow-ups by
default, keeps intentional standalone tasks possible, and shows an
access-checked "Created from <task> by <agent>" note on the task page
from the recorded run provenance
> - The benefit is that each agent-created task shows its source without
log inspection, while structural parentage, provenance, and blockers
stay separate concepts

## Linked Issues or Issue Description

Refs #13241 (shows tasks created from a task on the source task page;
this PR shows the reverse direction on the created task)
Refs #9727 (open proposal for creation provenance tracking)

**What existing behavior does this improve?**

Issue creation by agent runs, and the task detail page.

**Subsystem affected**

Server (`POST /api/companies/:companyId/issues`, `GET /api/issues/:id`),
shared types, UI task detail page, CLI `issue create`, Paperclip skill
docs.

**Current behavior**

When an agent run bound to an execution task creates a task and omits
`parentId`, the task is created with no parent. The task page shows no
source. The operator must inspect the run log to find the task that the
agent was working on. The source run and the privacy parent are
recorded, but the UI does not use them.

**Proposed behavior**

- When an agent run bound to an ordinary execution task omits
`parentId`, the server sets `parentId` to that task. The `issue.created`
activity records `parentDefaultedFromRunIssue: true`.
- An explicit `parentId: null` keeps the task standalone. Conversation
runs (chat handoffs), board or user creates, watchdog follow-ups, a run
task the agent may not mutate, a default parent that would cause a
delegation cycle, and a default parent the agent may not create a child
under (for example a protected assignment policy without a grant) also
stay standalone. The server runs the same `tasks:assign` decision with
the defaulted parent in scope before it accepts the default. No request
that succeeded before now fails. An explicit `parentId` is still checked
as before.
- `GET /api/issues/:id` returns `createdFrom` with the source task, the
run, and the agent. The server resolves it from `origin_run_id`, or from
the recorded creation activity for historical rows. It returns `null`
when the viewer may not read the source task or the run, when the run is
from another company, or when provenance is missing.
- The task page shows "Created from <task> by <agent>" in the classic
breadcrumb area and in the streamlined Tasks tab. The note is not a
blocker and it is shown with or without a parent.
- The CLI `issue create` command gets `--standalone`, which sends
`parentId: null`.

**Reason and benefit**

Operators see why a task exists on the task itself. Delegated follow-ups
stay inside the parent task tree, so parent completion and child
wake-ups keep working. Private and cross-company sources stay hidden.

**Breaking changes**

None for the API schema. Agents that create tasks from a run and relied
on the omitted `parentId` to mean "top-level" must now send `parentId:
null` (CLI: `--standalone`). The skill and the spec document this.

## What Changed

- `server/src/services/issue-creation-source.ts` (new): resolves a
task's creation source from the origin run or the creation activity,
scoped to the company, and loads the run-bound task by UUID or
identifier.
- `server/src/routes/issues.ts`: `POST /companies/:companyId/issues`
defaults `parentId` to the run's task when the body omits it (with the
exclusions above) and records the default in the activity log. `GET
/issues/:id` adds the access-checked `createdFrom` field.
- `packages/shared/src/types/issue.ts` and index exports: new
`IssueCreationSource` type and the optional `createdFrom` field on
`Issue`.
- `ui/src/components/task-detail/IssueCreatedFromNote.tsx` (new),
`TaskDetailTasksPanel.tsx`, and `IssueDetail.tsx`: show the creation
source in both task page layouts and count it in the Tasks tab badge.
- `cli/src/commands/client/issue.ts`: `issue create --standalone`.
- Docs: `doc/SPEC-implementation.md`, `doc/CLI.md`,
`skills/paperclip/SKILL.md`.
- Tests: `server/src/__tests__/issue-creation-source-routes.test.ts`
(new), `TaskDetailTasksPanel.test.tsx`, `IssueDetail.test.tsx`.

## Verification

Run the new server route test (embedded Postgres):

```sh
cd server && pnpm exec vitest run src/__tests__/issue-creation-source-routes.test.ts
```

It covers: ordinary delegation gets the parent and `createdFrom`;
explicit `parentId: null` stays standalone but still shows the source;
conversation handoff and board create stay standalone; a would-be
delegation cycle falls back to standalone; a protected source task
without a grant falls back to standalone while an explicit parent still
returns 403; an explicit cycle still returns 409; historical provenance
from the creation activity; missing provenance, a private source for an
outsider, and a cross-company run all return `null`.

Related existing suites that passed locally (11 files, 313 tests):
`issue-created-from-routes`, `issue-create-deduplication-routes`,
`issue-agent-mutation-ownership-routes`, `chat-project-tools`,
`issue-assignee-invokability-routes`, `issue-watchdogs-routes`,
`issue-dependency-wakeups-routes`, `public-mcp`,
`native-runtime/task-creation-backlog`, `issue-access-grants-routes`,
`issue-list-assignee-filter-routes`.

UI:

```sh
cd ui && pnpm exec vitest run src/components/task-detail/TaskDetailTasksPanel.test.tsx src/pages/IssueDetail.test.tsx
pnpm check:token-gates
```

Manual check: as an agent run bound to a task, `POST
/api/companies/:companyId/issues` with only a title. The response has
`parentId` set to the run's task. Open the new task; the page shows
"Created from <task> by <agent>".

The related server suites pass locally (`issue-created-from`,
`issue-create-deduplication`, `issue-agent-mutation-ownership`,
`chat-project-tools`, `issue-watchdogs`, `public-mcp`,
`task-creation-backlog`, `issue-access-grants`,
`permissions-upgrade-boundary`). The full `pnpm -r typecheck`, `pnpm
test:run`, and `pnpm build` were not run locally because the sandbox has
a 4 GB memory limit and the TypeScript compiler is killed on the server
project; the CI gates on this PR cover them.

## Risks

- Behavior shift for agent clients: a run-created task without
`parentId` now becomes a child of the run's task. Clients that want a
top-level task must send `parentId: null`. The watchdog, conversation,
and board paths are excluded, and the default never adds a blocker.
- The default parent inherits the parent's execution workspace, which
run-created tasks already inherited from the run's task.
- `createdFrom` adds one run lookup, one issue lookup, one access
decision, and one agent lookup to the task detail request. It is skipped
when the task has no origin run and no creation activity with a run.
- Privacy: the field returns `null` unless the viewer can read the
source task and the run, so a private source is indistinguishable from
missing provenance.

## Model Used

Claude Fable 5.1 (`claude-fable-5-1`), Anthropic, run through Claude
Code in a Paperclip-managed execution workspace with tool use, shell
execution, and a local embedded Postgres for tests.

## Checklist

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

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

---------

Co-authored-by: devinfoley <139239+devinfoley@users.noreply.github.com>
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-10 00:40:08 -07:00
DottaandPaperclip 3ec7309d91 feat(voice): add experimental Speko task connection runtime (#15727)
First PR: runtime. UI: #15728. Qualification: #15729.

## Thinking Path

> - Paperclip manages agent work through tasks and governed connections.
> - Chat connections already bind external conversations to those tasks.
> - Speko handles voice and telephony, while the selected Paperclip
agent does the work.
> - A call needs durable session authority, ordered follow-ups, and safe
result delivery.
> - This PR adds an explicit voice transport to the existing connection
runtime.
> - The UI and qualification suites follow in linked PRs. Speko stays
experimental.

## Linked Issues or Issue Description

**Problem or motivation**

Phone and browser voice conversations cannot use the chat connection
task lifecycle. A separate voice runtime is needed to preserve task
authority, retries, and reply history.

**Proposed solution**

Add company-scoped voice sessions, signed callbacks, durable replies,
inbound intake, and an agent-facing outbound-call tool. Reuse existing
tasks, queues, secrets, and publications.

**Roadmap alignment**

This extends the experimental chat connector entry points under Agent
Chat and Connected Apps. The project owner requested this feature.

Refs #11418 for the original provider catalog proposal. This
implementation uses the newer chat connection infrastructure rather than
an MCP catalog-only integration. Refs #15721 for remote OpenCode
startup.

## What Changed

- Add additive voice schema, shared contracts, session APIs, and
provider callbacks.
- Bind browser, inbound, and outbound sessions to an endpoint, task, and
selected agent.
- Add low-trust guest intake in an explicitly selected sandbox and keep
ordinary approval rules.
- Submit task work through session-scoped tools and push approved
replies through Speko POST /v1/calls/{id}/messages.
- Distinguish provider acceptance from confirmed spoken playback.
Reconcile reports without downloading recordings.
- Add protocol, migration, persistence, provider, and
delivery-diagnostic tests.

## Verification

- Master 3389bea708 is integrated. Database/shared builds, server
typecheck, migration upgrade/replay checks, and 46
communication-guidance/provider/protocol tests passed.
- The final persistence suite passed 85 real-database tests. Five
focused native continuation/authorization regressions passed. Five
callback ownership/rotation tests passed after the last runtime repair.
- Review repairs cover reconnect ownership, current caller authority,
duplicate delivery, multipart answers, task-page answers, guest question
handling, and saved sandbox recovery.
- A real OpenCode/OpenRouter DeepSeek task ran in Daytona and saved a
correct disk-space answer. This did not establish live-call playback.
- Full local typecheck/build passed before the final repairs; focused
typechecks passed after them. Latest-head CI runs the repository gates.
- The separate integrated browser qualification passed two journeys and
failed browser answer retrieval. The feature remains experimental. The
report in #15729 records this failure and outstanding real-provider
acceptance.
- No lockfiles are included. Speko migrations follow master as
0324–0330.

## Risks

- Voice sessions add migrations and provider-dependent lifecycle
behavior. Migrations preserve existing chat and AI transports.
- Callback origins must be reachable HTTPS. Provider keys and signing
secrets remain vaulted.
- Unverified callers receive task-scoped low-trust authority. Caller ID
does not grant private task access.
- Outbound telephony incurs provider charges. Provider acceptance is not
proof that the caller heard an answer.
- Keep the feature behind the existing experimental chat setting until
the real browser, inbound, outbound, and delayed-result acceptance
matrix passes.

## Model Used

OpenAI Codex, GPT-6, with tool use and code execution. The exact serving
model ID and context window are not exposed in this session.

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-09 21:54:11 -05:00
DottaandPaperclip ed2c22ea8c feat(connections): simplify dedicated GitHub App setup (#15416)
## Thinking Path

> - Paperclip manages agent work and the tools each agent can use.
> - GitHub bots need their own App identity and restricted repository
access.
> - Manual App configuration and repeated setup gates make that
connection hard to finish.
> - GitHub can create an App from a manifest, but people must approve
creation and repository access.
> - Each Paperclip stack should own configuration, credentials,
signature verification, and task admission.
> - This change uses Cloud as an encrypted callback and event gateway,
then completes setup in the stack.
> - GitHub review bots have their own experimental setting. Chat
connector opt-in does not control them.

## Linked Issues or Issue Description

**What existing behavior does this improve?**

Dedicated GitHub App setup, bot settings, and task-scoped GitHub
replies.

**Current behavior**

Users must configure an App, copy credentials, repeat repository
selection, and complete manual verification gates. Review settings are
hard to scan. Mentions in descriptions can be missed, and automatic
completion text can produce an extra GitHub comment.

**Proposed behavior**

Choose an agent and connect GitHub under a personal account or
organization. GitHub asks for creation and installation consent.
Paperclip resumes the same draft, stores secrets locally, imports
access, verifies delivery, and opens Settings. Each accepted request has
one editable App-owned comment for progress and results. Review
assessments produce deterministic checks for the reviewed commit.

**Breaking changes**

GitHub bots require their own default-off experimental opt-in. The
setup-method and delegated-agent screens are removed. Per-person
automatic-run flags remain readable but are replaced by author filters.
Existing connections, direct webhooks, saved restrictions, and manual
existing-App recovery remain supported.

Companion gateway:
https://github.com/paperclipai/paperclip-cloud/pull/688 (merged). The
roadmap and related PRs were checked; no duplicate dedicated-App wizard
was found.

## What Changed

- Add an independent **GitHub review bots** setting across the catalog,
routes, identity admission, and task controls. Existing bots continue
running when the UI setting is off.
- Replace setup with Choose agent and Connect GitHub. Support personal
and organization owners, inline low-trust conversion, saved drafts,
known organization suggestions, automatic completion, and same-App
recovery.
- Keep manifests, OAuth PKCE, credential exchange, vault storage,
installation verification, and original webhook-signature validation in
the stack. Use the Cloud sealed gateway for public callbacks and
outbound local delivery.
- Add resumable owner metadata in migration 0323. Retry a failed
registration renewal through the same durable replacement rather than
creating another App route.
- Support authorized mentions in issue and PR bodies, comments, inline
comments, and review summaries. Preserve attachments, edited-source
identity, duplicate protection, and lifecycle invalidation. Filter
requests explicitly addressed to another connected bot.
- Give agents task-scoped review, comment, and update tools. Update one
working comment through progress and final output. Close coalesced
requests and recover delayed acknowledgements, including deleted earlier
working comments. Preserve automatic replies for legacy connections
without saved review configuration. Preserve partial publication
evidence and quarantine uncertain automatic fallbacks without blocking
Board messages or questions.
- Reorganize Settings and Access with rich slash-skill instructions,
numeric passing scores, clear automation controls, formal-review
tooltips, member and contributor sections, and verified App branding
links. Preserve invalid score drafts and automation choices across tabs.
- Paginate repositories in 20-row batches with search and a true
connection-wide toggle. Batch verification at GitHub's 500-ID token
limit. Keep saved repository overrides while hiding their editor.
- Give each review a detail URL that remains usable beyond the newest
100 records. Synchronize the manager OpenAPI contracts and add recovery,
authorization, UI, and browser regressions.
- Reconcile the current master branch and retain its agent avatar,
feature catalog, and extracted heartbeat preparation code. Preserve a
saved test-drive port and recover from an occupied high port.

## Verification

- Focused UI, independent experimental-setting, and CLI tests: 199
passed.
- `pnpm -r typecheck`, `pnpm build`, and `pnpm check:token-gates`
passed. The broad local Vitest attempt was interrupted after resource
timeouts and stale expectations; the affected regressions passed focused
reruns. The latest-head full CI matrix passed, including all browser
shards, server/chat suites, builds, typechecking, canary packaging, and
Docker context integrity. A Docker Hub 429 required a CI retry; it
passed without changing the code.
- Final review repairs: 127 attachment/event tests and server typecheck
passed. All 13 final integration regressions passed under the normal CI
timeout, covering legacy reply compatibility, deleted coalesced
comments, inline-only review completion, progress edits, and native
final recovery. Restart-safe description/review attachments passed the
attachment suite.
- Final regressions: four reply/lifecycle tests, both native GitHub wait
tests, 171 feature-gate/reply-contract tests, the routed review preview,
and five scheduler/reply regressions passed. The final fixture repair
also passed all six setup-continuation cases and all three complete
chat-test shards in CI, covering terminal receipts and retries under the
normal CI timeout. One loaded-host receipt run exceeded its local
timeout; the exact case passed in an isolated rerun and the complete CI
shard.
- GitHub integration tests cover personal and organization setup, retry
recovery, edited mentions, attachment provenance, coalesced requests,
delayed acknowledgements, partial review writes, old review URLs, and
company boundaries.
- Browser qualification: both GitHub journeys, all five provider
setup/management journeys, and the GitHub uncertain-send recovery
journey passed. GitHub setup, reconnect, and task replies run with chat
disabled; chat enabled alone cannot expose GitHub bots. The disposable
qualification database was removed after testing.
- Earlier live qualification verified App-owned issue replies, native
slash-skill invocation, progress comment edits, and a 5/5 PR review with
a passing current-head check in the dedicated permissions-smoke
repository. These live checks did not use personal credentials as bot
execution authority.

## Risks

- Deploy the merged Cloud gateway protocol before the stack update. Each
callback and encrypted event must retain the original instance and
tenant binding.
- Migration 0323 uses idempotent column additions for test installations
that already applied the earlier draft migration number.
- A verified connection does not prove runtime isolation or a completed
review. Runtime checks remain separate.
- Required merge checks must be configured in GitHub. A passing numeric
score does not formally approve a PR; approval and request-changes tools
remain opt-in.
- Existing-App credentials cannot silently renew an uncertain manifest
exchange. Recovery preserves the existing App, draft, connection, and
agent.
- Repository changes save immediately. Global toggles affect all
currently available repositories, including unloaded rows, without
granting new installation access.
- A failed or uncertain tool write suppresses automatic fallback text;
the governed outbox retains its evidence. Deleted or replaced response
comments are not recreated through a personal credential fallback.
- GitHub logo upload remains an optional human action in GitHub App
settings. Runtime provisioning, delegated setup, screenshot publication,
and production push delivery remain deferred.

## Model Used

OpenAI Codex, based on GPT-6, with tool use and code execution. The
exact runtime model identifier and context size are not exposed in this
session.

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-09 17:01:20 -05:00
DottaandPaperclip 5cf90417d6 fix(ui): confirm cancellation from monitor cards (#15735)
## Thinking Path

> - Paperclip helps people manage AI agents and their tasks.
> - A task monitor schedules a later agent check.
> - The monitor card shows when that check will run.
> - The card has no direct control to cancel the monitor.
> - This change adds an X button and a confirmation dialog.
> - The operator can stop the scheduled check from the card.

## Linked Issues or Issue Description

**What existing behavior does this improve?**
The monitor card on the task page.

**Current behavior**
The operator must open task properties to clear a monitor.

**Proposed behavior**
Select the X in the top right of the card. Select Keep monitor to leave
the schedule in place. Select Cancel monitor to remove the scheduled
check.

**Reason and benefit**
The operator can cancel the monitor where its schedule is shown.
Confirmation helps prevent an accidental cancellation.

**Breaking changes**
None. The change uses the existing task update API.

## What Changed

- Add an accessible X button at the top right of the monitor card.
- Confirm cancellation before the task update.
- Keep the dialog open with an error if the update fails.
- Preserve the other execution policy settings and refresh the task
after success.
- Reject stale policy writes under the task row lock with an optional
expectedExecutionPolicy snapshot.
- Document the snapshot field and add a database test for stale
cancellation.
- Restrict snapshot requests to policy-only edits before
execution-control actions.
- Add seven route tests for rejected mixed requests and absent policy
updates.
- Keep automatic retry waits separate from monitor cancellation.
- Add component and task page tests.

## Verification

- `pnpm check:token-gates` passed.
- Monitor banner and task page tests passed: 199 tests. A targeted
database test and seven route tests also passed.
- UI typecheck and production build passed.
- Open a task with a scheduled monitor. Select X, then Keep monitor. The
schedule must remain.
- Select X, then Cancel monitor. The card must disappear after the
update.
- Local full build reached the Rust runner build but could not complete
because Cargo is absent. CI must verify the full build.
- Full repository typecheck, build, test suites, and E2E checks passed
in CI for the final commit. Local full checks were limited by missing
Cargo and workspace memory.

## Risks

- Low risk. Cancellation uses the existing company access checks and
activity log.
- A cancelled monitor no longer wakes the agent. The dialog explains
this effect.

## Model Used

OpenAI Codex, GPT-6. The runtime does not expose a more specific model
ID or context window size. Used code editing, shell commands, and tests.

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-09 16:38:04 -05:00
Devin FoleyandPaperclip 9befc66a44 Retain bounded Daytona acquisition failure observations (#15736)
## Thinking Path

> - Paperclip manages AI-agent work and reports failed runs.
> - Some runs acquire a Daytona sandbox before model execution.
> - Acquisition has one budget for creation, setup, and inline cleanup.
> - A timeout currently carries cleanup ownership but loses the step
that failed.
> - This pull request carries a bounded observation through the existing
error envelope.
> - Operators can identify the first failed step without exposing
provider responses or changing recovery.

## Linked Issues or Issue Description

**What happened?**

An acquisition timeout reports pending allocation cleanup without the
first failed step. The provider already knows its current step, but that
evidence is discarded at the worker boundary. A setup failure followed
by slow cleanup is also indistinguishable from slow creation.

**Expected behavior**

The immediate setup-failure report should contain a fixed phase and
bounded elapsed/budget values. Cleanup ownership, original messages,
deadlines, retry policy, and task behavior should remain unchanged.

**Steps to reproduce**

Use the provider regression fixtures to stall creation, workspace setup,
shell detection, expiry configuration, or sentinel upload. Also fail
setup early and let cleanup consume the remaining budget. The previous
source emits no phase diagnostic.

**Paperclip version or commit**

Base commit: `98e3cec78e8461774022a5ba0a777b09d4d16b96`.

**Deployment mode**

Hosted and self-hosted installations that use the Daytona sandbox
provider and enable Sentry.

Related public changes: #13979 established failed-allocation cleanup
ownership; #14097 preserves the provider acquisition budget; #15637
carries bounded workspace-transfer evidence. Duplicate searches found no
existing acquisition-phase diagnostic patch.

## What Changed

- Capture the first acquisition failure before inline cleanup. Keep the
observation if cleanup later reaches the deadline.
- Add an optional, validated observation to the existing
creation-cleanup envelope for acquire calls. Old ownership envelopes
remain valid. Malformed observations do not alter cleanup.
- Bind immediate reporting to an actual RPC error with matching company,
environment, and run ownership. Project only three bounded fields from
private host evidence.
- Add provider, SDK, actual worker/client, PostgreSQL cleanup,
collector, and real-Sentry regressions. Document the evidence limits.

## Verification

- Passed 404 focused tests across the SDK cleanup envelope, complete
Daytona provider suite, diagnostic collector, actual built worker/client
subprocess, and mandatory real-Sentry SDK suite.
- Passed 10 focused PostgreSQL cleanup-boundary cases. The filter
excluded 152 unrelated cases.
- Passed `pnpm -r typecheck` and `pnpm build` on the committed source.
- Full `pnpm test:run` is running. Final outcomes will be recorded
before merge.
- Independent source review passed. Replacing the provider with the
original source fails all 8 new phase/timing assertions. Replacing the
host boundary with the original source fails all 3 owned diagnostic
cases while 7 negative cases remain clean.
- CI passed: 54 successful checks and 2 expected Storybook skips. This
includes all server, workspace, serialized-server, Runner, browser,
build, canary, and real-Sentry SDK lanes.
- Greptile scored the committed source 5/5 with no review threads.
- No live provider operation, task replay, runtime configuration change,
or deployment was performed.

## Risks

Low risk: this only adds optional diagnostic evidence. The first
observed failing phase does not prove an upstream cause. Elapsed time
ends at that observation, not at completion of later cleanup. Evidence
is process-local and accompanies immediate failure reporting;
post-restart reports cannot reconstruct it. No historical run or lease
is backfilled. The wire schema remains v1 and cleanup ownership parsing
is unchanged.

## Model Used

OpenAI Codex, GPT-6, with repository inspection, code editing, local
execution, and independent agent review. The exact model snapshot and
context-window size are not exposed in this session.

## Checklist

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

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-09 14:25:14 -07:00
DottaandPaperclip c5f7713dd4 fix: clarify native tool use for external agents (#15734)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - External agents keep their own tools and app connections.
> - The Paperclip assignment catalog controls the Paperclip bridge.
> - Dot treated a qualification test restriction as a rule for later
work.
> - Existing prompts did not clearly separate these two tool sources.
> - This pull request tells agents to use their own capabilities and
return results to Paperclip.
> - The benefit is that a missing Paperclip app does not block an
available native capability.

## Linked Issues or Issue Description

Related work: #15722 and #15691. I searched open PRs for Dot tool
guidance and found no duplicate.

**What happened?**
After a qualification test, Dot refused a Slack request because the test
Paperclip agent had no assigned Slack app. Dot already had a working
Slack connection in ChatGPT. It carried the test's plugin restriction
into a later task message.

**Expected behavior**
An external agent uses its own available tools, apps, plugins, skills,
and capabilities to complete the current request. It then returns the
result through Paperclip's task reporting and completion tools. The
assignment catalog limits Paperclip calls. It does not disable the
agent's native tools.

**Steps to reproduce**
1. Connect a Dot that has a native Slack connection.
2. Complete a Paperclip qualification task with a restriction scoped to
that test.
3. Send a later task message that requires Slack.
4. Observe that Dot can mistake the Paperclip catalog for its full tool
inventory.

**Deployment mode**
Observed on Cloud staging with the Dot Runner.

## What Changed

- Add shared tool-use guidance for external-agent onboarding and Dot
setup.
- Include it in the server onboarding document, pairing response, event
instructions, and capability response.
- Clarify the tool descriptions on both Dot bridge paths.
- Include the same guidance in each Dot Runner assignment without adding
a shared-package dependency to the standalone Runner.
- Document native tool use and the scope of test restrictions.

## Verification

- The 49 relevant onboarding, Dot invitation, and Runner context tests
passed. The final UI run passed 29 tests. The updated plain-text
renderer run passed all 4 tests.
- Full workspace typecheck, full workspace build, and design token gates
passed. All current-head CI gates passed, including full tests, Runner
verification, and browser E2E. Greptile is 5/5 on the exact final
commit, and the one review finding is resolved.
- The real Dot received the standing correction and confirmed that it
will use its relevant tools and connections, return results through
Paperclip, and stop carrying the test restriction forward.
- Extended the existing plain-text renderer test to check native Slack
access, qualification-test scope, and the Paperclip denial boundary.
This covers agents that receive only the onboarding.txt URL.
- The full Vitest suite passed in CI. The earlier local Cloud
qualification run encountered failures in unchanged suites; this
follow-up uses focused local tests for the instruction changes.

## Risks

This changes instructions, not access checks. Native tools retain their
own permissions and approval requirements. Paperclip operations remain
scoped to the authorized company, agent, and task. Agents must not use
another connection or identity to bypass a denial. There is no database
migration or new permission grant.

## Model Used

OpenAI GPT-6 through Codex. Used reasoning, repository tools, and
browser control. The runtime does not expose a more specific model ID or
context window size.

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-09 16:20:38 -05:00
DottaandPaperclip b6b3cb3761 Fix unavailable workspace branches with an inline repair and retry (#15726)
## Thinking Path

> - Paperclip manages AI agents and their work.
> - Isolated workspaces must resolve a starting Git ref before an agent
starts.
> - A task can explicitly select a branch that the repository does not
have.
> - The current recovery notice calls this a missing secret and offers
no branch repair.
> - This pull request explains the branch failure and adds a task-scoped
repair action.
> - Operators can correct the branch and request a guarded retry from
the task thread.

## Linked Issues or Issue Description

Related: Refs #11892 added unresolved-ref recovery. Refs #15719 added
bounded failure diagnostics. This change uses that recovery path and
adds its operator repair UI.

**What happened?**

A task that selects `main` in a repository with only `master` stops
before the adapter starts. The task shows a missing-secret message and a
generic retry. Repeating the run cannot fix the stored branch setting.

**Expected behavior**

Explain that the starting ref could not be resolved. Offer a verified
repository default, or let the operator enter a branch. Save only the
task's starting branch and retry its recorded owner through the existing
admission gates.

**Steps to reproduce**

1. Create an isolated-workspace task in a repository with `master` and
no `main`.
2. Set the task's base ref to `main` and assign an agent.
3. Wait for the configuration failure.
4. Use the inline branch repair and confirm the agent completes in a
worktree based on `master`.

## What Changed

- Replace the missing-secret diagnosis for unresolved workspace refs.
Keep uncertain fetch/access failures described as uncertain.
- Read the remote's advertised default branch with the existing Git
credentials and a bounded timeout. Do not guess or silently change the
branch.
- Add an atomic branch repair to the existing recovery resolution
endpoint. Check company access, board runtime permission, incident
identity, current owner, task/project state, dependencies, interactions,
approvals, budget, and active execution before requesting a retry.
- Preserve the effective inherited workspace setup when saving the task
branch override, and attach one repair notice per failed run even when
the incident is reused.
- Bind the shared repair card to the exact recovery notice and failed
run in both task-thread renderers. Validate branch syntax and prevent
duplicate submissions.
- Add Storybook examples, regression tests, and a documented local
acceptance fixture with a real Git repository and process adapter.

## Verification

- Red/green regressions cover the repair endpoint and preservation of
inherited agent setup. The regression failed before each fix and passed
afterward.
- Focused integration suite: 162 tests passed; task-thread/card suite:
230 passed. After review refinements, all 13 repair-route tests, 10 card
tests, 77 recovery-action tests, and the repeated-failure heartbeat
regression passed locally.
- Real browser acceptance passed for suggested-branch and custom-entry
repairs. Invalid syntax left the task blocked. Both valid repairs ran
the authenticated worker in a real isolated worktree and reached Done;
reload preserved the result.
- Repeated failures reused the recovery incident and retained an
actionable notice on the latest run. The inherited-setup journey
verified the provisioned file, agent branch template, worktree parent
directory, and actual Git commit before completing. [Before/after
screenshots](https://github.com/paperclipai/paperclip/pull/15726#issuecomment-6088734666).
- Full local typecheck and build passed; server typecheck passed again
after review fixes. Token gates passed.
- The monolithic local Vitest run was stopped after resource-contention
timeouts and stale assertions. Targeted regressions were rerun; the full
CI matrix passed on final revision
`26c543ff490bec29ddc77a49ee532c7f84fb96dc`. One signoff E2E
worker-cancellation failure passed on a rerun without code changes. The
two opt-in Storybook workflow jobs were skipped; the Storybook journey
was checked manually.
- Repeat the live journey with `tests/e2e/workspace-base-ref/README.md`.
Storybook examples use simulated callbacks and are not the live
acceptance proof.

## Risks

- Default-branch discovery can add up to 10 seconds to an unresolved-ref
failure. Lookup failure leaves manual entry available.
- A valid branch name can still be absent or inaccessible. The retried
workspace preparation remains authoritative and can block again with new
evidence.
- Retry remains subject to normal admission gates. The repair changes
only the task override; it does not alter project or agent defaults.
- No database migration or new dependency.

## Model Used

OpenAI GPT-6 through Codex, with tool execution, repository analysis,
and browser testing. The exact serving variant and context-window size
are not exposed in this session.

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-09 15:56:14 -05:00
Devin FoleyandPaperclip 98e3cec78e feat(costs): report monthly subscriptions beside API spend (#15634)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Its Costs page reports API charges and subscription token usage.
> - Subscription runs do not show the recurring fee paid for the
account.
> - Several agents can share one paid seat, so a fee per agent would
overstate cost.
> - This pull request identifies connected subscription accounts and
reports each monthly fee once.
> - Users can compare API spend and subscription costs, see uncertainty,
and enter their actual price.

## Linked Issues or Issue Description

Refs #498 and #3406 for related subscription reporting needs. This
change does not add subscription budget enforcement or automatic
optimization.

Related prior approaches: #10544 and #11104 proposed API-equivalent
token costs for subscription work. This PR reports recurring account
fees separately from usage charges and budgets. A search found no open
PR for monthly account fee reporting.

**Subsystem affected**
Costs, managed AI connections, shared contracts, database schema, and
board UI.

**Problem or motivation**
An organization can pay for subscriptions even when included runs record
no additional dollar charge. The Costs page cannot show that monthly
commitment or distinguish a shared paid seat from several separate
seats.

**Proposed solution**
Discover account identity from the managed connection selected for a
run. Use exact known plans for labeled monthly list-price estimates.
Keep ambiguous plans and unconfirmed identities unpriced until the user
supplies a price. Sum current monthly fees separately from date-filtered
API charges and token usage.

**Alternatives considered**
A fee per agent double-counts shared accounts. Token-based API price
estimates do not measure the recurring subscription fee. Provider
invoices would be more exact but are not available through these account
credentials.

**Roadmap alignment**
Extends the shipped Better Budgeting and Personal & Shared AI Accounts
capabilities. The feature and UI were reviewed with the maintainer
before this PR.

## What Changed

- Add company-scoped subscription accounts, connection bindings, and
immutable price revisions in replay-safe migration 0322.
- Identify OpenAI workspace/seat and Claude organization/account pairs
only after provider authentication. Keep provisional records
grant-scoped; unchecked ID-token claims cannot combine accounts or grant
billing editors. Keep credentials and raw provider identities out of
reports.
- Attach the selected subscription to new run receipts. Resolve
duplicate aliases without rewriting old monetary receipts.
- Add cached background discovery with four provider checks and twenty
discovery requests at a time. Accepted requests wait for capacity;
excess requests receive HTTP 429 and a UI retry action. Preserve saved
prices and observations when a provider check fails. Dashboard polls
load current prices only; audit revisions stay in the database.
- Support owner-controlled monthly or annual prices, fractional-cent
precision, separate currency totals, tracking status, and duplicate
linking. Preserve both personal owners and shared-account managers when
discovery finds the same paid seat.
- Show API spend beside monthly subscription commitment, with separate
token totals and clear estimate labels. Account details and fee totals
follow billing-owner/shared-audience visibility; company-wide token
totals remain available to cost readers.
- Use consistent amount and estimate badge formatting for agent, user,
project, and model rows.
- Add real PostgreSQL tests, route authorization tests, UI tests,
interactive Storybook fixtures, and operator documentation.

## Verification

- Current head `d7b5c78dadf5033a3c447d83434676ac94687e77` passed all 53
checks, with two checks skipped. This includes the full test matrix,
browser tests, build, typecheck, migration policy, canary packaging, and
security checks.
- Greptile Apex reviewed that exact head at 5/5 with no unresolved
findings.
- Local `pnpm -r typecheck`, `pnpm build`, `pnpm check:token-gates`,
migration safety checks, and `git diff --check` passed.
- All 238 focused tests passed across accounting, subscription
persistence, authorization, UI, migration replay, and snapshot drift.
- The expanded local chat suite passed 1,149 tests. Two cases failed
because this workspace found an unrelated ancestor skill directory; both
passed unchanged in an isolated checkout. The full local Vitest command
was not repeated after the rebase because of this environment issue. CI
covered the complete test matrix on the final head.
- Migration `0322_reflective_kree.sql` follows master's
`0321_acoustic_human_fly.sql`. Its snapshot and journal were
regenerated. Master's migration and snapshot are unchanged. The
subscription SQL retains its original content and hash.
- Disposable PostgreSQL upgrade fixtures applied master's added
lifecycle and Slack migrations without changing saved subscription
prices or cost receipts. The renamed subscription migration was
recognized by hash, retained one history row, and a second migration run
was a no-op.
- Regression tests cover provider capacity, fractional-cent edits,
billing visibility after grant revocation, and
fixed-price/credit/unknown usage. The new UI billing-label tests fail
against the old wording and pass with the fix.
- Browser checks passed for desktop and mobile layouts, shared-account
totals, annual price edits, unknown prices, and stale provider data.
- A live OpenAI account probe returned HTTP 200 and a verified Pro
account identity. The generic Pro plan correctly remains unpriced.
- Live Claude discovery identified Max 20x and a $200/month estimate.
Two real Claude agent runs were attributed to that same account, with
two usage receipts, two agents, one monthly fee, and zero additional
usage charges. Two OpenAI connections also deduplicated to one account.
- Live Codex execution is not verified: both Paperclip's managed hello
test and a direct host `codex exec` fail with a workspace-routing
authentication error. The current credential passes the usage API probe.
This is separate from the successful account-discovery check.
- A local performance fixture with 50,000 usage events and 5,001 saved
price revisions produced a 1,589-byte report in 11.5 ms median / 12.2 ms
maximum over ten warmed runs. PostgreSQL used the subscription/revision
index to read one current price row. These are local measurements, not a
production latency guarantee.
- [Desktop, account details, and mobile
screenshots](https://pages.paperclip.ing/pr-15634-subscription-costs-d5d285e2/)
show the production Costs page with synthetic Storybook fixtures.
- To inspect the UI, run `pnpm storybook` and open **Costs /
Subscriptions**. Edits there change fixture data only.

## Risks

- Provider plan identifiers can change. Unknown plans remain unpriced.
Automatic prices are estimates before tax; discounts and negotiated
prices require a user-supplied amount.
- Subscription fees describe the current monthly commitment. They do not
follow the selected usage date range and do not consume agent budgets or
create finance events.
- Monthly fees cover only accounts visible to the viewer; company-wide
token totals retain their existing scope.
- Legacy or unmanaged usage can remain unattributed. Unconfirmed
identities require manual prices and may need explicit duplicate linking
after credential changes.
- Disconnecting a connection does not prove provider billing stopped.
Users must end or exclude tracking explicitly.
- Migration 0322 adds tables, a nullable cost-event column, and an
index. It is replay-safe, but normal migration locks still apply.

## Model Used

OpenAI Codex, based on GPT-6. This session did not expose a more
specific backend model ID or context-window size. Capabilities used:
code editing, shell execution, database tests, and browser verification.

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-09 13:38:01 -07:00
DottaandPaperclip cb291bf129 Fix Dot Cloud invitation and anonymous consent setup (#15722)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Dot joins through a public MCP connection and the Runner task
system.
> - A new hire must connect before its lifecycle can become ready.
> - The invite UI treated the hire's temporary paused status as a manual
pause.
> - Anonymous Cloud consent also reloaded after protected background
probes returned 401.
> - This pull request fixes both gates without changing server access
checks.
> - The benefit is that a new Dot can complete Cloud setup and the UI
waits for actual readiness.

## Linked Issues or Issue Description

Related merged work: #15691 and #15581. I searched open Dot PR and issue
titles. I found no duplicate.

**What happened?**
A new Dot invite displayed “Resume this agent before connecting Dot.”
The hire was preparing or verifying. The anonymous Cloud consent page
remained on “Loading connection request…” because background
tenant-session failures caused repeated document reloads.

**Expected behavior**
The invite must issue a setup prompt when the server permits connection
setup. Public Dot consent must load without a board session. The Done
button must wait for both the binding and agent lifecycle to become
ready.

**Steps to reproduce**
1. Enable Dot, Assistant connections (MCP), and the native Runner on a
Cloud test tenant.
2. Choose New Agent, Invite an external agent, then Dot.
3. Observe the false resume gate on the new hire.
4. Open the plugin's public Dot consent page in a browser without a
tenant board session.
5. Observe the loading loop after a protected background probe returns
`tenant_session_required`.

**Paperclip version or commit**
Reproduced on `556daf9a99e8674f9c4a1c38ac20ae9adafdd417`.

**Deployment mode**
Cloud staging with a managed Daytona Runner. No production tenant
changes.

## What Changed

- Return lifecycle state and connection setup authority in the operator
Dot binding response.
- Use that authority to prepare prompts during hire preparation and
verification.
- Continue polling after event readiness until the agent lifecycle is
ready.
- Keep expected tenant-session failures from reloading an exact public
Dot consent route.
- Classify Dot consent as a global route. Retain board session and
archived-stack recovery.
- Add regression tests and update the Dot deployment documentation.

## Verification

- Before the fix, regression tests reproduced the false pairing gate and
anonymous consent reload.
- After the fix, 34 Dot invitation tests and 51 public consent/API/route
tests passed before rebasing.
- Full workspace typecheck, full build, final UI typecheck, and design
token gates passed locally. All current-head CI gates are green,
including full tests and browser E2E.
- The final UI regression run passed 80 tests. The broad local test run
has reported failures in unchanged chat, OAuth-tool-access, and
native-resume suites while running alongside other development
instances; the equivalent isolated CI lanes passed. The broad local run
was stopped after these failures to release local resources; it is not
claimed as passing.
- Live Cloud qualification passed OAuth discovery, the approved agent
grant, ChatGPT account handoff, a signed event subscription, and the
inbox readiness challenge. The agent became ready and normal scheduling
launched the managed Runner. A real Dot accepted the task, read its
context, wrote and verified a document, posted a comment, and completed
through paperclip_finish and paperclip_dot_finish. The task persisted as
Done after reload, and the successful turn's sandbox was destroyed with
a successful cleanup receipt.
- Restarting the existing Dot refreshed its newly installed plugin
actions. The first Daytona allocation remained creating and hit the
acquisition deadline; a bounded normal retry acquired a sandbox and
launched through authenticated provider ingress. The earlier allocation
still rejects deletion while creating (HTTP 409), so its failed-run
cleanup remains pending.
- After deployment, use a real Dot to open the consent page without
board credentials, pair, confirm task events, and finish an assigned
task through the managed Runner.

## Risks

The operator binding response has two new required fields. Server and UI
must deploy together. The recovery exception only applies to a valid Dot
consent pathname and tenant-session 401 responses. It does not expose
protected APIs or suppress archived-stack recovery. No schema migration
or agent permission change is required.

## Model Used

OpenAI GPT-6 through Codex. Used reasoning, repository tools, test
execution, and browser control. The runtime does not expose a more
specific model ID or context window size.

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-09 15:19:33 -05:00
Devin FoleyandPaperclip 712671068e test(runner): use the production close budget for settled callbacks (#15720)
## Thinking Path

> - Paperclip manages autonomous AI agents and their work.
> - Paperclip Runner preserves the authority of each provider session.
> - A reusable close requires durable semantic results, provider drain,
and suspension.
> - The real-process tests gave successful close cases a shorter budget
than production.
> - Under load, the test can miss its drain deadline and then expect an
unsafe success.
> - This change tests successful close with the unchanged production
budget.
> - Deliberately stalled and failed-persistence cases keep their short
deadline and rejection checks.

## Linked Issues or Issue Description

**What happened?**

Release verification failed in `fences reusable suspension against late
semantic completion` for both successful modes. The runner suspended,
but the provider drain proof missed the test's preparation deadline.
Production correctly rejected reuse. The test expected success.

**Expected behavior**

Successful real-process cases should use the production close budget.
Failure cases should still reject without exact settlement proof.

**Steps to reproduce**

Run the affected tests with the real runner and fake provider. Add 250
ms after each actual control-store save during close. With the old
five-second override, both successful modes reject with the same
missing-drain-proof settlement. With the production default, both pass.
The controlled delay reproduces the deadline mechanism. It does not
measure the actual CI disk latency.

**Paperclip version or commit**

Base commit: `1602512820832b43afef6786bedeee4e5294db8e`.

**Deployment mode**

Release verification and local real-process tests. No application or
deployment behavior changes.

Duplicate search: #14382 and #14395 modify nearby runner tests, but do
not change this parameterized close test. They are separate work.

## What Changed

- Use the production close budget for the two successful modes.
- Keep the explicit five-second budget for stalled callbacks and
persistence failures.
- Keep all semantic-result, exact drain, suspension, and checkpoint
assertions.
- Change one test file. Production code and deadlines stay unchanged.

## Verification

- Unchanged baseline: all four affected cases passed. Ten additional
successful-mode repeats passed.
- Controlled durable-write delay: the old budget failed both successful
modes. The production budget passed both.
- Candidate: all four affected real-process cases passed.
- Parallel baseline runner sweep: 3,491 passed, 5 unrelated local
fixture failures, and 12 skipped. The affected cases passed. This is not
an aggregate pass.
- `pnpm -r typecheck` passed.
- `pnpm build` passed.
- Independent review passed all four affected cases and repeated the
real-write latency contrast with the same result. No findings.
- `pnpm test:run` was interrupted after 15 unrelated local
warm-ownership fixture failure markers (exit 130). The full local
aggregate did not complete or pass. The changed Runner test is outside
the root test project list. The completed independent and focused checks
above cover the change.
- All GitHub CI is green on the exact head: 52 successful check runs,
one successful commit status, and two expected Storybook skips. The
affected Runner lane passed.
- Greptile scored the exact head 5/5, with no open comments.

## Risks

Low risk. This changes a test option only. The two successful cases can
now wait up to the existing production deadline. The two failure cases
keep their short bound. Missing receipts still reject reusable close.
The source does not relax a permission, ownership fence, or durability
check.

## Model Used

OpenAI GPT-6 through Codex, with reasoning, terminal tools, and an
independent agent review. The exact deployed model suffix and
context-window size are not exposed in this session.

## Checklist

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

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-09 12:25:42 -07:00
DottaandPaperclip 3fc64c5156 feat(slack): add Require at-mention setting (#15612)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Slack messages can create tasks and continue existing tasks.
> - A reply in a subscribed thread can start agent work without a new
mention.
> - Some users want to control each reply with an explicit bot mention.
> - This pull request adds a Require at-mention setting to Slack app
settings.
> - The setting checks new messages and queued messages before they
start work.

## Linked Issues or Issue Description

**What existing behavior does this improve?**

Slack app settings and the rules that admit inbound messages.

**Subsystem affected**

Server, UI, database, and shared API contracts.

**Current behavior**

After the bot joins a thread, an ordinary reply can wake the agent.
Direct messages do not need a bot mention.

**Proposed behavior**

Add Require at-mention below Allow direct messages. When enabled, each
channel message, thread reply, and direct message must mention the bot.
Direct messages must also be allowed.

**Reason and benefit**

Users can prevent ordinary conversation from starting agent work.

**Breaking changes**

New Slack connections require a bot mention by default. Existing
connections keep their saved setting. Work that has already started is
not cancelled.

**Additional context**

A search for existing at-mention PR titles found no duplicate.

## What Changed

- Add the endpoint field, schema validation, API response, and UI
toggle. New Slack connections enable the setting.
- Add an idempotent database migration and generated metadata. Renumber
it to 0321 after current master.
- Check the current setting at inbound admission, task mutation, and the
first heartbeat queue claim.
- Keep Slack tool access and recovery for already-running work when the
setting changes.
- Cancel queued batches that contain an unmentioned input, including
coalesced messages.
- Dispatch promoted follow-ups after the scheduler releases its agent
start lock. Preserve these checks in the new queue and run-control
modules.
- Filter unmentioned messages without retaining their content.
- Keep provider-message deduplication and existing access checks.
- Add thread, DM, duplicate-delivery, queued-message, and new-connection
default regression tests.
- Document the setting and its scope.

## Verification

- Previous head `16791bb7`: typecheck, build, all server shards, Runner
checks, and E2E passed. Two chat shards failed in three fixtures that
used unmentioned Slack messages.
- Update setup follow-ups to mention the Slack bot. Disable the mention
rule explicitly in the callback ordering test, which tests ordinary
subscribed replies.
- Previous local checks passed: six Slack integration cases, all 46
durable chat scheduler tests, all 24 queue/run-control tests, migration
safety, and UI token gates.
- Greptile reviewed `16791bb7` with 5/5. All review threads are
resolved.
- Head `53163c20f`: all five focused integration cases passed. These
cover all three prior CI failures and both default-on channel/DM cases.
Fresh CI and Greptile are running.
- Full local recursive typecheck, build, and repository tests were not
repeated for this fixture-only change. CI supplies these checks.
- Manual check: create a Slack connection. Require at-mention must be
on. An ordinary thread reply or DM must not wake the agent. A bot
mention must wake it once. Disable the setting and confirm ordinary
replies work again.

## Risks

- The migration adds a non-null boolean with a false default. Apply it
before the new server runs.
- The setting also applies to DMs. The UI help text states this.
- Enabling it blocks queued unmentioned work but does not cancel a run
that has already started.
- Full local verification is limited by the environment constraints
above; latest-head CI must pass before merge.

## Model Used

OpenAI GPT-6 (Codex agent), with reasoning, tool use, and code
execution. The runtime does not expose a more specific model version or
context-window size.

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-09 14:03:02 -05:00
Nicky LeachandPaperclip 5badea4798 Use the agent lifecycle contract for plugin setup and status (#15391)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Some plugins must prepare resources before an agent can work.
> - Those resources must stop or be removed when the agent pauses or
terminates.
> - The agent lifecycle module now owns these steps and their durable
completion.
> - Plugins use its required callback contract instead of a separate
readiness query.
> - This PR documents that contract and shows its progress and retry
action on the agent page.

## Linked Issues or Issue Description

Refs: #15631

**Subsystem affected**

Required plugin lifecycle work and the agent detail page.

**Problem or motivation**

The lifecycle module exposes `onAgentLifecycle` and
`agents.lifecycle.manage`, but the plugin authoring guide does not
explain their use. The agent page displays legacy status. Setup
therefore looks paused and offers Resume. Termination leaves the page
before resource cleanup completes.

**Proposed solution**

Use the callback, admission guards, persisted state, and retry route
supplied by the lifecycle module. Show pending phases and fixed host
errors. Keep the detail page open during incomplete termination. Use
lifecycle state for pause and resume controls.

**Alternatives considered**

A separate plugin readiness query would duplicate the module's state and
admission rules. The final diff contains no readiness API, database
commit hooks, or second admission check.

## What Changed

- Document the manifest declaration, callback results, phase ordering,
capability scope, retry behavior, and provider revision requirements.
- Correct SDK comments for lifecycle, routing, and external object
callbacks.
- Show preparation, verification, pause, resume, termination, and
cleanup progress from the existing agent fields.
- Refresh pending steps every two seconds and other states every thirty
seconds. Keep these reads separate from the agent record used by
editable forms. Use the existing authorized retry route for failed
steps.
- Offer Pause during setup. Disable pause and resume while stop or
cleanup is incomplete. Keep cleanup failures reachable on the detail
page. Disable new work after termination starts.
- Test required resource work across setup, pause, resume, and confirmed
deletion. Test every worker callback phase, missing handlers, retry
authorization, and UI behavior.

## Verification

- Focused UI tests: 139 passed across lifecycle status, action buttons,
API tests, and the configuration form. A regression preserves unsaved
edits during an in-flight lifecycle refresh and a failed refresh.
- Focused host and shared tests: 113 passed across lifecycle
integration, retry authorization, plugin RPC, and manifest validation.
The database suite used isolated local PostgreSQL 18 through a temporary
loader outside the repository.
- Module boundary tests: 11 passed. Module import/write checks and UI
token gates passed.
- Plugin SDK build, server direct TypeScript check, and UI TypeScript
check passed.
- `git diff --check` and an added-line secrets/private-reference scan
passed. Fixtures use synthetic identities.
- Full `pnpm -r typecheck` and `pnpm build` passed using the existing
local Rust toolchain.
- Visually checked all six progress phases with the application
components and styles. Captured preparation and cleanup failure
screenshots from the production UI build with synthetic API data;
artifacts are kept outside git.
- Full local `pnpm test:run` was attempted and stopped after a
native-runner failure reproduced in isolation:
`native-session-resume.test.ts` / `archives a damaged prior epoch before
completing guarded same-task replacement with real runnerd` returns a
failed Codex fixture result instead of success. The native-runtime and
runner trees are unchanged from the base. No full local test pass is
claimed.
- All latest-head CI checks passed, including test shards, verification,
E2E, and the canary packaging check. Greptile reviewed commit
`96473e03a` at 5/5 with no unresolved comments.

## Risks

- Selected required plugins remain a dependency for lifecycle
completion. The lifecycle module retains their requirements when a
plugin is disabled or removed.
- Plugins must make repeated provider operations safe and fence older
revisions. Host revision checks do not cancel external requests.
- Polling adds one agent-detail read every two seconds during pending
work and every thirty seconds otherwise.
- No schema change, private VM provider implementation, resource
backfill, or deployment is included. No live provider test was run.

## Model Used

OpenAI GPT-6 through Codex, with reasoning, repository inspection, code
editing, and command execution. The exact model revision and context
window were not reported by the runtime.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either linked existing issues or described the issue in-PR
- [x] I have not referenced internal or instance-local Paperclip issues
or links
- [x] My branch name describes the change and contains no internal
ticket id
- [x] I have run focused tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented risks
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no unresolved comments
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-09 11:15:24 -07:00
DottaandPaperclip 556daf9a99 feat(dot): run cloud assignments in managed sandboxes (#15691)
## Thinking Path

> - Paperclip manages agents and governs their work.
> - The Runner owns execution and task authority.
> - Dot executes at OpenAI and uses Paperclip through MCP.
> - Dot previously required a self-hosted controller.
> - Cloud must admit Dot work in a managed sandbox and keep protocol
traffic in the tenant.
> - This pull request adds managed Dot execution and dedicated pairing
routes.
> - The same Runner path can later host sandboxed workspace tools.

## Linked Issues or Issue Description

**Agent or provider**

OpenAI Dot, through the existing dedicated MCP adapter. Related changes:
#15402, #15414, and #15581.

**Why this adapter is useful**

Cloud users need to assign work to Dot and let Dot request work while
idle. Neither path should execute agent commands on the control-plane
host or require an idle sandbox.

**How the agent is invoked**

The tenant serves OAuth, signed mailbox events, and scoped tools. Normal
admission creates a managed sandbox for each assignment. A verified Rust
Runner owns that assignment and relays its tools and results.

## What Changed

- Enable the external-agent invitation in Cloud behind the standalone
Dot flag.
- Launch Dot through the existing managed process launcher and
authenticated PRP transport.
- Verify the artifact digest and Dot capability before dispatch. Read
provider checkpoints from the execution target for recovery.
- Reject local execution in Cloud and reject managed workspace access
for this release.
- Add dedicated public Dot pairing aliases. Preserve the personal
assistant consent paths.
- Keep Dot events in the tenant when a personal Cloud broker is
configured.
- Use the app-configured heartbeat for Dot-initiated work. Report
terminal admission failures and fence stranded offers before new
admission.
- Offer normal comments through the active assignment's mailbox. Keep
their wakes deferred until a successful history receipt contains the
exact IDs; preserve unread comments through finish, batching and
recovery without replaying consumed input.
- Require a sandbox process fingerprint before dispatch and allow a
bounded five-minute controller reconnect gap. Preserve remote process
birth without inspecting a colliding controller PID.
- Recognize authenticated remote shutdown receipts even without an OS
exit code.
- Document dedicated pairing aliases and teach route coverage to inspect
literal path arrays.
- Add opt-in private Daytona qualification and focused contract tests.

## Verification

- Workspace typecheck, production build, and UI token gates passed.
- Focused onboarding, OAuth, managed environment, artifact metadata, and
terminal-fence tests passed. One environment-test timeout passed on an
isolated repeat.
- A private Daytona fixture passed with the real Rust Runner, signed
readiness, assigned app tools, document writes, duplicate receipts,
authority fences, completion, and sandbox deletion.
- A real OpenAI Dot completed both an operator-assigned task and a
Dot-initiated task in managed Daytona sandboxes. Both leases were
released.
- A real accepted Dot assignment survived a controller gap longer than
one minute with the same sandbox process, Runner, session, and
assignment. Dot consumed the normal task-comment follow-up and completed
exactly once; the lease was released.
- A real cancellation fenced an accepted assignment, released its lease,
and received Dot's acknowledgement without claiming a global provider
stop.
- Final local checks: 74 Dot execution, OAuth onboarding and API
contract tests after integrating the current agent-lifecycle changes, 9
real Rust driver tests, 21 remote-runtime tests plus the 3
detached-process cleanup tests, and 17 lifecycle tests passed. The final
live Daytona fixture passed and deleted its sandbox.
- A final real Dot follow-up stayed pending until its exact comment
appeared in a successful history receipt. Dot completed the original
managed assignment once; its lease was released.
- The broad local suite crossed a rebase and was stopped; its failures
are not a qualification of this final source. Focused repeats passed.
The final head passed all CI gates: workspace types, build, general and
serialized test suites, Rust and Runner verification, all browser
shards, and the canary dry run. Greptile is 5/5 with both findings
resolved.

## Risks

- Deploy the tenant app with its current Linux Runner artifact and the
corresponding front-door protocol routes together.
- This branch has not been deployed to a Cloud tenant. A deployed tenant
still needs an OAuth and assignment smoke test.
- Dot provider usage and cost are unmetered. Revocation fences Paperclip
tools and does not prove a global OpenAI stop.
- Missing or changed recovery identity fails closed. No replacement Dot
thread is invented.
- No schema migration is added. Managed Dot workspace access remains
unavailable.

## Model Used

OpenAI Codex, based on GPT-6, with reasoning, tool use, code execution,
and browser testing. The exact runtime model identifier and
context-window size are not exposed in this session.

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-09 12:58:35 -05:00
DottaandPaperclip 0726a00e80 feat(apps): qualify Bitly, Context7, Hugging Face and Resend MCP (#15686)
## Thinking Path

> - Paperclip lets people manage AI agents and govern their tools.
> - Apps already supports provider-hosted MCP servers.
> - Useful providers still need real setup and read proof before Browse
exposure.
> - Browser testing found a Bitly token-format failure and an OAuth
callback that replaced an explicit empty agent selection.
> - This PR qualifies four provider methods and fixes those shared OAuth
paths.
> - Providers that still need login or approval remain withheld from new
Browse listings.

## Linked Issues or Issue Description

Refs: #15621, the merged hosted MCP qualification batch. Searches found
no duplicate Bitly or Context7 implementation PR.

**What existing behavior does this improve?**

Apps setup, provider MCP discovery, token exchange, and saved agent
access through an OAuth callback.

**Subsystem affected**

Shared Apps definitions, the server tool-access service, and the UI
setup/recovery route.

**Current behavior**

Bitly's callback can fail with `oauth_access_token_missing` when its
token response is not JSON. Curated MCP callbacks can treat an
explicitly saved empty install set as access for all agents. Context7 is
hidden and Hugging Face lacks a curated anonymous method. Saved drafts
for hidden providers cannot finish setup through their catalog wizard.

**Proposed behavior**

Request JSON token responses. Record explicit remote MCP install choices
in the install transaction and preserve them at callback. Keep managed
subject/default access when no choice was saved. Expose the qualified
Bitly and Context7 methods, add anonymous Hugging Face Hub access, and
record Resend qualification. Resume hidden providers only through an
exact matching company-visible saved draft.

**Reason and benefit**

People can connect useful hosted tools through the existing Apps flow.
An explicit zero-agent selection survives authorization. Public
documentation lookups need no OAuth app, account, or key.

**Breaking changes**

Explicitly saved empty MCP install choices now remain empty. Existing
managed defaults without a saved choice retain their behavior. No schema
migration or API shape change.

## What Changed

- Qualify Bitly OAuth, Context7 public MCP, Hugging Face public MCP, and
Resend OAuth with real browser setup, useful UI reads, and reload
checks.
- Negotiate JSON OAuth token responses and preserve explicitly saved MCP
agent reach with a transactional config marker.
- Add durable provider overrides, permission reviews, dated text-only
evidence, and official branding provenance. Remove all seven evidence
images and their report references.
- Restore Finish setup for hidden-provider drafts with
company/application/provider checks; keep fresh setup withheld. Preserve
success after the exact resumed draft becomes active, and restore valid
completed URLs to that exact saved Permissions page; reject initially
active, disabled, or archived resume targets. Align the Context7 route
assertion with its new qualified availability.
- Retain hidden ClickUp, Klaviyo, and monday.com research with exact
login/approval gates. monday.com requires provider callback
allowlisting.

## Verification

- Connector service suite: 420 passed, including
default/empty/agent/company reach and managed OAuth lifecycle coverage.
- Shared catalog: 36 passed. Override tests: 3 passed. Brand checks: 101
identities passed.
- Focused UI setup/recovery, Browse, and OAuth-helper suites: 306
passed. Actual hidden-draft resume/reload passed; a public Context7
draft seeded in the isolated app completed through the active-state
refetch and persisted with zero agents after reload. The completed URL
refresh and View connection open the exact saved Permissions page. Fresh
hidden setup, normal initially active resume, disabled/archived status,
and provider mismatch are rejected; a draft at the completion stage
stays in setup.
- Recursive typecheck and build passed again after rebase. The full
local Vitest run began before rebase and was cancelled as superseded
while still in the general-server phase; it is not a completed pass.
Exact-head CI supplies broad coverage. The focused connector service
suite passed against the final code. UI typecheck, build, and token
gates passed again after the draft-recovery fix.
- Targeted mock MCP Playwright journey: 1 passed (34.9s). It now
verifies View connection reaches the exact saved Permissions route, both
discovered actions, and reload persistence. This replaces the stale
Browse expectation found by CI.
- All CI gates passed on final commit
`32bb4c6422411eee632486950e45e2735102d1b3`. The inherited-pause test
timed out in the cleanup run and passed on one retry without code
changes; the entire file also passed locally, 36/36. Its exact timing
cause remains unresolved. A signoff timeout on the preceding
production-code commit also passed on its single retry. Greptile
reviewed the final commit at 5/5 with no open findings.
- Actual UI reads: Bitly current-user read; Resend List Domains
including a fresh setup after the final callback refinement; Context7
React docs; Hugging Face public docs search. No provider writes or real
agent runtimes ran.
- [Text-only qualification
report](https://github.com/paperclipai/paperclip/blob/32bb4c6422411eee632486950e45e2735102d1b3/doc/connections/easy-mcp-batch-2-2026-10-09.md)
include evidence limits and exact blockers. Account/profile/domain
results are omitted.

## Risks

- Bitly `mcp.all` and Resend `full_access` remain broad provider grants.
Qualification kept writes Off and selected no agents. Read proof does
not establish write behavior or refresh rotation.
- The explicit-choice marker applies to new install saves; older
unmarked flows keep their existing defaults. Its JSONB merge avoids
overwriting concurrent config fields.
- Public provider catalogs and rate limits can change. Unqualified
providers remain withheld from new Browse entries; retained connections
remain available for recovery.

## Model Used

OpenAI Codex, based on GPT-6, plus OpenAI `gpt-6-luna` subagents for
provider research, browser testing, and review. The exact primary
serving variant and context-window size are not exposed by this runtime.
Used reasoning, code execution, and browser tools.

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-09 11:52:33 -05:00
DottaandPaperclip 6080daf262 fix(runner): start native OpenCode without postinstall (#15702)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Paperclip Runner starts a qualified OpenCode runtime for native
tasks.
> - The default launch path uses a file populated by OpenCode's
postinstall script.
> - Package managers can skip that script and leave a text placeholder.
Native task startup then fails with `spawn ENOEXEC` before the model
request.
> - This pull request resolves the declared platform package directly
and includes the pinned runtime in the published server dependency
graph.
> - Users can run native OpenCode tasks after a normal install without
global commands or manual dependency repair.

## Linked Issues or Issue Description

**What happened?**

Native OpenCode tasks fail at session startup when dependency
postinstall is skipped. The Runner selects
`opencode-ai/bin/opencode.exe`, which contains a text placeholder. The
published server also lacks the OpenCode runtime dependency used by its
vendored Runner.

**Expected behavior**

Paperclip starts the qualified platform binary installed by the package
manager. macOS uses a Mac binary. No manual postinstall command is
needed.

**Steps to reproduce**

1. Install dependencies with lifecycle scripts disabled.
2. Configure a native OpenCode agent with an OpenRouter model and valid
credentials.
3. Assign a task. The previous default fails before any model request.

Related work: #15682 fixes HTTP transport registration. #15422 includes
compatible OpenCode resolution in a broader agent setup change. This PR
isolates the runtime repair for current users.

## What Changed

- Resolve pinned OpenCode platform packages through the module
dependency graph in source, standalone, and vendored server layouts.
- Check package identity, version, platform, executable containment, and
execute permission. Preserve verified executable launch profiles.
- Use the resolver for new and resumed native sessions. Reject missing
remote pack executables before controller dependency lookup.
- Declare `opencode-ai@1.18.34` as a published server dependency. Leave
platform selection to the consumer's package manager.
- Check remote paths for the selected provider only. An unused OpenCode
path must not reject a Pi run on macOS.
- Add skipped-postinstall and invalid artifact regressions. Document
automatic runtime selection.

## Verification

- Regression tests fail with the previous default path and pass with
platform resolution.
- Source, standalone, and vendored layout fixtures cover Apple Silicon,
Intel Mac, and Linux x64 baseline packages.
- A fresh npm install with `--ignore-scripts` resolves the macOS
executable and reports `1.18.34`. The placeholder remains unchanged.
- Live browser test on Apple Silicon: a native
OpenCode/OpenRouter/DeepSeek task ran shell arithmetic, created and
uploaded a verified 23-byte file, and completed. A follow-up ran shell
arithmetic and completed using the same session. Both runs committed
successfully while the wrapper remained broken.
- `pnpm -r typecheck` and `pnpm build` passed. All 269 affected Runner
tests and 8 server packaging tests passed. `pnpm test:run` encountered
15 initial database-heavy failures; all 15 passed on an isolated group
rerun. The redundant local run was then stopped after the matching
server and workspace CI suites passed. All final-head checks passed (56
passed, 2 skipped); its unrelated chat-retry browser assertion passed on
one rerun. An additional local repeat could not start its temporary
server within the startup timeout. Greptile reviewed the final head at
5/5 with no open findings.

## Risks

- Native runtime resolution requires the pinned optional platform
package. Installations that omit optional dependencies fail with an
explicit runtime error.
- Supported native targets remain Apple Silicon, Intel Mac, and Linux
x64. This change does not qualify another platform.
- Published server installations now install the OpenCode dependency.
Remote provider packs retain their verified executable paths and
digests.
- No schema changes or agent configuration migration.
- Repository policy assigns `pnpm-lock.yaml` to CI. PR CI refreshes
dependency resolution before frozen installs, and the master workflow
updates the tracked lockfile. This PR leaves the tracked lockfile
unchanged.

## Model Used

- OpenAI GPT-6 through Codex, with reasoning, tool use, and code
execution. The session does not expose the exact GPT-6 variant or
context window.
- Live verification used OpenRouter `deepseek/deepseek-v4-flash-0731`;
it did not author this patch.

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-09 11:46:15 -05:00
2bc88ca1c5 build(deps): bump ws and @types/ws (#15164)
Bumps [ws](https://github.com/websockets/ws) and
[@types/ws](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/ws).
These dependencies needed to be updated together.
Updates `ws` from 8.21.3 to 8.22.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/websockets/ws/releases">ws's
releases</a>.</em></p>
<blockquote>
<h2>8.22.0</h2>
<h1>Features</h1>
<ul>
<li>Introduced the <code>protocols</code> option (8b918b01).</li>
</ul>
<h1>Bug fixes</h1>
<ul>
<li>Calling <code>websocket.close()</code> with invalid arguments no
longer transitions the
state to <code>WebSocket.CLOSING</code> (<a
href="https://redirect.github.com/websockets/ws/issues/2337">#2337</a>).</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/websockets/ws/commit/297202cdae9b0590629821373b3b679c407f3431"><code>297202c</code></a>
[dist] 8.22.0</li>
<li><a
href="https://github.com/websockets/ws/commit/8b918b01c149c6e4ccb8051bace7f322db94ed8b"><code>8b918b0</code></a>
[feature] Introduce the <code>protocols</code> option</li>
<li><a
href="https://github.com/websockets/ws/commit/73e03eb35b1a84a3b28f906bab6a359231660695"><code>73e03eb</code></a>
[ci] Update actions/setup-node action to v7</li>
<li><a
href="https://github.com/websockets/ws/commit/d9b89544e627f2a260fb85a6f42c8ecba98d7615"><code>d9b8954</code></a>
[fix] Change the ready state after validating the arguments (<a
href="https://redirect.github.com/websockets/ws/issues/2337">#2337</a>)</li>
<li>See full diff in <a
href="https://github.com/websockets/ws/compare/8.21.3...8.22.0">compare
view</a></li>
</ul>
</details>
<br />

Updates `@types/ws` from 8.18.1 to 8.18.2
<details>
<summary>Commits</summary>
<ul>
<li>See full diff in <a
href="https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/ws">compare
view</a></li>
</ul>
</details>
<br />

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: nickyleach <331803+nickyleach@users.noreply.github.com>
Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-09 09:27:45 -07:00
Nicky LeachandPaperclip 2dd9811e8b Own agent hiring and termination in a lifecycle module (#15631)
## Thinking Path

> - Paperclip manages AI agents and their work.
> - Agent creation, approval, pause, and termination change whether an
agent can work.
> - These changes currently use separate service and database paths.
> - Some agents need setup after their record exists and before their
harness can run.
> - This PR adds one module that owns those state changes and their
transactions.
> - The module records progress and retries incomplete work after a
server restart.

## Linked Issues or Issue Description

**Problem or motivation**

A hire can become active before its execution environment is ready.
Direct agent state writes also bypass one common lifecycle boundary.
Termination does not have a durable step for resource cleanup.

**Proposed solution**

Use agent lifecycle commands for hiring, approval, pause, resume, and
termination. Keep proposed hires pending until approval. Prepare each
approved hire, test its saved harness configuration, and then permit
work. Wait for required plugin work before completing a step.

**Alternatives considered**

A general database commit hook would expose transaction details to
callers. A timer alone would delay each new hire. This module owns each
command transaction and starts its worker after commit. A periodic scan
recovers work after a process stops.

**Roadmap alignment**

This change adds the lifecycle boundary for the existing agent and
plugin systems. It does not add a user interface or a provider
implementation. It replaces the lifecycle delivery approach in #15391.
Related proposals include #11475 and #13099; this change does not add
their external executor protocols.

## What Changed

- Add durable approval, preparation, verification, pause, resume, stop,
and cleanup states.
- Keep agent creation, lifecycle state, configuration writes, and agent
record deletion behind `modules/agent-lifecycle`. Keep validation,
credential rules, reads, onboarding, invitations, general approvals, and
company data deletion in their services.
- Commit a hire before the remaining onboarding or invitation work.
Serialize requests with the existing dedicated database connection
helper. Reuse the hire after a failed attempt.
- Keep accepted work in the run queue during setup. Require execution
and cleanup evidence before completing pause or termination.
- Retain the original credential owner when approving migrated hires.
- Start lifecycle work after each command commits. Use database leases
and revision checks for retries and late results.
- Add a generic required plugin method and capability. Store the
required plugin IDs for each agent. Track host and plugin completion
separately.
- Keep harness verification and credential rules in services. Supply
their results to lifecycle through explicit ports. Reject failed logins
and incomplete probes.
- Remove reverse imports from lifecycle adapters into services. Share
record queries and validation below both layers.
- Use one hire decision path for agent IDs and approval IDs. Resolve the
approval and agent change in one transaction. Expose policy
reconciliation on the command object.
- Save configuration and verification invalidation through one module
operation. Ordinary commands own their transaction. Restrict the shared
transaction integration to its listed callers. Reject identity, company,
accounting, timestamp, and unknown fields.
- Require completed termination before deleting agent records. The
company deletion service calls the module through a separate deletion
interface.
- Save an approved secret before applying its agent binding. A failed
binding leaves the secret approved. A retry reuses it.
- Remove old permission and metadata export files. Move hire
configuration rules out of lifecycle persistence.
- Report failed worker steps and scans with operation context and known
error codes. Omit provider messages, stacks, and configuration values.
Document ordinary application use and extension rules.
- Recover expired native owners only after execution stops. Retry
cleanup of failed retained leases. Wait for setup in the live smoke
script.
- Keep manual, budget, and company pause reasons separate. Guard
execution status writes with the ready state.
- Add a migration, boundary checks, regression tests, and a lifecycle
guide. Keep the current UI.
- Limit periodic policy checks to 100 eligible agents per minute.
Continue from the last agent ID. Exclude pending hires and agents in
termination or a final state. Keep explicit company and budget updates
immediate.

## Verification

- Latest head `ccc3c86b0` aligns the shared status update schema with
the PATCH route. All 15 shared tests, 104 server route/OpenAPI tests, 2
CLI tests, and shared/server/CLI TypeScript checks pass. The Greptile
comment is fixed. CI is running; no new Apex review was requested for
this small fix.

- Rebase `75708ac94` rebases onto master at `2eb5187e4`. The backup test
uses the shared 90-second timeout from master; the older timeout commit
was removed. The affected backup test passes.
- Agent budget edits now pass the target agent ID through enforcement.
All 50 affected tests, server TypeScript, and 11 boundary tests pass.
Both configuration update paths have regression coverage. CI is running
on the latest head. No new Apex review was requested for these small
fixes.

- Rebase `9b568666a` preserves the run-control extraction and
delivery-work startup changes from master. All 559 affected tests,
server TypeScript, and 11 boundary tests pass. CI and Apex review are
running on the final head.
- The policy scan fix passes 56 lifecycle and diagnostic tests, 24
policy and caller tests, and 11 boundary tests. A regression test checks
the page limit, interval, excluded states, and cursor wraparound.

- Rebase `fd4698750` passes all 611 tests in eight affected lifecycle,
route, and heartbeat suites. Server TypeScript and all 11 module
boundary tests pass. The company deletion rollback and concurrent hire
tests are included.

- Follow-up `00aac7646` fixes the failed decision deletion test and the
public update schema. All 126 affected server tests, 8 shared tests, 2
CLI tests, and 11 boundary tests pass. Shared, server, CLI, and UI
TypeScript checks pass.

- Server TypeScript passes: `pnpm --filter @paperclipai/server exec tsc
--noEmit`.
- All 11 boundary tests pass: `node --test
scripts/check-module-boundaries.test.mjs`. The repository boundary scan
also passes.
- All 68 lifecycle, failure diagnostic, and harness verification tests
pass. Tests reject forbidden fields through the root command, combined
transition command, and restricted transaction integration. They also
check invalid fields returned by configuration preparation.
- Failure tests cover host work, plugin work, claims, renewals,
deferrals, and scans. Log tests check known error codes and exclusion of
private error contents.
- All 355 tests in 10 existing caller suites pass. These tests cover
secret approval, pairing, pending hires, credentials, company import,
built-in agents, managed agents, instructions, and skills.
- The branch is rebased onto `origin/master` at `2eb5187e4`. The queue
guards and cancellation lock fix use the extracted heartbeat queue.
Agent cancellation uses the extracted run-control file. The source diff
scan found no secrets or private URLs.
- Earlier checks cover approval retries, rollback, late verification
results, policy holds, deletion rollback, concurrent company deletion,
and queue admission during setup.
- Before the rebase, CI passed on `00aac7646` and Greptile Apex rated it
5/5 with no open comments. CI and a new Apex review are pending for the
rebased commit. The branch has no merge conflicts.
- The full local build and native Dot suite were not run. The host has
no Cargo. No live provider test was run.

## Risks

- Background policy recovery takes more than one minute when more than
100 agents are eligible. Explicit company and budget updates still
reconcile immediately.

- The restricted configuration integration keeps an agent reference and
its dependent records in one transaction. It cannot change a budget or
invoke a lifecycle transition. A periodic scan starts pending setup
after that transaction commits.
- Secret approval and binding use separate transactions. A failed
binding can leave an approved secret with no agent binding.
- New approved hires remain unavailable until setup and verification
complete. Existing clients see `paused` during these steps. This PR does
not change the UI.
- Migration `0320_daily_onslaught.sql` maps existing statuses and pause
reasons. It does not create external resources or claim that an existing
harness passed verification.
- Use a coordinated server update for this migration. Older server
versions can write legacy status without the new lifecycle checks.
- A failed onboarding or invitation request can leave a committed hire.
A retry reuses that hire and completes the remaining records.
- Deletion requires completed termination. Company deletion can require
another request while cleanup is pending.
- Required plugins must make repeated calls safe and reject older
revisions. A disabled or removed required plugin blocks completion until
it is restored.
- A new hire can run a second harness test after the existing UI test.
Some adapters can charge for this test.
- No live provider test was run. Provider implementation and resource
backfill remain separate work.

## Model Used

OpenAI GPT-6 through Codex, with reasoning, code tools, and local test
execution.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have described the issue in this PR with the feature request
field labels
- [x] I have not referenced internal or instance-local issues or links
- [x] My branch name describes the change
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation
- [x] I have considered and documented risks
- [x] Targeted local tests pass
- [x] All Paperclip CI gates are green on the new commit
- [x] Greptile Apex is 5/5 with no open comments on the new commit
- [x] I will address review comments before requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-09 09:05:12 -07:00
Dotta 2eb5187e43 Runner/Pi 2/5: document setup and fix CI fixtures (#14922)
## Thinking Path

> - Paperclip manages AI agents and their work.
> - The experimental Runner owns provider processes and durable
sessions.
> - Pi needs working task execution and human controls.
> - The five-PR stack must preserve changes already on master.
> - The runtime implementation has merged in #14921; this layer carries
setup documentation and a narrowly scoped CI fixture repair.
> - This PR belongs to native GitHub stack #15602, ending at #14956.

## Linked Issues or Issue Description

Refs #14436, #14631, #14743 and #14956.

Ship Pi 1.0 through the experimental Paperclip Runner. The five PRs are
#14921, #14922, #14923, #14924 and #14956. The user authorized the
complete merge after checks pass. Existing `pi_local` execution is
unchanged. Accounting and wider provider/platform qualification remain
deferred.

## What Changed

- Create the warm Pi fake sidecar and its directory with explicit
private modes, independent of the runner umask. Preserve the
qualified-asset permission guard and every warm-admission timing
assertion.

- Document explicit public Pi host setup and verified Linux companion
import for Daytona.
- Preserve historical installation and qualification checkpoints with
their original source identities.
- Use the repository's existing `EMBEDDED_POSTGRES_TEST_TIMEOUT_MS` for
the backup error fixture, which starts a real PostgreSQL cluster.
Preserve all error, archive, and retention assertions.

## Verification

- Full local `pnpm -r typecheck` passes, including Runner Rust, server
and UI. Focused integration checks pass: 194 Runner
admission/environment tests, 63 profile/credential tests with one
expected skip, 152 Dot/UI configuration tests, and Pi transcript/notice
tests.
- Full local `pnpm build` passes on the final source.
- Fresh final-source checks pass: all 698 Rust workspace tests (32
binaries), 156 credential/profile/controller tests with one expected
skip, Runner TypeScript typecheck, and 20 package/setup/sandbox tests.
- The profile-21 Pi materializer passes on the native host with the
official pinned Node 24.21.0 and its npm. It verifies all 150 locked
packages, the patched dependency and the exact closure. Setup/package
bundle tests and UI token gates pass.
- The old hashes were reproduced for all three supported targets before
calculating the patched graph. New closure hashes are darwin-arm64
`282022db10150c6632b3444df421342e7d534bdf5d5fb1097a2e79d0625a2bcf`,
darwin-x64
`64e251e19009f755c0b04f73ce2138246faab71a961b0f13d75ebfcc34bef12e`, and
linux-x64
`713b1fdff42fb56a1518bdc084f181d70bee8ebadc3e4b1d76321ed9108c8410`.
Independent native platform execution is separate from graph identity
reproduction.
- Historical cloud qualification remains unchanged: all seven core cases
pass on shipping source `10dc43c9ec65d88c2f782d62afb296d09494f215`,
harness `1a4408a48cfb5a1f094a311141c257c92cd7a893`, image
`sha256:5b3a775b383591bda1b0c1889e509acc70ce7f37c53f09733c81d59037f02280`,
and accepted Sonnet 4.6/low fixture. All 215 canonical files and all
seven cleanup checks pass independent verification. These are profile-19
results and are not relabeled as fresh profile-22 runs.
- Current Pi digest:
`sha256:e92078bee3c23bec4100aa589013a44613d054cd686826534025d8019e9f39a9`.
[The readiness
plan](https://github.com/paperclipai/paperclip/blob/codex/pi-production-readiness/doc/plans/2026-10-02-pi-production-readiness.md)
preserves campaign and failed-attempt provenance.
- Merge only after every PR's current-head CI and fresh review pass.
Linux CI covers the full suites, build and browser tests. The local
embedded Postgres API-authority suite cannot start on this macOS/Node 26
host, so Linux CI must confirm that suite.

### Fresh profile-22 core qualification — 2026-10-08

All seven accepted core cases pass canonically on Pi profile 22, with
`openrouter/anthropic/claude-sonnet-4.6` and native-confirmed low
thinking. This model is a fixture; production accepts the caller's
explicit Pi provider/model.

Runtime/install source: `3241a992f2a7703e59e97ed0fd3e5d6405de4401`.
Frozen accepted harness: `1a4408a48cfb5a1f094a311141c257c92cd7a893`.
Immutable cloud image:
`ghcr.io/paperclipai/paperclip-daytona-runner@sha256:506f22db7edd78f37c0c40bec1cc084af1850455026dbf467194bfbb8fcef141`.
Pi digest:
`sha256:e92078bee3c23bec4100aa589013a44613d054cd686826534025d8019e9f39a9`.

[Hosted Linux image and clean-install
verification](https://github.com/paperclipai/paperclip/actions/runs/37868328023)
passes, including all 20 source-bound archives, normal CLI/Pi setup,
companion import and the production pack reader. This exact installation
source includes the latest master integration and the corrected Pi warm
instruction-root fence. Full local typecheck/build and current-head
hosted CI verify the final stack. All 13 focused real-root regressions
pass. The full local executor suite passed 662 tests; 15 database tests
could not start the Mac embedded PostgreSQL service. Hosted Linux CI
passes the full required verification and E2E checks. These fresh
results keep their own source identity; profile-19 results remain
historical.

| Core path | Canonical campaign | Retained archive SHA-256 |
| --- | --- | --- |
| File edit, validation, download and Done |
`pi-core22-replyfix-0-1791511228` | 23 files;
`a473e8603a3dd4737863291f8d3d1e392391f0b16d433c3e0e0e9d8baf7a97b0` |
| Pending question and controller restart |
`pi-core22-replyfix-1-1791511376` | 33 files;
`6b829c4eb74e1f32a89c692a4ae7130dbfc1c6d3cf13915effe2103d9e242c8e` |
| Three-turn session/process/workspace continuity |
`pi-core22-replyfix-2-1791511587` | 23 files;
`7a87021f8f9a3fdd3c58bb4467f8d82c635e3ea4795d6e75f144d9aa14818df8` |
| Four typed questions and browser reconnects |
`pi-core22-replyfix-3-1791511881` | 42 files;
`9e31755252be1f4f9cb0626c984c142d4d1ae5f5bee3a7af08444db8d12c280a` |
| Plan approval and completion | `pi-core22-replyfix-4-1791512031` | 22
files;
`a0383ce1aab38e7b5a25ce0e9dd3bebea5c037ebd96ae6b29dae19015da2ae2c` |
| Same-turn steering and permission denial |
`pi-core22-replyfix-5-1791512261` | 39 files;
`c929b8c7070f0b66aedc17e65ca46e6beab1e363926ac9f7e2a75fb250f05949` |
| Stop during pending permission | `pi-core22-replyfix-6-1791512390` |
33 files;
`7f0a58ae0f4d5bfc76149435f4e322537089c5bd16e7ffe9b5ad71f10a621a07` |

All 215 canonical files (28714587 bytes) are independently
hash-verified. All seven cleanup grades pass, with no owned runtime
process or temporary root after each case. Automatic retries are zero.
The owned cloud host stopped normally after retention. The prior
profile-22 warm attempt remains failed and separately retained: archive
SHA-256
`1e54eba5ec72b50cee1534b23d1d1d4f21a090006b8a64501ba70db972abfde5`. Its
original canonical classification is preserved. Diagnosis reproduced a
product bug comparing an agent-files root against an unset
checkpoint-only field. The fix stores the admitted physical root
separately from the adopted per-run collection capability. The real-root
regression fails before the fix and passes afterward, including
rejection of a changed physical root. Fixture, grader, model and all
seven accepted case IDs are unchanged; this fresh campaign tests
final-reply publication after file registration first. The intermediate
restart attempt also remains failed and retained: archive SHA-256
`5dcaefdf1d17cf4cd54fd4cf810f45e736667392339b8ce7caf08bb4e225277f`. Its
original canonical classification is preserved. Pi resumed, wrote the
verified answer and completed its task; exact runner suspension was
proven, but idle stop consumed about 5.2s and left under 3s for the
drain acknowledgement. The Pi-only default shutdown grace is now 15s,
preserving a full 5s drain round trip and a finite suspension reserve.
Explicit caller deadlines, other provider defaults, literal drain
receipts and exact suspension identity checks remain unchanged. The
timing regression fails before this correction and passes afterward; all
18 focused settlement tests and Runner typecheck pass. The final-source
file attempt is also preserved as failed (`candidate_failure`), archive
SHA-256
`db6767b6773ea618997927ac77bdb005a5ac81492c7b9c0ffbc900449f829bc9`.
Native edit, validation, exact downloadable artifact and Done/succeeded
all passed, and the exact final reply was durably recorded. A workspace
recovery owner completed before the live heartbeat reached presentation,
leaving that reply absent from task chat. Recovery now materializes only
a completed final reply from the accepted turn of an ordinary internal
Done task, preserving issue/run/contract binding, suppression,
external-chat authorization and same-run deduplication. The database
regression covers the generated file-preparation receipt, suppression,
unapproved external continuation and replay. Server typecheck and all 49
response-selection tests pass; hosted Linux verifies the database
regression because embedded PostgreSQL cannot start on this Mac.

The delayed-final-answer database regression passes on [the final
root-source Linux server
shard](https://github.com/paperclipai/paperclip/actions/runs/37868262553/job/113628594152),
alongside 1,108 passing tests. The first root Runner shard had one
unchanged durable-resume test exceed its 5-second timeout; the identical
top-source shard and the isolated exact test passed. One rerun of that
failed job and its required aggregate passed without source or test
changes. The original failed job log and the single-rerun receipt remain
retained.

### October 9 merge verification

Current merge head: `18744bf27490d6f064f9d5bac2c2af202c590a99`. All
current-head checks pass, including `ci / verify` and `ci / e2e`;
exact-head Greptile review is 5/5 with no unresolved threads. Current
master conflicts are resolved. The user authorized the maintainer
override of the code-owner review gate after these checks. The seven
retained live core cases remain bound to source
`3241a992f2a7703e59e97ed0fd3e5d6405de4401` and its recorded cloud image.

## Risks

- The security correction changes the dependency closure and profile
identity. Old sessions must reopen on the new profile. Exact identities
and credential bindings fail closed.
- The runner remains experimental and requires explicit selection.
Legacy Pi Local is unchanged. Caller model IDs pass through; the E2E
model is a fixture.
- Accounting and the broad platform/provider matrix remain deferred.
This merge does not publish a release or deploy a service.

## Model Used

OpenAI GPT-6 through Codex assisted with reasoning, repository
inspection, editing and tool use. The exact serving ID and context
window are not exposed in this session. Final live qualification uses Pi
1.0.0 with `openrouter/anthropic/claude-sonnet-4.6` and native-confirmed
low thinking.

## Checklist

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

> - Paperclip manages AI-agent work and its delivery to users and
agents.
> - Five delivery queues scan the database even when empty.
> - Each queue already has durable rows; empty polling wastes idle
hosting capacity.
> - Producers can register intent inside their existing database
transaction.
> - Central transaction tracking can wake consumers after the outer
commit without extra caller wrappers.
> - A lost response needs reconciliation against PostgreSQL before an
empty queue is safe to leave idle.
> - This change uses one scheduler for outstanding work and lets
settled, empty queues go quiet.

## Linked Issues or Issue Description

Supersedes the closed #15614. Related idle-safety work: #15522 and
#15599.

**What existing behavior does this improve?**

Delivery scheduling for feedback exports, chat completions, connection
continuations, question answers, and tool-action receipts.

**Current behavior**

Feedback scans every five seconds. Four delivery queues scan on the
heartbeat interval, normally 30 seconds. Startup and some event paths
also scan them.

**Proposed behavior**

Each producer awaits one intent registration before its queue write. The
existing `createDb` transaction boundary tracks nested savepoints and
wakes the consumer after outer settlement. Startup scans restore durable
work. Pending rows, failures, and unresolved transactions retain retry
deadlines. Empty, settled queues have no timer or recurring scan.

**Reason and benefit**

Normal delivery starts after commit. Central tracking removes
caller-specific post-commit plumbing. PostgreSQL transaction status
resolves lost responses without new tables or a permanent uncertainty
latch.

**Breaking changes**

No API or schema changes. The notification scope is one DB owner and its
dedicated child pools. Direct SQL, separate roots, and other processes
require an explicit wake/recovery integration. This path requires
PostgreSQL 14+ transaction-information functions; embedded PostgreSQL
uses 18.

## What Changed

- Add one named-deadline scheduler and app-owned coordinator for five
existing queues.
- Instrument `createDb().transaction()` centrally, including nested
savepoints. Dedicated child connections share their owner's signal
scope.
- Register work before the five queue insert paths. The first
registration obtains the outer XID; unrelated transactions issue no
extra SQL. Tool receipt insertion gains a small transaction around its
existing insert.
- Query `pg_xact_status` only for rejected, tracked transactions. Probe
before scanning the queue. Retain the idle hold while PostgreSQL still
reports an in-progress transaction or the probe fails. Release it after
settlement and reconciliation.
- Remove unconditional delivery recovery scans and caller-specific
completion post-commit actions. Retain the existing task-scoped
completion activity fast path and durable claims.
- Coalesce wakes without postponing an earlier deadline. Retry
outstanding rows and failures; suppress dispatch during idle drain while
allowing transaction and queue reconciliation; suppress both during warm
standby. Cancel deadlines and await active delivery sweeps on shutdown.
- Serialize feedback flushes. Vote routes return after saving. Uploads
have a 30-second deadline and shutdown cancellation; unfinished exports
remain recoverable.
- Document the writer contract and update the dated sleep inventory.

## Verification

- Final head: `a4609956841107ad60c4cb50fe2acb05636b1363`.
- Passed: all final-head hosted checks, with 54 successes and two
intentional skips. The full test matrix, typecheck, build, canary, and
aggregate verification passed in [run
37940948440](https://github.com/paperclipai/paperclip/actions/runs/37940948440).
- Passed: Greptile 5/5 on the same head, with a successful check run and
zero unresolved review threads. The branch is mergeable.
- Passed locally after the final rebase: 50 coordinator, scheduler, and
startup tests; server typecheck; server build.
- Passed locally before the final import-only rebase: repo-wide
typecheck and build; 237 PostgreSQL producer/delivery and database
signal tests; feedback, native-question, and idle-safety regression
tests.
- Real PostgreSQL tests hold transactions open after an injected client
response loss, then commit or abort. They verify that an empty scan
cannot clear an in-progress transaction. Another test terminates a real
backend and verifies recovery without replay.
- Coordinator tests cover an hour with no empty-queue timers,
pending/error retries, worker replacement, concurrent writes,
earliest-deadline preservation, rollback during idle drain, committed
work during drain, standby, and shutdown.
- Local `pnpm test:run` was started and stopped after embedded
PostgreSQL startup failures appeared. It did not finish and is not
reported as a pass. Later local database reruns had skipped suites;
those skips are not claimed as verification. The earlier PostgreSQL
tests did execute and pass, and the final hosted full matrix passed.

## Risks

- One XID query is added per transaction that registers delivery work.
Nested transactions share that ID. Registration must be awaited before
writing; new enqueue paths must follow this contract.
- Work signals are local to a DB owner and its dedicated child pools.
Independent roots, direct SQL, or other processes are not observed.
Startup scans recover already committed rows, but do not fence late
transactions from a previous process. Cross-process ownership and
database failover require separate work.
- A database outage or genuinely unresolved transaction keeps an idle
hold until status can be reconciled. No timer clears uncertainty by
assumption.
- These changes remove five empty polling loops. They do not implement
whole-instance sleep, database teardown, or an external waker. The
earliest deadline covers only the registered queues.
- Waiting tool reviews retain their existing retry cadence until their
receipts can be delivered.
- Feedback vote responses no longer wait for the remote upload. Sharing
consent and the saved vote response are unchanged.
- Real hosting-provider sleep and cost savings have not been measured.

## Model Used

OpenAI Codex, GPT-6. Used reasoning, repository inspection, code
editing, and command execution. The runtime did not expose the exact
model revision or context window.

## Checklist


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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-09 10:01:26 -05:00
DottaandPaperclip 57e977be72 feat: integrate Pi 1.0 into the experimental Runner (#14921)
## Thinking Path

> - Paperclip manages AI agents and their work.
> - The experimental Runner owns provider processes and durable
sessions.
> - Pi needs working task execution and human controls.
> - The five-PR stack must preserve changes already on master.
> - Each layer now carries the complete integrated source for a safe
sequential fallback.
> - This PR belongs to native GitHub stack #15602, ending at #14956.

## Linked Issues or Issue Description

Refs #14436, #14631, #14743 and #14956.

Ship Pi 1.0 through the experimental Paperclip Runner. The five PRs are
#14921, #14922, #14923, #14924 and #14956. The user authorized the
complete merge after checks pass. Existing `pi_local` execution is
unchanged. Accounting and wider provider/platform qualification remain
deferred.

## What Changed

- Recover missing final replies after workspace finalization changes
owners, using accepted-turn evidence without rerunning work or granting
external-chat publication.
- Preserve the admitted Pi instruction root across warm runs, while
retaining changed-root rejection.
- Give Pi a bounded 15-second default shutdown grace so stop, drain
acknowledgement and durable suspension can complete. Explicit deadlines
and other providers retain their existing behavior.
- Integrate the Pi 1.0 runtime and master contracts.
- Use Pi profile 22. Preserve explicit caller-selected models and exact
native thinking levels. Keep Pi's wrapper, helper, extension and
question/control behavior unchanged from the qualified profile-19
runtime.
- Preserve master's Dot lifecycle and consent fields, configured task
environment, status guards and current Codex/Claude dependency versions.
Cursor stays qualified. Copilot stays pending; profile 17 binds the
changed shared protocol validation sources.
- Exclude general AWS IAM credentials from Pi static/custom provider
bindings and selected task projections; preserve the provider-scoped
Bedrock bearer key. Profile 21 is retained as historical provenance.
Rust and cloud install probes use the current declaration.
- Patch bundled brace-expansion 5.0.9 to the exact official 5.0.12
payload. Pin the patch and complete runtime closures. Include the patch
in normal installed setup tooling. Keep the upstream Pi shrinkwrap as
provenance and permit only this exact security correction.
- Include current attestation files in the Docker build context. Keep
the repository lockfile unchanged from master. CI and private image
builds resolve manifest changes before their frozen installation.

## Verification

- Full local `pnpm -r typecheck` passes, including Runner Rust, server
and UI. Focused integration checks pass: 194 Runner
admission/environment tests, 63 profile/credential tests with one
expected skip, 152 Dot/UI configuration tests, and Pi transcript/notice
tests.
- Full local `pnpm build` passes on the final source.
- Fresh final-source checks pass: all 698 Rust workspace tests (32
binaries), 156 credential/profile/controller tests with one expected
skip, Runner TypeScript typecheck, and 20 package/setup/sandbox tests.
- The profile-21 Pi materializer passes on the native host with the
official pinned Node 24.21.0 and its npm. It verifies all 150 locked
packages, the patched dependency and the exact closure. Setup/package
bundle tests and UI token gates pass.
- The old hashes were reproduced for all three supported targets before
calculating the patched graph. New closure hashes are darwin-arm64
`282022db10150c6632b3444df421342e7d534bdf5d5fb1097a2e79d0625a2bcf`,
darwin-x64
`64e251e19009f755c0b04f73ce2138246faab71a961b0f13d75ebfcc34bef12e`, and
linux-x64
`713b1fdff42fb56a1518bdc084f181d70bee8ebadc3e4b1d76321ed9108c8410`.
Independent native platform execution is separate from graph identity
reproduction.
- Historical cloud qualification remains unchanged: all seven core cases
pass on shipping source `10dc43c9ec65d88c2f782d62afb296d09494f215`,
harness `1a4408a48cfb5a1f094a311141c257c92cd7a893`, image
`sha256:5b3a775b383591bda1b0c1889e509acc70ce7f37c53f09733c81d59037f02280`,
and accepted Sonnet 4.6/low fixture. All 215 canonical files and all
seven cleanup checks pass independent verification. These are profile-19
results and are not relabeled as fresh profile-22 runs.
- Current Pi digest:
`sha256:e92078bee3c23bec4100aa589013a44613d054cd686826534025d8019e9f39a9`.
[The readiness
plan](https://github.com/paperclipai/paperclip/blob/codex/pi-production-readiness/doc/plans/2026-10-02-pi-production-readiness.md)
preserves campaign and failed-attempt provenance.
- Merge only after every PR's current-head CI and fresh review pass.
Linux CI covers the full suites, build and browser tests. The local
embedded Postgres API-authority suite cannot start on this macOS/Node 26
host, so Linux CI must confirm that suite.

### Fresh profile-22 core qualification — 2026-10-08

All seven accepted core cases pass canonically on Pi profile 22, with
`openrouter/anthropic/claude-sonnet-4.6` and native-confirmed low
thinking. This model is a fixture; production accepts the caller's
explicit Pi provider/model.

Runtime/install source: `3241a992f2a7703e59e97ed0fd3e5d6405de4401`.
Frozen accepted harness: `1a4408a48cfb5a1f094a311141c257c92cd7a893`.
Immutable cloud image:
`ghcr.io/paperclipai/paperclip-daytona-runner@sha256:506f22db7edd78f37c0c40bec1cc084af1850455026dbf467194bfbb8fcef141`.
Pi digest:
`sha256:e92078bee3c23bec4100aa589013a44613d054cd686826534025d8019e9f39a9`.

[Hosted Linux image and clean-install
verification](https://github.com/paperclipai/paperclip/actions/runs/37868328023)
passes, including all 20 source-bound archives, normal CLI/Pi setup,
companion import and the production pack reader. This exact installation
source includes the latest master integration and the corrected Pi warm
instruction-root fence. Full local typecheck/build and current-head
hosted CI verify the final stack. All 13 focused real-root regressions
pass. The full local executor suite passed 662 tests; 15 database tests
could not start the Mac embedded PostgreSQL service. Hosted Linux CI
passes the full required verification and E2E checks. These fresh
results keep their own source identity; profile-19 results remain
historical.

| Core path | Canonical campaign | Retained archive SHA-256 |
| --- | --- | --- |
| File edit, validation, download and Done |
`pi-core22-replyfix-0-1791511228` | 23 files;
`a473e8603a3dd4737863291f8d3d1e392391f0b16d433c3e0e0e9d8baf7a97b0` |
| Pending question and controller restart |
`pi-core22-replyfix-1-1791511376` | 33 files;
`6b829c4eb74e1f32a89c692a4ae7130dbfc1c6d3cf13915effe2103d9e242c8e` |
| Three-turn session/process/workspace continuity |
`pi-core22-replyfix-2-1791511587` | 23 files;
`7a87021f8f9a3fdd3c58bb4467f8d82c635e3ea4795d6e75f144d9aa14818df8` |
| Four typed questions and browser reconnects |
`pi-core22-replyfix-3-1791511881` | 42 files;
`9e31755252be1f4f9cb0626c984c142d4d1ae5f5bee3a7af08444db8d12c280a` |
| Plan approval and completion | `pi-core22-replyfix-4-1791512031` | 22
files;
`a0383ce1aab38e7b5a25ce0e9dd3bebea5c037ebd96ae6b29dae19015da2ae2c` |
| Same-turn steering and permission denial |
`pi-core22-replyfix-5-1791512261` | 39 files;
`c929b8c7070f0b66aedc17e65ca46e6beab1e363926ac9f7e2a75fb250f05949` |
| Stop during pending permission | `pi-core22-replyfix-6-1791512390` |
33 files;
`7f0a58ae0f4d5bfc76149435f4e322537089c5bd16e7ffe9b5ad71f10a621a07` |

All 215 canonical files (28714587 bytes) are independently
hash-verified. All seven cleanup grades pass, with no owned runtime
process or temporary root after each case. Automatic retries are zero.
The owned cloud host stopped normally after retention. The prior
profile-22 warm attempt remains failed and separately retained: archive
SHA-256
`1e54eba5ec72b50cee1534b23d1d1d4f21a090006b8a64501ba70db972abfde5`. Its
original canonical classification is preserved. Diagnosis reproduced a
product bug comparing an agent-files root against an unset
checkpoint-only field. The fix stores the admitted physical root
separately from the adopted per-run collection capability. The real-root
regression fails before the fix and passes afterward, including
rejection of a changed physical root. Fixture, grader, model and all
seven accepted case IDs are unchanged; this fresh campaign tests
final-reply publication after file registration first. The intermediate
restart attempt also remains failed and retained: archive SHA-256
`5dcaefdf1d17cf4cd54fd4cf810f45e736667392339b8ce7caf08bb4e225277f`. Its
original canonical classification is preserved. Pi resumed, wrote the
verified answer and completed its task; exact runner suspension was
proven, but idle stop consumed about 5.2s and left under 3s for the
drain acknowledgement. The Pi-only default shutdown grace is now 15s,
preserving a full 5s drain round trip and a finite suspension reserve.
Explicit caller deadlines, other provider defaults, literal drain
receipts and exact suspension identity checks remain unchanged. The
timing regression fails before this correction and passes afterward; all
18 focused settlement tests and Runner typecheck pass. The final-source
file attempt is also preserved as failed (`candidate_failure`), archive
SHA-256
`db6767b6773ea618997927ac77bdb005a5ac81492c7b9c0ffbc900449f829bc9`.
Native edit, validation, exact downloadable artifact and Done/succeeded
all passed, and the exact final reply was durably recorded. A workspace
recovery owner completed before the live heartbeat reached presentation,
leaving that reply absent from task chat. Recovery now materializes only
a completed final reply from the accepted turn of an ordinary internal
Done task, preserving issue/run/contract binding, suppression,
external-chat authorization and same-run deduplication. The database
regression covers the generated file-preparation receipt, suppression,
unapproved external continuation and replay. Server typecheck and all 49
response-selection tests pass; hosted Linux verifies the database
regression because embedded PostgreSQL cannot start on this Mac.

The delayed-final-answer database regression passes on [the final
root-source Linux server
shard](https://github.com/paperclipai/paperclip/actions/runs/37868262553/job/113628594152),
alongside 1,108 passing tests. The first root Runner shard had one
unchanged durable-resume test exceed its 5-second timeout; the identical
top-source shard and the isolated exact test passed. One rerun of that
failed job and its required aggregate passed without source or test
changes. The original failed job log and the single-rerun receipt remain
retained.

### October 9 merge verification

Current merge head: `5a8fe63512a7166aaef5cf50065a25008aa8b44b`. All
current-head checks pass, including `ci / verify` and `ci / e2e`;
exact-head Greptile review is 5/5 with no unresolved threads. Current
master conflicts are resolved. The user authorized the maintainer
override of the code-owner review gate after these checks. The seven
retained live core cases remain bound to source
`3241a992f2a7703e59e97ed0fd3e5d6405de4401` and its recorded cloud image.

## Risks

- The security correction changes the dependency closure and profile
identity. Old sessions must reopen on the new profile. Exact identities
and credential bindings fail closed.
- The runner remains experimental and requires explicit selection.
Legacy Pi Local is unchanged. Caller model IDs pass through; the E2E
model is a fixture.
- Accounting and the broad platform/provider matrix remain deferred.
This merge does not publish a release or deploy a service.

## Model Used

OpenAI GPT-6 through Codex assisted with reasoning, repository
inspection, editing and tool use. The exact serving ID and context
window are not exposed in this session. Final live qualification uses Pi
1.0.0 with `openrouter/anthropic/claude-sonnet-4.6` and native-confirmed
low thinking.

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-09 08:56:41 -05:00
DottaandPaperclip 6f9d0a56ba fix: resolve installed Codex and preserve npm host dependencies (#15555)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Installed agents need their own runtime dependencies.
> - Native Codex startup and browser login could depend on a global CLI.
> - npm bundles do not inherit workspace dependency overrides or
patches.
> - Codex native packages must come from npm for the consumer host.
> - This PR fixes executable resolution and the required npm dependency
layout.
> - Usable installed CLI versions can run without a numeric version
gate.

## Linked Issues or Issue Description

Refs: #15422. This is a prerequisite for the later Codex-default change.

**What happened?**

Packaged native Codex startup and browser login could require a global
Codex CLI. The server's vendored runner lacked its own declared Codex
bridge. A bundled wrapper could retain producer-host binaries or select
the legacy adapter's separate platform version.

**Expected behavior**

Prefer the installed Codex executable. Accept usable older or newer
versions. Use the selected host's PATH when the dependency is absent.
Keep the patched JavaScript graph. Let npm install official native
packages for the consumer platform. Grant sandbox reads only to the
selected vendor resources.

**Steps to reproduce**

1. Prepare a clean npm installation without a global Codex command.
2. Start native Codex or its browser login.
3. Inspect the selected executable, installed host package, and sandbox
resource paths.

**Paperclip version or commit**

Frozen master base: `1881894973a2b25838d8abed9bd8aeebc3af4441`.

**Deployment mode**

Source and packaged self-hosted installation.

## What Changed

- Share installed Codex command resolution across native startup, direct
evals, and browser login. Accept usable version differences. Preserve
explicit commands, recorded sessions, remote host boundaries, and the
Linux ARM64 legacy login path. Return safe errors for missing
executables and failed login terminals.
- Declare the server's Codex bridge. Retain the patched JavaScript
dependency graph in npm packages. Strip Codex native payloads. Declare
official optional host packages on the published server manifest so
native and legacy versions remain separate. Preserve consumer esbuild
platform dependencies.
- Adjust resource lookup for npm's separate platform packages. Retain
package identity, path containment, resolver ownership, and narrow
sandbox reads. Keep exact version and digest checks for explicit ACPX
artifact qualification.
- Extend existing packaging, installed-consumer, login, selection,
recovery, and integrity tests. Document the retained behavior.

The diff is now 23 files, 1,709 additions, and 53 deletions. The prior
diff had 35 files and about 3,700 changed lines. Removed work is
preserved on `codex/runner-packaging-full-snapshot` at
`6f3060beaa842ffcee21af058370d3cab5f571e9`.

Removed from this PR: release workflows and assembly, provider-pack
changes, Docker materialization, Git installer changes, extra login
HOME/working-directory isolation, and unrelated CI fixture repairs. This
PR does not change agent defaults, stored runner choices, UI, schema, or
provider qualification.

## Verification

- Final candidate: `dde37d7ed0121c10b60b8801eda80f8dc17909ad`. [All 47
ordinary CI jobs
passed](https://github.com/paperclipai/paperclip/actions/runs/37842288835)
on attempt 1, including typecheck, tests, build, E2E, runner checks, and
the installed-consumer canary. [Fresh Greptile
review](https://github.com/paperclipai/paperclip/pull/15555#issuecomment-6059581546)
is 5/5 on this head; no unresolved threads remain. Human approval is
still outstanding.
- Reused focused controls passed with Node 24: 71 initial narrowed
checks, then 56 affected Codex/selection/eval checks after the relative
PATH correction. Runner TypeScript no-emit, syntax, and diff checks
passed. The existing fixture reproduces the original relative PATH
failure and verifies working-directory selection, empty entries,
ordering, and absolute launch. One CLI entrypoint test was initially
blocked by sandbox IPC and passed with its existing local socket
allowed. Login HOME, config-directory assignments, and working directory
match master.
- [The actual clean Linux npm
consumer](https://github.com/paperclipai/paperclip/actions/runs/37842288835/job/113535523044)
passed on the final candidate's CI integration. All 17 Paperclip
tarballs omit native Codex payloads. Official npm host packages retain
their own integrity and `inBundle=false`. Native Codex selects 0.160.0;
the legacy closure retains 0.156.1. Package admission, command leases,
narrow native sandbox resources, consumer hooks, preserved lock, and
offline lifecycle controls passed. Provider calls were zero. No new
workflow is added.
- Actual official Codex 0.156.1 passed on the final committed source on
macOS ARM64: installed dependency preference, absolute and relative PATH
fallback, narrow resource lookup, and app-server initialize/initialized.
Executed module hashes match the candidate. One scripts-disabled
install, three version probes, and one handshake completed in 26
seconds; owned files and process group were removed. No login,
account/model request, or provider task ran.
- CI checked out `dfda8e708e87306d22ed735d78bdfcbe770e99b7` on base
`65b558180533039a891ee0cd1ccab9988aa79adc`. Its 13 upstream paths do not
overlap this PR's 23 paths or alter packaging/Codex inputs. The consumer
report records producer `7b8e94c08657b5ddc265946459762340f125726c`,
after the existing canary staged a generated-lock-only commit (one file,
three insertions). These identities are kept separate; raw
generated-lock bytes were not retained.
- No local Docker or Rust build, paid provider turn, merge, or
deployment. Later PRs must prove live onboarding and production cloud
packaging before changing defaults.

## Risks

- npm must install optional host dependencies. Missing dependencies
still return errors. Paperclip tarballs do not pre-bundle Codex
executables.
- The repository requires CI-owned lockfile updates. PR CI resolves the
changed manifest and stages its own producer lockfile. A raw source
Docker build with `--frozen-lockfile` must wait for the existing master
lockfile bot to merge its refresh, or use a disposable resolved
checkout. No Docker build or deployment is qualified by this PR.
- Ordinary Codex startup accepts version differences. Actual protocol or
login failures remain errors. Explicit ACPX artifact checks retain their
release pins.
- The published server delegates platform installation outside its
bundled JavaScript graph. Focused negative controls reject unsafe
package metadata and paths. The hosted consumer test passed on this
candidate’s CI integration.
- Existing agents retain their stored runner choices. There is no data
migration or automatic upgrade. Release pipeline and platform
qualification work remain separate prerequisites for later defaults.

## Model Used

OpenAI Codex, GPT-6, with reasoning, tool use, code execution, and
parallel agents. The exact serving snapshot and context window are not
exposed in this session.

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-09 08:19:51 -05:00
DottaandPaperclip 2b688a8fe3 feat(connections): add verified MCP providers and setup fixes (#15621)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Apps give agents governed access to external tools.
> - Several provider MCP servers lacked a supported catalog entry or
failed during setup.
> - Real browser tests identified specific registration, session, and
form defects.
> - This pull request adds seven catalog entries and fixes the shared
paths used by eleven verified providers.
> - Users can connect these providers through the existing Apps flow and
control each action.

## Linked Issues or Issue Description

**What existing behavior does this improve?**

The Apps catalog and remote MCP setup, discovery, and action tester.

**Subsystem affected**

Shared app definitions, the server tool services, and the Apps UI.

**Current behavior**

Seven providers lack a catalog entry. Airtable can select an advertised
client-metadata flow that fails. Calendly rejects the registration name.
Tavily needs an initialized session before a call. Firecrawl exposes
invalid defaults for optional nested form objects. HTTPS setup can
display a callback that differs from the server callback.

**Proposed behavior**

Add Calendly, Exa, Firecrawl, GSC Wizard, Parallel Search, Tavily, and
Windsor.ai. Preserve Airtable, Linear, Make, and PostHog. Use reviewed
provider options through the shared MCP and OAuth paths. Display the
callback supplied by the server. Omit untouched optional object inputs.

**Reason and benefit**

Eleven providers passed bounded reads through the real Paperclip browser
action tester. This PR includes that verified set and its required
shared fixes. Unfinished providers remain outside this change. AgentMail
keeps its existing integration.

**Breaking changes**

No database migration. Existing OAuth credentials and action policies
keep their ownership and access rules. Airtable's reviewed method
re-registers a retained client-metadata binding through DCR. Tavily's
reviewed method initializes sessions before dispatch. The existing
customer, managed, and Vercel OAuth gateway paths now refresh on
upstream 401 and return `oauth_refreshed_retry_required` (409),
requiring an explicit caller retry. They do not replay the rejected call
automatically; the next invocation initializes a fresh credential-scoped
session when required.

Related catalog work: #15545. This branch preserves current master
catalog entries and does not add another Google Workspace integration.
Open and closed provider PRs and public MCP issues were searched. No
duplicate for this verified set was found. The change extends the
shipped Connected Apps roadmap item.

## What Changed

- Add seven catalog entries with official provider branding and reviewed
permissions.
- Update Airtable, Linear, and Make metadata and show Make in Apps.
- Add authoritative provider source overrides that use the existing
generation and review checks.
- Add the reviewed Airtable DCR option and compatible Calendly
registration names.
- Initialize Tavily sessions before discovery and calls, including
retained connections. Keep credential-scoped session caching and single
call dispatch.
- Use the server's callback URL in the OAuth setup UI.
- Omit untouched optional object defaults; keep supplied empty strings,
false, zero, and object values intact in the action tester, with strict
required-child validation.
- Require an explicit retry after OAuth refresh instead of replaying a
tools/call with missing session headers.
- Record all eleven successful reads, write policies, auth-method
limits, and qualification caveats. Omit credentials and private account
data.
- Find chat connector cards through catalog search in browser tests, so
pagination does not hide Slack or other later entries.

## Verification

- Real browser qualification: eleven bounded reads passed. Catalog
refresh and reload proof are recorded in
`doc/connections/verified-mcp-qualification-2026-10-08.md`.
- Provider writes and actual agent-adapter sessions were not run.
Alternative documented auth methods and expiry refresh remain
unqualified.
- `pnpm -r typecheck`: passed.
- `pnpm build`: passed.
- Focused shared/catalog tests: 41 passed. Source override tests: 3
passed. Catalog regeneration fixture suite: 9 passed. Latest form
regression suites: 31 passed. Gateway suite: 38 passed. Other focused UI
suites passed before these last fixes.
- UI token gates and both token sync checks: passed.
- The catalog regeneration fixture includes the authoritative provider
overrides; its full suite passes. The focused OAuth socket case passed
on isolated rerun.
- Complete local UI suite: 7,866 passed. CLI suite: 511 passed, 6
skipped. Complete shared suite: 892 passed.
- The unchanged AgentMail/ClickUp discovery fallback suite passes all 45
cases. An OpenAI login test passed on isolated rerun.
- Local broad database coverage is limited by macOS PostgreSQL
shared-memory exhaustion (`shmget: No space left on device`, not disk
space). The broad run was interrupted after diagnosis; no host settings
or other running services were changed.
- CI found that the Slack browser test assumed its catalog card was on
the first page. The test now uses catalog search; the Slack case passes
locally. Adjacent GitHub and iMessage cases could not start locally
because embedded PostgreSQL initialization failed before browser
assertions.
- Final commit
[`febe4520e`](https://github.com/paperclipai/paperclip/commit/febe4520e13d4b3a4121eafc3d22540c2b11379d):
all 54 checks passed, with none pending or failed. [CI
run](https://github.com/paperclipai/paperclip/actions/runs/37847182065)
passed typecheck, build, all general and serialized test suites, all
eight browser shards, runner checks, canary dry run, and the aggregate
verification gate.
- Greptile reviewed that exact final commit at 2026-10-08 21:33 UTC and
returned 5/5 with no outstanding findings or unresolved threads.
- PR UI preview against the existing local test server: Calendly
catalog/setup observed; Firecrawl read passed after expanding More
options with nested optional inputs untouched. This retest proves
frontend behavior, not the revised OAuth backend against a live
provider.

<details>
<summary>Browser evidence</summary>

![Calendly
catalog](https://raw.githubusercontent.com/paperclipai/paperclip/codex/verified-mcp-connectors/doc/connections/verified-mcp-qualification-2026-10-08/calendly-catalog.jpg)

![Calendly
setup](https://raw.githubusercontent.com/paperclipai/paperclip/codex/verified-mcp-connectors/doc/connections/verified-mcp-qualification-2026-10-08/calendly-setup.jpg)

![Firecrawl
read](https://raw.githubusercontent.com/paperclipai/paperclip/codex/verified-mcp-connectors/doc/connections/verified-mcp-qualification-2026-10-08/firecrawl-read.jpg)

</details>

## Risks

- Provider registration and consent behavior can change. Airtable's DCR
option is explicit and keeps the existing issuer, resource, redirect,
and PKCE checks.
- Tavily uses initialized sessions without automatic call retries. After
a successful OAuth refresh following 401, callers now receive a
retry-required result. A later explicit retry can still require
reauthorization if the provider rejects the refreshed token. Provider
writes are not live-qualified.
- Optional object cleanup affects the shared action tester. Regression
tests cover absent objects, required children, defaults, and populated
values.
- GSC Wizard's underlying Google data scopes and Google flow completion
were not independently verified. Its account reported paid/trial
metadata of unknown origin. No purchase was performed.
- No database migration, new AgentMail integration, or change to
existing action grants is included.

## Model Used

OpenAI GPT-6 through Codex assisted with implementation, research, tool
use, and code execution. The root backend model ID and context window
are not exposed in this session. The cheaper subagents used OpenAI
`gpt-6-luna`. No model context size is inferred.

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-09 08:10:46 -05:00
dependabot[bot] b9750b152f build(deps): bump rustls from 0.23.43 to 0.23.45 in /packages/paperclip-runner/runner (#15295)
Bumps [rustls](https://github.com/rustls/rustls) from 0.23.43 to
0.23.45.
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/rustls/rustls/commit/2976d90fd1c2db6b518700dd101b714069cfcb17"><code>2976d90</code></a>
Prepare 0.23.45</li>
<li><a
href="https://github.com/rustls/rustls/commit/f9d4ee92b20da535ef5982ffcaf6f62385f79641"><code>f9d4ee9</code></a>
Handshake &quot;alignment&quot; check covers previously-received
messages</li>
<li><a
href="https://github.com/rustls/rustls/commit/c4e92e8c9ee29ca3f552d4938efa73680c179179"><code>c4e92e8</code></a>
Keep data needed for HRR processing together</li>
<li><a
href="https://github.com/rustls/rustls/commit/e553a7a70f99cad4722f06b32cc37857008a7d3f"><code>e553a7a</code></a>
server: TLS1.2 is not available after a HRR</li>
<li><a
href="https://github.com/rustls/rustls/commit/5dff9da73798253d8d35909dd8548db522cd973c"><code>5dff9da</code></a>
Test whether server negotiates TLS1.2 after HRR</li>
<li><a
href="https://github.com/rustls/rustls/commit/185a063b5fe1e9698c589d8be6a83d67224b95a1"><code>185a063</code></a>
reject a second ClientHello that changes the cipher suite</li>
<li><a
href="https://github.com/rustls/rustls/commit/9fafe6dd0c15ea6e47399e94b2c6b647861f874b"><code>9fafe6d</code></a>
reject a second ClientHello that drops pre_shared_key</li>
<li><a
href="https://github.com/rustls/rustls/commit/1b42c5f78e8e826d6afa72ce0ead3e3a4e624d79"><code>1b42c5f</code></a>
providers: zeroize private key DER</li>
<li><a
href="https://github.com/rustls/rustls/commit/64ad386785c718c74262b79e6893813db381adfe"><code>64ad386</code></a>
Bump version to 0.23.44</li>
<li><a
href="https://github.com/rustls/rustls/commit/1efbf662ed79d1392c542c0822805a818d232ac0"><code>1efbf66</code></a>
bogo: remove PostQuantum setup</li>
<li>Additional commits viewable in <a
href="https://github.com/rustls/rustls/compare/v/0.23.43...v/0.23.45">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=rustls&package-manager=cargo&previous-version=0.23.43&new-version=0.23.45)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)
You can disable automated security fix PRs for this repo from the
[Security Alerts
page](https://github.com/paperclipai/paperclip/network/alerts).

</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-10-08 22:36:44 -07:00
Devin FoleyandPaperclip 1c4ce44e13 fix: retain bounded workspace transfer failure evidence (#15637)
## Thinking Path

> - Paperclip manages AI agents and the work they produce.
> - Sandbox work must return to the host when an agent run ends.
> - A failed transfer must keep its source available for recovery.
> - Some transfer errors lose their useful fields before restore
diagnostics reach Sentry.
> - This change records fixed transfer stages, failure kinds, and
numeric RPC codes.
> - The next failure can identify the operation that failed without
exposing workspace contents.

## Linked Issues or Issue Description

**What happened?**

A workspace transfer can fail after model execution succeeds. Several
command, archive validation, and download errors become plain errors.
The existing RPC envelope then reports `unknown`, with no transfer stage
or command exit code. A host RPC timeout also loses its code from
restore diagnostics.

**Expected behavior**

Keep bounded evidence through the provider, worker RPC, restore result,
and Sentry context. Keep the same exception, error message, retry rules,
and source retention policy. A transfer timeout must remain separate
from the model execution timeout flag.

**Steps to reproduce**

Return a nonzero exit code from the sandbox archive command, return a
per-file download error, exceed a tar listing limit, or time out the
sync-out RPC. Observe the missing fields in the saved restore
diagnostic. The added tests use local fixtures for these cases.

Related public work: #15479 preserves the source after restore failure.
#15481 carries bounded sync-out diagnostics through RPC. This change
supplies missing producer evidence and extends that same envelope. I
checked the roadmap and searched open PRs for duplicate transfer
diagnostic work.

## What Changed

- Add optional transfer stage and failure kind fields to the existing
diagnostic envelope. Capture command exits and listing deadlines at
their producers.
- Record only known codes from typed RPC errors at the sync-out
boundary. Revalidate every field before persistence and Sentry
projection.
- Keep annotations private to each outbound request and restore
settlement. Preserve frozen error identity and prevent evidence from
leaking across concurrent or later calls.
- Document the fields. Cover producer failures, quota limits, old
workers, concurrent error reuse, and redaction through the real Sentry
SDK.

## Verification

- Focused SDK, provider, host, persistence, and real Sentry tests: 449
passed, no skips. Independent review also ran the focused contracts and
all provider tests. The optional Sentry SDK is required for this check,
so the contract tests cannot skip.
- A compiled Daytona transfer and compiled SDK worker pass a local RPC
round trip. This uses the development TypeScript loader for workspace
dependency exports. The transfer and capture modules are compiled
JavaScript.
- `pnpm -r typecheck` and `pnpm build` passed. The excluded Daytona
package also passed `tsc --noEmit`.
- The initial local `pnpm test:run` stopped in the general-server group:
60 suites could not initialize embedded PostgreSQL because the isolated
install skipped its Darwin library-link setup. The existing package
postinstall repairs this; `initdb --version` now passes. All 60 affected
suites then passed: 1,342 tests, no skips. No local full aggregate pass
is claimed.
- Independent source review covers privacy, concurrency, packaging, and
recovery behavior.

## Risks

- These diagnostics help identify future failures. They do not establish
or repair the cause of a past transfer failure.
- New fields are optional. Older workers remain compatible. Unknown
values are omitted.
- The change adds a small request-local diagnostic scope. It keeps the
original thrown errors, archive confinement, cleanup order, timeout
values, retry count, and source retention policy.
- No schema or deployment changes are required. No live provider actions
are part of validation.

## Model Used

OpenAI Codex, based on GPT-6, with repository inspection, code
execution, and independent agent review. The exact deployed model ID and
context-window size are not exposed in this session.

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-08 19:27:39 -07:00
Devin FoleyandPaperclip 9b624a110e fix: checkpoint database backups before idle sleep (#15629)
## Thinking Path

> - Paperclip coordinates agent work and preserves company state.
> - Hosted instances can stop compute when admission and all work
sources are quiet.
> - The periodic database backup timer currently blocks every automatic
sleep.
> - Disabling backups would remove recovery points.
> - This change offers an explicit final-backup checkpoint before sleep.
> - A verified archive and restart marker preserve recovery while
compute is stopped.

## Linked Issues or Issue Description

**What happened?**

An otherwise idle instance with automatic backups enabled always reports
background work. Operators cannot reclaim idle compute without disabling
those backups. The work inventory also queries the database before
checking known local blockers.

**Expected behavior**

An operator can enable checkpoint mode. The server may authorize sleep
only after all other work is quiet and a fresh backup is verified under
the same owned hold. Backups resume on restart with the existing
retention policy.

**Steps to reproduce**

Acquire a bounded idle drain on an instance with no application work and
automatic backups enabled. Read its owned idle safety report. It reports
present even when all other work is clear. With this change and
`PAPERCLIP_DB_BACKUP_IDLE_CHECKPOINT_ENABLED=1`, a successful final
backup can permit sleep; backup failures still refuse it.

**Paperclip version or commit**

Reproduced from master at 4265cb3a2b.

**Deployment mode**

Hosted single-process instances with persistent backup storage and
serialized sleep/wake operations.

Searched open backup and sleep PRs and issues. Related: #15522 and
#15599 establish owned idle holds and plugin drains. #15358 proposes
general backup health/retention validation; this change verifies only
opted-in sleep checkpoints and their restart catch-up.

## What Changed

- Add an off-by-default checkpoint flag. Keep automatic backups enabled.
- Reject known local blockers before database work.
- Finish a new backup during each owned safety check, including final
revalidation.
- Verify the complete gzip archive and sync its file and directory
before pruning older recovery points.
- Use unique checkpoint filenames so repeated checks cannot replace an
earlier verified archive.
- Keep backup work counted through dump, validation and persistence.
Changed owners, expired holds, concurrent work and errors refuse sleep.
- Persist a restart marker before the dump. Attempt a fresh backup on
restart before idle eligibility, then resume the normal timer. Only a
verified fresh backup clears the marker.
- Restrict managed checkpoint reads to verified Cloud control actors.
Tenant instance-admin elevation does not grant backup authority.
- Keep archive verification outside engine fallback so failures retain
their original cause.
- Document that recurring duplicate archives pause while asleep. The
final checkpoint and historical archives remain on persistent storage;
retention does not prune while asleep.

## Verification

- Focused idle, spool, backup and route checks: 137 tests passed,
including restoration into a separate PostgreSQL database.
- Backup library and checkpoint tests: 15 passed, including rejection
before historical backups can be pruned.
- `pnpm -r typecheck` and `pnpm build` passed. Follow-up server
typecheck and database build cover the verification callback.
- Review follow-up: 51 backup/restore/startup tests, 122 route/safety
tests, 32 signed-control tests, and server typecheck passed. Startup
cases exercise both flag states and retry after failure. The final
test-cleanup adjustment passes all 35 startup tests.
- The full local run hit four ancestor-directory skill-fixture failures
and one tool-route failure. All five passed from an isolated checkout at
949210 (3 targeted chat/tool checks and the complete 39-test email
suite). The redundant local run was stopped after final-head hosted CI
passed. No full local pass is claimed.
- Added-line secret/private-reference review and `git diff --check`
passed.
- [Final-head hosted
CI](https://github.com/paperclipai/paperclip/actions/runs/37853380365)
passed, including typecheck, build, all general and serialized test
shards, all eight E2E shards and the canary dry run. Apex is 5/5 on
5b1de388ef, with no new findings and all review threads resolved. The
branch is conflict-free. Live staging activation awaits merge and a
canonical image; no production configuration or deployment changed.

## Risks

- The flag defaults off. This is for a single process whose host
controls every writer and preserves its backup volume across sleep.
Independent database writers require a different backup owner.
- Safety reads perform a backup only after a valid owned drain and all
other checks pass. Slow backups can outlive the caller timeout; they
remain counted until their work settles and cannot authorize sleep after
hold expiry.
- Initial and final reads each take a fresh backup. Hosts must allow
sufficient request time while retaining shutdown headroom.
- Retention settings are unchanged. Sleeping instances stop producing
duplicate hourly archives and retain their last checkpoint. Filesystem
data, encryption keys and off-provider disaster recovery remain separate
responsibilities.
- No schema migration. Disable the checkpoint flag to restore the
blanket backup blocker; automatic backups and an existing restart marker
remain active.

## Model Used

OpenAI Codex, GPT-6. Used reasoning, repository inspection, code editing
and command execution. The runtime did not expose an exact model
revision or context-window size.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have described the issue in-PR following the bug report template
- [x] I have not referenced internal/instance-local Paperclip issues or
links
- [x] My branch name describes the change and contains no internal
identifier
- [x] Focused and isolated local checks pass; final-head hosted CI is
green (local full-run limitation documented above)
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation
- [x] I have considered and documented risks
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all review comments before requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-08 15:58:55 -07:00
Devin FoleyandPaperclip 4265cb3a2b fix(ci): cache native server integration builds in release verification (#15619)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Release verification must run the same server integration coverage
as PR verification.
> - Three server suites use real Rust Runner binaries.
> - PR checks already run them with the shared Rust dependency cache,
but release checks cold-build them inside ordinary server test shards.
> - A cold Dot Runner build can consume its entire setup deadline before
any test runs.
> - This pull request gives release verification a required cached
native integration lane and preserves every test.

## Linked Issues or Issue Description

**What happened?**

On master commit `1881894973a2b25838d8abed9bd8aeebc3af4441`, [Cloud
readiness run
37837810707](https://github.com/paperclipai/paperclip/actions/runs/37837810707)
failed in server shard 7. Dot Runner's `cargo build --release` exceeded
its 300-second child-process deadline. The other 1,640 tests in that
shard passed. The failed setup then tried to remove an undefined
temporary path and emitted a second error. Cargo output was captured as
an opaque buffer, which obscured build progress.

**What did you expect to happen?**

Build fixture binaries before tests in a lane with the existing Rust
dependency cache. Run all native integration tests and make their result
required for release readiness. A setup failure should keep its original
diagnostic.

**Steps to reproduce**

Run release verification on a clean runner. The existing
`general-server-without-chat` group retains the three Cargo-backed
suites outside the PR workflow. The Dot suite can time out during a cold
release build. Run the new workflow and partition tests against the
previous source to reproduce five routing and coverage failures
deterministically.

**Version / commit**

Observed at `1881894973a2b25838d8abed9bd8aeebc3af4441`; this change is
based on `ed6abbf158b`.

**Deployment mode**

GitHub Actions Release and Cloud readiness verification. No application
runtime or deployment action changes.

Related work: #15581 also edits Dot integration tests for onboarding
behavior. It does not repair release test routing. Searches found no
open PR for this failure.

## What Changed

- Add an explicit server test group that excludes the dedicated chat and
native suites. Preserve the existing PR and local test groups.
- Run all three native server suites in one required matrix lane with
the existing trusted Rust dependency cache.
- Build debug and release fixture binaries in a visible step with a
10-minute limit before tests start. Keep Cargo freshness checks and the
existing test deadlines.
- Stream Cargo diagnostics and clean up safely when Dot setup stops
before creating its temporary directory.
- Test complete, non-overlapping partitions for Release, Cloud
readiness, other callers, and existing PR/local groups. Check cache
restrictions, build order, and the source verification dependency.

## Verification

- Passed 44 workflow and partition tests: `node --test
scripts/__tests__/run-vitest-stable-shard.test.mjs
scripts/__tests__/release-verify-workflow.test.mjs`.
- The same tests fail in five relevant cases against the previous
workflow and selector. They pass after this correction.
- An independent review repeated all 44 tests successfully.
- Passed `actionlint .github/workflows/release-verify.yml`, `git diff
--check`, and a secret scan.
- Passed all 381 workflow policy tests: `node --test
'.github/scripts/tests/*.test.mjs'`.
- Passed full `pnpm build` in a clean worktree.
- Built debug and release fixture binaries, then passed all 32 tests in
the three real native integration suites: `pnpm test:run:general --
--group general-server-native-runner` (49.5 seconds, no skips).
- Passed full `pnpm -r typecheck`.
- Injected a synthetic Cargo setup failure. The suite reports that
failure without the secondary undefined-path cleanup error.
- Exact-head CI completed: 53 successful checks, including all server
shards, both native Runner lanes, build, typecheck, browser tests, and
the canary dry run. Two optional Storybook checks were skipped.
- Started the duplicate local `pnpm test:run` aggregate and stopped it
after exact-head CI passed. No completed local aggregate result is
claimed. All test processes owned by that run exited.
- Greptile scored the final head
`ffe5ab5a28af2dfea9db1c1952c652f070bf52f8` at 5/5 with no review
threads.
- `Superagent Supply Chain Scan` is neutral, not passed: it only
supports exact dependency pin replacements and cannot verify structural
edits to `.github/workflows/release-verify.yml`. It reported no
annotations. Independent source review, Greptile, actionlint, and the
workflow policy tests cover this structural change.
- GitHub still requires a code-owner review for the workflow files.
There are no merge conflicts.

## Risks

- Adds one CI matrix job, which increases concurrent runner demand. The
existing cache writer and trust restrictions stay in place.
- Missing dependencies still compile from the lockfile. A build that
exceeds its step limit fails visibly; failed tests still block source
verification.
- Workflow execution uses the new lane after merge. PR tests validate
the workflow contract and run the existing native test lane.
- The supply chain scanner cannot analyze this workflow structure. Its
neutral result is an explicit coverage limit; it is not counted as a
successful scan.
- No runtime, schema, deployment, publication, credential, or
test-timeout changes.

## Model Used

OpenAI Codex, based on GPT-6, with repository inspection, code
execution, and independent agent review. The exact deployed model ID and
context-window size are not exposed in this session.

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-08 14:33:10 -07:00
DottaandPaperclip 2b4a1d7073 feat(dot): add guided invitations and persistent agent connections (#15581)
Add guided external-agent invitations with live Dot connection checks and ongoing access until revoked. Keep expired credentials invalid and enforce permissions for private avatar uploads. Preserve Runner recovery and remote launch boundaries.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-08 16:26:41 -05:00
Devin FoleyandPaperclip 3d1d5294d9 Drain idle plugin workers before automatic sleep (#15599)
## Thinking Path

> - Paperclip runs autonomous work through agents, schedules, and
plugins.
> - Automatic idle sleep must preserve accepted work and unfinished
cleanup.
> - Every enabled plugin currently blocks sleep, including unused
providers.
> - An enabled flag or package version cannot prove that a worker is
idle.
> - This change adds a live worker drain under the existing owned hold.
> - Idle workers can allow sleep while unknown work stays protected.

## Linked Issues or Issue Description

Refs #15522. Related: #15391 adds plugin readiness for agent admission;
this change concerns instance sleep and does not replace that contract.

**Subsystem affected**

Plugin worker lifecycle and automatic idle sleep.

**Problem or motivation**

A workspace with no pending work cannot sleep when any plugin is
enabled. Removing that check alone would lose accepted RPCs, background
tasks, or cleanup after a caller timeout.

**Proposed solution**

Require a live `onIdleDrain` handshake from each worker. Close admission
in both processes for the exact owner and expiry. Count accepted work
until completion. Continue checking durable work separately.

## What Changed

- Add bounded worker holds, exact-owner release, automatic expiry, and
an abort signal for plugin-owned background work.
- Count host and worker requests through their real completion receipts.
Keep timed-out work counted. Check active notifications and terminal
routes.
- Accept enabled plugins only when their current workers provide
matching runtime receipts. Missing workers, old SDKs, crashes, invalid
replies, and unknown cleanup still prevent sleep.
- Let unused Daytona workers opt in. Once a worker contacts the
provider, it remains a blocker for that process lifetime. This
restriction avoids treating its existing timeout and terminal-close
behavior as a cleanup receipt.
- Document the plugin author contract. No schema or user-facing API is
added.

## Verification

- All hosted CI checks passed on 6ffb682894, including all server,
runner, workspace, build, typecheck, and end-to-end checks. One
unrelated OpenCode transport test hit a five-second timeout and passed
on rerun.
- `pnpm -r typecheck` passed.
- `pnpm build` passed.
- Focused Vitest: 293 tests passed across worker admission, real
child-process RPC, durable idle checks, and Daytona.
- Adjacent worker manager and duplex tests: 119 passed.
- Real child-process tests cover late worker completion, a host write
after caller timeout, stale owners, closed admission, and release.
- SDK tests cover hook failures, busy workers, expiry without another
request, and late acknowledgements after expiry.
- Initial long local run: 17,202 passed, 10 failed. Five failures
involved parent-directory skill fixtures; four of those were already
reproduced and passed in an isolated worktree. One HTTP test had a
socket hang-up; all 66 tests in that file passed on rerun. The other
four used new tests with runtime modules loaded before the follow-up
edits; all pass in the fresh focused run above. A clean build and
full-suite rerun at the final commit are running in an isolated
worktree. No full-suite pass is claimed.
- Follow-up: 44 focused tests passed, including repeated owned holds
without an intervening normal request. Worker status changes now
invalidate an in-progress scan.
- Apex follow-up: 13 idle tests, 119 adjacent worker tests, 71
instance-settings route tests, and server typecheck passed. A real
queued notification completes its write while preparation is in flight;
synchronous and async session callback failures are logged.
- Diff whitespace and added-line secret/private-reference scans passed.

## Risks

- Plugins are trusted code. A hook must account for work outside SDK
RPCs and keep it quiescent until its signal aborts. There is no
package-name or manifest-only exemption.
- This first change targets unused workers. Used Daytona workers remain
awake until remote cleanup receipts are complete. Restarting does not
bypass durable lease and recovery checks.
- Unknown completion remains a blocker, including after a worker crash.
This can retain cost but cannot authorize sleep from a timeout alone.
- Enabled jobs, schedules, credentials, integrations, and other durable
work remain blockers. Durable wake ownership is separate follow-up work.
- Rollback restores the blanket plugin blocker. No data migration is
required.

## Model Used

OpenAI Codex, GPT-6. Used repository inspection, reasoning, code
editing, and command execution. The runtime did not report an exact
model revision or context-window size.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either linked existing public issues or described the issue
in this PR
- [x] I have not referenced internal or instance-local issues or links
- [x] My branch name describes the change and contains no internal
identifiers
- [x] Focused local tests pass; full CI is green (long local rerun
status is recorded above)
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation
- [x] I have considered and documented risks
- [x] All Paperclip CI gates are green
- [x] Greptile Apex is 5/5 on 6ffb682894 with no open findings
- [x] I will address all review comments before requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-08 12:57:32 -07:00
Devin Foley 53105d5830 feat(apps): add Gauge connection (#15596)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Agents reach external services through the Apps catalog. Each
catalog entry is a reviewed `AppDefinition` that connects a provider's
hosted MCP server to Paperclip's shared vault, grants, policies,
gateway, and audit trail.
> - Gauge (`withgauge.com`) measures how AI answer engines mention and
cite a brand. Its hosted MCP server also gives SEO, analytics and ads
reports, and runs a content pipeline that can publish to a connected
CMS.
> - Gauge is not in the catalog. Operators must use the generic "Connect
your own MCP server" flow. That flow has no branding, no organization
guidance, and no warning about live CMS publishing.
> - The connector playbook supports this provider with existing
definition fields. The server supports dynamic client registration with
a reviewed `mcp` scope, and it accepts an organization API key as a
bearer header.
> - This pull request adds the Gauge definition, its artwork, the
research and permission-review ledger rows, documentation, and
deterministic tests.
> - The benefit is a branded, governed Gauge connection with browser
sign-in, an API-key option, and a clear publish warning.

## Linked Issues or Issue Description

**Problem or motivation**

Marketing and growth teams use Gauge to track their brand in AI answers
and to run content workflows. They want their Paperclip agents to read
visibility, keyword and traffic data, and to prepare content. Gauge is
not in the Apps catalog. Operators must paste the MCP URL into the
generic remote-MCP flow, which gives no branding, no method guidance,
and no warning that content tools can publish live.

**Proposed solution**

Add a catalog-only Gauge connection built from the connector playbook.
Browser sign-in uses Gauge's dynamic client registration and requests
only the reviewed `mcp` scope. The user selects one Gauge organization
on the consent screen. An optional method sends a customer-created
organization API key as an `Authorization: Bearer` header. Both methods
warn the operator to set publish actions to Ask first. Every discovered
tool stays governed by the normal per-action policies.

**Alternatives considered**

A plugin was not needed because no custom UI, tables, workers, or
webhooks are involved. The identity scopes that Gauge also advertises
(`openid`, `profile`, `email`, `organizations`) are not requested,
because Gauge selects the organization on its consent screen. A
Gauge-specific `classifyRisk` rule was not added, because the tool names
cannot be seen without an account. The generic rule already classifies
`publish`, `create` and `update` tools as writes.

**Roadmap alignment**

This extends the existing self-serve remote-MCP connection catalog and
does not overlap planned core work.

## What Changed

- Added the `gauge` provider to `scripts/ingest-app-definitions.mjs`
(category `analytics`, API-key placement, guidance, warnings,
description) and regenerated
`packages/shared/src/app-definitions/gauge.json` and the generated
registry.
- Added the Gauge row to the self-serve MCP research ledger with
`dcr_or_api_key` auth and risk tier S3.
- Added permission reviews for `gauge/mcp-oauth` (explicit scope `mcp`,
from Gauge's live authorization-server metadata) and `gauge/mcp-api-key`
(provider key), with evidence links.
- Added Gauge's mark (`ui/public/brands/apps/gauge.png`, the avatar of
Gauge's official GitHub organization) and the brand manifest entry.
- Added gallery copy for the Gauge card.
- Added `doc/connections/GAUGE.md` (endpoints, scopes, administrator
setup, capabilities and policy, manifest, brand provenance, validation
hook) and linked it from the connections README and the permission
audit.
- Tests: Gauge definition shape, store visibility and artwork, URL
recognition, reviewed scope, bearer-header placement, the connect form's
sign-in default and API-key gating, and the pinned catalog counts.

## Verification

- `pnpm exec vitest run packages/shared/src/app-definitions.test.ts
packages/shared/src/app-definitions-url.test.ts
ui/src/pages/apps/AppsConnect.test.tsx ui/src/pages/apps/Browse.test.tsx
ui/src/lib/app-brand-assets.test.ts
ui/src/pages/apps/AppLogo.brand-assets.test.tsx
server/src/__tests__/tool-access-service.test.ts` — 738 passed.
- `node scripts/check-app-brand-assets.mjs` and `node --test
scripts/app-brand-validation.test.mjs` — passed.
- `pnpm --filter @paperclipai/shared typecheck`, `pnpm --filter
@paperclipai/server typecheck`, `pnpm --filter @paperclipai/ui
typecheck` — clean.
- `node scripts/ingest-app-definitions.mjs --definitions-only` produces
no Gauge drift.
- Manual: on a local instance, open Apps → Browse and confirm the Gauge
card and icon. Open `/apps/connect?source=gauge` and confirm that
sign-in is the default and that the API-key method is under Advanced.
- Live metadata probe on 2026-10-08: an unauthenticated `initialize` on
`https://app.withgauge.com/mcp` returns 401 with `resource_metadata`.
Both `.well-known` documents return the recorded endpoints and scopes.
Dynamic client registration succeeds. The authorize endpoint accepts
`scope=mcp` and rejects an unknown scope with HTTP 400.

## Risks

- Low risk to existing providers: the change is additive catalog data
plus tests. The generated registry only gains one import.
- Gauge content tools can publish to a connected CMS, including live,
and a bulk keyword update replaces each prompt's keyword list. Both
methods warn the operator, and the API-key helper text tells operators
to set publish actions to Ask first.
- Gauge API keys are not scoped and reach the whole organization.
Paperclip cannot narrow an issued key.
- The permission-review ledger records live proof for both methods as
not run. The lifecycle checklist in `doc/connections/GAUGE.md` still
needs a documented pass with a Gauge organization.

> For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and
discuss it in `#dev` before opening the PR. Feature PRs that overlap
with planned core work may need to be redirected — check the roadmap
first. See `CONTRIBUTING.md`.

## Model Used

- Claude Opus 5.5 (`claude-opus-5-5`, 1M context) in Claude Code, with
tool use (shell, file editing, web research).

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [ ] All Paperclip CI gates are green
- [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge
2026-10-08 12:37:06 -07:00
dependabot[bot] 9f4acc8f14 build(deps): bump @modelcontextprotocol/sdk from 1.30.0 to 1.31.0 (#15361)
Bumps
[@modelcontextprotocol/sdk](https://github.com/modelcontextprotocol/typescript-sdk)
from 1.30.0 to 1.31.0.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/modelcontextprotocol/typescript-sdk/releases">@​modelcontextprotocol/sdk's
releases</a>.</em></p>
<blockquote>
<h2>1.31.0</h2>
<h2>Upgrade notes</h2>
<ul>
<li>Stored OAuth tokens and client information now include an
<code>issuer</code> field. Storage that rejects unknown fields needs to
allow it.</li>
<li>Pass <code>expectedIssuer</code> when constructing
<code>ClientCredentialsProvider</code>,
<code>PrivateKeyJwtProvider</code> or
<code>StaticPrivateKeyJwtProvider</code>. Constructing them without it
is deprecated.</li>
</ul>
<h2>What's Changed</h2>
<ul>
<li>[v1.x] Bind stored OAuth credentials to the authorization server
that issued them by <a
href="https://github.com/maxisbey"><code>@​maxisbey</code></a> in <a
href="https://redirect.github.com/modelcontextprotocol/typescript-sdk/pull/2888">modelcontextprotocol/typescript-sdk#2888</a></li>
<li>chore: bump version to 1.31.0 by <a
href="https://github.com/claude"><code>@​claude</code></a>[bot] in <a
href="https://redirect.github.com/modelcontextprotocol/typescript-sdk/pull/2890">modelcontextprotocol/typescript-sdk#2890</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/modelcontextprotocol/typescript-sdk/compare/1.30.1...1.31.0">https://github.com/modelcontextprotocol/typescript-sdk/compare/1.30.1...1.31.0</a></p>
<h2>1.30.1</h2>
<h2>What's Changed</h2>
<ul>
<li>[v1.x] fix(server): read HTTP request bodies with a size limit and
bound JSON-RPC batch length by <a
href="https://github.com/maxisbey"><code>@​maxisbey</code></a> in <a
href="https://redirect.github.com/modelcontextprotocol/typescript-sdk/pull/2717">modelcontextprotocol/typescript-sdk#2717</a></li>
<li>fix(auth): preserve resource URI without trailing slash (<a
href="https://redirect.github.com/modelcontextprotocol/typescript-sdk/issues/1968">#1968</a>)
by <a
href="https://github.com/MukundaKatta"><code>@​MukundaKatta</code></a>
in <a
href="https://redirect.github.com/modelcontextprotocol/typescript-sdk/pull/1972">modelcontextprotocol/typescript-sdk#1972</a></li>
<li>chore: bump version to 1.30.1 by <a
href="https://github.com/claude"><code>@​claude</code></a>[bot] in <a
href="https://redirect.github.com/modelcontextprotocol/typescript-sdk/pull/2848">modelcontextprotocol/typescript-sdk#2848</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a
href="https://github.com/MukundaKatta"><code>@​MukundaKatta</code></a>
made their first contribution in <a
href="https://redirect.github.com/modelcontextprotocol/typescript-sdk/pull/1972">modelcontextprotocol/typescript-sdk#1972</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/modelcontextprotocol/typescript-sdk/compare/1.30.0...1.30.1">https://github.com/modelcontextprotocol/typescript-sdk/compare/1.30.0...1.30.1</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/modelcontextprotocol/typescript-sdk/commit/4b0051f400219f8d8855f9a5433c6df35f15a639"><code>4b0051f</code></a>
chore: bump version to 1.31.0 (<a
href="https://redirect.github.com/modelcontextprotocol/typescript-sdk/issues/2890">#2890</a>)</li>
<li><a
href="https://github.com/modelcontextprotocol/typescript-sdk/commit/51ad4f03190dc5c84ab8b1a25f9b78b277be0dc7"><code>51ad4f0</code></a>
[v1.x] Bind stored OAuth credentials to the authorization server that
issued ...</li>
<li><a
href="https://github.com/modelcontextprotocol/typescript-sdk/commit/289ac2c3af7e1536160e80414296b175171a1a87"><code>289ac2c</code></a>
chore: bump version to 1.30.1 (<a
href="https://redirect.github.com/modelcontextprotocol/typescript-sdk/issues/2848">#2848</a>)</li>
<li><a
href="https://github.com/modelcontextprotocol/typescript-sdk/commit/12b425678a76cd54b0452a2ccf1e5dc7740f73ef"><code>12b4256</code></a>
fix(auth): preserve resource URI without trailing slash (<a
href="https://redirect.github.com/modelcontextprotocol/typescript-sdk/issues/1968">#1968</a>)
(<a
href="https://redirect.github.com/modelcontextprotocol/typescript-sdk/issues/1972">#1972</a>)</li>
<li><a
href="https://github.com/modelcontextprotocol/typescript-sdk/commit/a9f6eb709b85459d01e8f2a9e881fef2621756c1"><code>a9f6eb7</code></a>
[v1.x] fix(server): read HTTP request bodies with a size limit and bound
JSON...</li>
<li>See full diff in <a
href="https://github.com/modelcontextprotocol/typescript-sdk/compare/1.30.0...1.31.0">compare
view</a></li>
</ul>
</details>
<br />

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-10-08 11:05:20 -07:00
Devin FoleyandPaperclip 3d0e74e743 Keep proven external connection failures out of Sentry (#15590)
Apply the reviewed change for Keep proven external connection failures out of Sentry.

Validation: local typecheck/build and focused regression tests, passing exact-head CI, Greptile 5/5, and independent source review. The PR records full-suite evidence and any local environment limitations.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-08 10:19:40 -07:00
Devin FoleyandPaperclip 0ac194450a fix: make Copilot provider-pack wrappers portable (#15586)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Container images include a movable provider pack for agent
execution.
> - pnpm executable wrappers can contain the temporary build directory.
> - New optional Copilot packages add wrappers that the build does not
replace.
> - This pull request gives those installed wrappers relative executable
paths.
> - Image publication can finish while the existing path check remains
enforced.

## Linked Issues or Issue Description

Refs #15572 and #15560. The small portability loop comes from
cryppadotta's larger Copilot runtime PR #15560. This separate fix
repairs image publication without waiting for that feature's
qualification and runtime changes. That PR can remove its duplicate loop
after this lands.

**What happened?**

The standard Docker build stops with `Provider pack shim
copilot-linux-x64 retains its temporary build path`. The failure
occurred before and after #15522. See [the failed master
build](https://github.com/paperclipai/paperclip/actions/runs/37802065316).

**Expected behavior**

Installed native Copilot wrappers resolve their pinned executable after
the provider pack moves. Optional packages that are absent do not gain a
command. The builder still rejects wrappers with temporary paths.

**Steps to reproduce**

1. Run the provider-pack build from the affected master revision on
Linux x64.
2. Let `pnpm deploy --prod` install the optional Copilot package.
3. The wrapper scan rejects its temporary `NODE_PATH`.

**Paperclip version or commit**

Master `3367b75ccce34d02f355cda1f1ed3fe0b34cf93d`.

**Deployment mode**

Docker and provider-pack builds.

## What Changed

- Replace installed Copilot platform wrappers with relative native
executable launchers.
- Move the existing executable wrapper writer into an importable helper.
Retain the same launch behavior for Node, Claude and OpenCode.
- Test relocation, argument handling, exit status, absent optional
packages and missing executable packages. Register the tests in the
existing Runner test preparation command.
- Hash the helper in Daytona image identity and prove that helper
changes invalidate the image cache.
- Document the packaging rule. Keep dependencies, provider qualification
and the final temporary-path check unchanged.

## Verification

- 17 Node packaging tests passed across the new wrapper tests,
provider-pack release tests and candidate selection tests.
- Six existing bundled remote-provider-pack tests passed using the
Runner Vitest configuration.
- Nine Daytona image identity tests and Runner E2E typecheck passed
after the cache-input correction.
- `pnpm -r typecheck`: passed.
- `pnpm build`: passed.
- Real `pnpm deploy --prod` reproduction on macOS ARM64: the original
Copilot wrapper contained the temporary path. After the rewrite and
directory relocation, the actual executable returned Copilot CLI 1.0.88
with exit code zero using only `/usr/bin:/bin` in `PATH`.
- Syntax checks, `git diff --check` and the pre-push secret scan passed.
- The full local `pnpm test:run` reproduced the same five
skill/connector fixture failures observed earlier in this workspace. It
was stopped after current-head clean-checkout CI passed; later local
phases were not run. This local run is not claimed as passing. Focused
packaging tests, workspace typecheck/build and all hosted CI passed.
- [Hosted Docker verification
passed](https://github.com/paperclipai/paperclip/actions/runs/37804902678):
Linux AMD64 and ARM64 image builds, multi-architecture publication and
the process-reaping smoke check. This run tested
`779d94989c54d9abbeba0838194c951186af66a6`; the only later changes are
Daytona cache identity and its regression test. Provider-pack build code
is identical. Local Docker did not respond within the bounded probe.
- Current head `db2c19e270b8d5a7bab5db39d3de0e4761cf57c3`: 54 successful
checks, two conditional skips, no failures and no merge conflicts. Apex
is 5/5 with no unresolved comments.

## Risks

The helper uses each installed package's exported executable. An
installed wrapper with a missing package still fails the build. This
change does not execute Copilot during image construction, alter
dependency pins, change runtime admission or weaken the temporary-path
check.

## Model Used

OpenAI GPT-6 via Codex, with reasoning, repository inspection, tool use
and code execution. The exact serving model identifier and context
window are not exposed in this session.

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-08 09:33:24 -07:00
Devin FoleyandPaperclip 3367b75ccc fix: fence accepted work and cleanup before idle sleep (#15522)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - A host can stop an idle instance to reduce unused compute.
> - Zero active runs do not prove that requests, saved work, or cleanup
are complete.
> - A client can disconnect while its request still writes, and failed
cleanup can remain only in memory or on disk.
> - This pull request holds new admission and checks accepted work,
cleanup, and persisted work under an owned drain.
> - The host gets an empty report only while those checks remain valid.

## Linked Issues or Issue Description

Refs #13413. That companion PR uses the same owned-hold vocabulary for
runtime services. This PR covers HTTP requests, scheduler work,
accounting, cleanup, and the instance work inventory. It does not
include the preview gateway changes.

**What existing behavior does this improve?**

The instance task-drain API reports process counters. It does not prove
that a host can safely stop the instance for idle sleep.

**Current behavior**

A quiet run set can coexist with an unfinished request, cleanup after a
completed run, future work, or a failed accounting write.

**Proposed behavior**

Provide a bounded owned idle hold. Block new ingress, track accepted
handler promises, inspect durable and local work, and return `none` only
when the same hold stays quiet through the checks. Keep normal
deployment drains compatible.

**Reason and benefit**

Hosts can identify eligible idle instances without treating a disconnect
or failed cleanup write as completed work.

## What Changed

- Add `purpose: "idle"`, a bounded TTL, unique owners, and owner-checked
release to task drain. Existing holds cannot be replaced by another API
request.
- Gate HTTP ingress before parsers, auth, webhooks, and MCP. Gate new
WebSocket upgrades. Track async handlers in nested Express routers and
error middleware until they settle, even after the response or client
disconnect.
- Count accepted live-event WebSocket authentication through settlement,
even after disconnects. Count detached built-in agent, managed-home and
runtime-service startup reconciliation after readiness.
- Keep health and control mutations tracked. Count control-request
authentication separately from the read-only report, including
concurrent user/company/membership writes.
- Pause new scheduler admissions during idle holds. Count work already
in flight, including database backups, and reject scans whose work
generation changes. Periodic backups block sleep without a host wake
schedule.
- Inspect accounting and orphan-cleanup spool directories without
skipping temporary or malformed entries. Retain orphan tokens through
queue splices, flush failures, and buffer overflow. Keep failed usage
capture counted until its database failure fence is written.
- Check persisted work across companies in a bounded read-only
transaction. Include deferred agent-file cleanup and saved watchdogs
whose watched issues are complete. Enabled plugins and unsupported
retained work remain blockers.
- Require the exact idle owner and completed startup tracking before
returning an empty report. Keep reports free of tenant details.
- Document the hosting protocol, retry behavior, conservative blockers,
and the remaining external provider-stop race.

## Verification

- Current head: `8d9a599b732c2047b8c671d4799065d7c90a3567`, rebased on
master `941a3fa991aeb97eb1ac390c65b7973b5f6de1ad`. Both heartbeat helper
extractions are preserved. GitHub confirms no merge conflicts.
- Focused heartbeat renderer/run-log, drain, control-auth, admission,
route and PostgreSQL inventory checks: 234 tests passed in 10 suites
after the rebase.
- The POST task-drain contract includes the expected `409` conflict
response. The 84 OpenAPI and instance-settings route tests and server
typecheck passed after that final documentation fix.
- Final accepted-upgrade/startup regression run: 104 tests passed in
five suites, including success and failure after readiness or
disconnect. Final server typecheck also passed.
- `pnpm -r typecheck`: passed.
- `pnpm build`: passed.
- `pnpm install --frozen-lockfile` and the PR diff secret scan passed.
No dependency or lockfile changes are added by this PR.
- The prior verification covered HTTP disconnects and early responses,
async error handlers, concurrent authentication writes, signed
bootstrap, saved watchdogs, backup promises, orphan cleanup, spools and
failed accounting fences. Those tests passed.
- The last full local `pnpm test:run` stopped in the general-server
phase with 16,658 passing tests and five skill/connector fixture
failures caused by an ancestor workspace skill directory. That full
local run preceded this rebase and has not been repeated for the import
conflict. Full current-head CI passed: 53 successful checks and two
conditional skips, with no failures.
- All eight review findings are fixed and their threads resolved,
including accepted upgrade authentication, detached startup writes and
the POST conflict contract. Current-head Apex review is 5/5 with no new
findings; all eight review threads remain resolved.
- No live provider stop or production change was performed.

## Risks

- The hosting controller must use the owned protocol and hold external
admission through its final validation and provider stop. A legacy drain
cannot authorize idle sleep. During an idle hold, new requests receive
503 with `Retry-After: 1`; the host must handle queueing or retry before
enabling this path.
- This is a single-process protocol. An unexpected restart after the
last validation can race an external provider stop. The host must
serialize deploy/wake/sleep operations and bind the validation to the
instance it stops. Multiple replicas need shared fencing.
- Some retained state conservatively prevents sleep, including every
enabled plugin. This PR does not promise that every inactive instance
becomes eligible.
- The HTTP adapter uses Express 5 router layers. Real Express tests
cover nested routes, errors and disconnects. New routes must register
before tracking is installed. Detached work must have durable state or
explicit work tracking.
- Unrecoverable in-memory cleanup debt keeps the instance awake until
reconciliation. This change does not make such debt survive an unplanned
process crash. No schema migration or provider configuration change is
included.

## Model Used

OpenAI GPT-6 via Codex, with reasoning, repository inspection, tool use
and code execution. The exact deployment variant/model ID and context
window are not exposed in this session.

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-08 08:35:45 -07:00
941a3fa991 Pin Copilot native dependencies with the maintained lockfile refresh (#15572)
Pin the three optional GitHub Copilot 1.0.88 native packages for Runner and server using the maintained lockfile workflow. Synchronize the package contract and bound initial render readiness in the deliberately throttled browser fixture. Current-head CI and focused checks pass.

Co-Authored-By: Dotta <cryppadotta@users.noreply.github.com>
Co-Authored-By: lockfile-bot <lockfile-bot@users.noreply.github.com>
Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-08 09:37:53 -05:00
DottaandPaperclip 71cd0a2621 fix(skills): honor the current run harness checkout (#15548)
## Thinking Path

> - Paperclip manages work for AI agents.
> - The runtime claims eligible assigned tasks before it starts an
agent.
> - The wake tells the agent when the runtime already holds that claim.
> - The legacy skill still requires another checkout in every case.
> - This PR makes the skill honor the current task and run claim.
> - Manual checkout and server ownership checks remain in place for
other cases.

## Linked Issues or Issue Description

**Where is the issue?**

`skills/paperclip/SKILL.md`, in the scoped wake procedure and Step 5.

**What's wrong?**

The wake can say that the harness already checked out the issue. The
skill still tells the agent that it must call checkout. These
instructions conflict.

**Suggested fix**

Skip the second checkout only when the runtime wake explicitly confirms
the claim for this issue and run. Retain manual checkout when that
statement is absent or the agent selects another task. Refs #14948 for
the existing shared prompt reduction.

## What Changed

- Honor the explicit runtime claim in the scoped wake procedure and Step
5.
- Keep context reads, status writes, deliverable handling and conflict
rules.
- Add checks for normal and resumed wake text and excluded automatic
claims.
- Retain successful checkout HTTP activity for legacy stock-task evals.
Bind each receipt to the exact company, task, agent and run. Keep this
observation separate from the original task grades.

## Verification

- Checkout observation calibration: nine tests pass.
- Focused skill, wake and database ownership tests: in progress.
- Full repository build, typecheck and tests: in progress.
- Planned live comparison: the existing assigned-skill document case on
legacy Codex and Claude. One attempt per variant and profile. No
automatic retries. The baseline and candidate share the observation code
and task oracle.
- Live results are pending. This draft does not claim behavioral
qualification.

## Risks

- Agents may misread prompt guidance. The API still enforces ownership;
the text grants no new authority.
- The exception is specific to the current issue and run. It does not
remove ordinary legacy completion writes or authorize another task.
- Activity measures successful checkout HTTP calls. Failed attempts
require separate run-log inspection. Missing or mismatched observations
cannot count as zero calls.
- One trial per profile cannot establish general reliability, speed or
cost trends.

## Model Used

OpenAI Codex, GPT-6 family. The exact model build and context window are
not exposed in this session. Used code editing, shell tools and test
execution.

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-08 06:38:09 -05:00
DottaandPaperclip d66acb7ac1 feat: automate Slack bot app setup and installation (#15413)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Chat connectors give each agent a customer-owned bot and task-backed
conversations.
> - Manual Slack setup requires app creation and copying durable
credentials.
> - Operators need a shorter setup that an assisting agent can use
safely.
> - This pull request creates the app through Slack's Manifest API and
installs it through OAuth.
> - Durable registration state supports recovery without creating
another app.
> - A four-screen wizard, automatic avatar upload, and OAuth account
linking reduce setup work.
> - Connector settings and per-turn tool guidance support daily use
after installation.

## Linked Issues or Issue Description

**Subsystem affected**

Native Slack bot setup, company secret storage, chat connector
management, and agent tool guidance.

**Problem or motivation**

New Slack bots require manual app creation and copying a signing secret
and bot token. Interrupted setup can create duplicate apps. The setup
and management screens contain unnecessary controls. Agents also need
guidance for native questions, files, thread replies, and governed Slack
actions.

**Proposed solution**

Use a temporary app-configuration access token to create a
customer-owned app. Save durable secrets in the vault. Bind OAuth to the
initiating actor, company, endpoint, registration revision, scopes, and
configured origins. Preserve manual and existing-app recovery. Link the
installing user's account, send a welcome DM, and advance from saved
server evidence. Keep request-URL recovery instructions available if
automatic connection detection waits.

**Alternatives considered**

The Slack CLI adds installation requirements. Socket Mode changes
transport. A shared Paperclip-owned app changes app ownership. These
alternatives are outside this change.

**Roadmap alignment**

This extends existing chat connectors and secrets capabilities. Related
public work: #14037 and #13954 cover Slack MCP prerequisites and user
OAuth. No duplicate bot-registration PR was found.

## What Changed

- Share one reviewed manifest builder between automatic registration and
manual setup.
- Add replay-safe migration 0318 and company-bound registration state
with vault references and uncertain-creation recovery.
- Add registration, installation, callback, and resume APIs with
short-lived, single-use OAuth state.
- Save installation credentials before downstream checks and preserve
bot identity constraints.
- Reduce automatic setup to four screens. Keep advanced app details,
manual recovery, and existing-app setup.
- Upload the agent avatar with the Paperclip dark background. Link the
OAuth installer's account and send setup DMs.
- Show agent and connector-owner avatars. Simplify settings, access, and
conversation screens.
- Discover joined Slack channels and enable them by default. Start a
task from a bare mention and admit same-thread follow-ups.
- Refresh Slack tool guidance each turn. Add native-form, file,
approval, and delivery regressions plus manual model probe definitions
and sanitized acceptance records.
- Update deployment/database docs, OpenAPI, redaction, removal cleanup,
production Storybook stories, and provider browser tests.
- Merge current master and move the registration migration after its
latest migration without rewriting published commits.

The completed Slack success view intentionally has a single centered
**Done** action and no **Save & exit**, as explicitly requested by the
product owner. `DESIGN.md` records this exception; unfinished setup
steps retain the aligned wizard footer.

## Verification

- Passed after the master merge: repository typecheck, full build,
Storybook build, design-token gates, module-boundary gates, and
migration generation.
- Passed: all 352 focused Slack deterministic tests and all 14 affected
provider browser tests. Browser tests use controlled provider fixtures
and a separate throwaway instance.
- Passed on current head `c5d01e0e2`: the complete GitHub test matrix
(general server, chat, all workspaces, serialized server, and Runner),
all eight browser shards, typecheck/release registry, build, canary dry
run, security checks, and policy gates. There are 52 passing checks and
no pending or failing checks.
- Greptile completed on the exact current head with 5/5 and no
actionable findings or open review threads.
- Local repair verification passed 93 focused tests, including same-app
reinstall after revocation and rejection of consent started before
revocation, the AgentMail browser journey, and repository typecheck.
Local build and Storybook build also passed. The redundant local
full-suite rerun was stopped after the complete current-head CI matrix
passed.
- Real Slack setup and agent replies were exercised in the authorized
isolated test drive during the setup iteration.
- The ten additional model probes were attempted with legacy
`codex_local`, `gpt-5.6-sol`: five passed, two failed, and three were
partly verified. Native runtime is not qualified. See
`server/src/services/connectors/slack/evals/2026-10-08-acceptance.md`
for evidence and limits.
- Passing model probes cover native forms, downloaded file bytes, bare
mentions with thread replies, explicit posts/reactions, and saved
approval denial.
- The controlled uncertain-write probe found wrong delivery-check IDs.
The canvas fallback attempt used an invented tool name. Search
pagination/native search, a private-source denied-tool receipt, and
distinct board/webhook origins remain unqualified.

Reviewer path: enable Chat connectors, start Slack chat setup, select an
agent, enter an app-configuration access token, and approve Slack
installation. Send a message to the bot and confirm that setup advances
to success. Inspect settings and allowed channels. See
`doc/connections/SLACK-AUTOMATIC-SETUP.md` for deployment and recovery.

## Risks

- Slack app creation has no provider idempotency guarantee. A timeout
after dispatch stays uncertain until the operator checks Slack.
- OAuth needs a stable public HTTPS board origin. Webhook ingress may
use a separate configured HTTPS origin. Workspace policy can delay
installation.
- Migration 0318 can replay safely on instances that applied the earlier
development migration.
- OAuth installation now links the installer to the initiating Paperclip
user. Identity checks and company access rules still apply.
- Joined channels now enable bot responses by default. Linked-user
authorization and per-action approval rules still apply.
- Model behavior has the documented delivery-check and canvas fallback
failures. A passing CI run does not establish that every model probe
passed.
- Removing the connection does not delete the customer's Slack app. No
new first-party telemetry is added.

## Model Used

OpenAI Codex, GPT-6 family, with reasoning, repository tools, code
execution, and browser verification. The runtime does not expose a more
specific authoring model ID or context-window size. The live bot probes
used OpenAI `gpt-5.6-sol` through `codex_local` in legacy mode.

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-08 06:33:31 -05:00
DottaandPaperclip d0f69670db fix(runner): recover saved execution prompts after upgrades (#15518)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Native runs save an immutable execution context for restart
recovery.
> - The context includes the prompt text, revision, and content hashes.
> - The parser required that saved prompt to match the current release.
> - A server upgrade could reject a valid saved run before provider
recovery.
> - This pull request validates and preserves the saved prompt snapshot.
> - Routine prompt changes no longer need a catalog of past strings.

## Linked Issues or Issue Description

**What happened?**

A hot restart selected a dead native runner for same-run recovery.
Reading its saved v5 execution input failed with
`input.runtimeContext.prompt must match the fixed Paperclip prompt
revision`. The new controller accepted only v6.

**Expected behavior**

Recovery uses the saved prompt and validates its content hashes. It
preserves the same run and provider session without starting a duplicate
turn.

**Steps to reproduce**

1. Start a native run and save its execution input and provider
checkpoint.
2. Change the fixed execution prompt in the server release.
3. Stop the runner and recover the saved run with the new controller.
4. Observe that the old parser rejects the saved prompt before provider
recovery.

**Paperclip version or commit**

The v5-to-v6 prompt change was introduced in #15446. The defect also
reproduces on current master before this fix.

**Deployment mode**

Source-built server with the native runner.

Related work: #15446 added task-monitor guidance. The held prompt-size
experiment in #15489 changes prompt wording but does not add recovery
compatibility.

## What Changed

- Read the prompt text and revision from the saved execution snapshot.
- Treat the revision as non-empty metadata and preserve the exact saved
bytes.
- Validate the prompt SHA-256 and the aggregate context digest.
- Keep fresh-run builders on the current prompt constants.
- Test arbitrary saved prompts, malformed fields, altered text, stale
hashes, and aggregate drift.
- Test recovery parsing for Codex input versions v3-v5 and OpenCode,
ACPX Pi, and Dot v6 inputs.
- Extend the real-process restart suite with both the incident's v5 wire
fixture and a prompt unknown to this release.
- Run the restart recovery suite in the existing Rust-equipped PR lane,
where its runner and fake-provider binaries are built. Verify complete,
non-overlapping test coverage for PR, release, and local callers.
- Document recovery from saved snapshots without a historical prompt
catalog.

## Verification

- Red: the new contract regressions fail against the catalog-based
parser with the original prompt-validation error.
- Green: 53 focused contract and materialization tests pass.
- Red: the real-process unknown-prompt regression fails with master's
original parser at the saved-input recovery read after process loss.
- Green: all 15 real-process restart tests pass locally on the final
branch. The saved-prompt cases keep the run and provider session,
replace the PID, and record one `turn/start`.
- Local repository `pnpm -r typecheck` and `pnpm build` passed after
rebase on `89f09dad723766e5351953f0731b9aa5daada28d`. The 53 focused
tests also passed on that head.
- Red: the new test-roster checks fail against the old CI placement.
- Green: all 26 test-scheduling checks pass after moving the restart
suite.
- CI ran all 15 restart recovery tests with no skips on final head
`6719fc2bb7a31a0f72ea04c7e525a63dcc6f9105`. [Runner test
job](https://github.com/paperclipai/paperclip/actions/runs/37764782334/job/113271464966).
- Greptile scored 5/5 on that exact head with no actionable findings.
- The complete CI matrix passed on final head
`6719fc2bb7a31a0f72ea04c7e525a63dcc6f9105`: general/workspace tests,
serialized server suites, both runner Vitest lanes, Rust and static
checks, all browser shards, typecheck, build, and the canary dry run.
[CI
run](https://github.com/paperclipai/paperclip/actions/runs/37764782334).
- There are no unresolved review threads or merge conflicts.
- Reproduce focused tests with `pnpm --filter
@paperclipai/paperclip-runner exec vitest run
src/contracts/runtime-context.test.ts
src/contracts/native-execution.test.ts
src/drivers/runtime-context-materializer.test.ts`.
- Reproduce restart tests with `pnpm --filter
@paperclipai/paperclip-runner build:rust` followed by `pnpm exec vitest
run
server/src/services/native-runtime/native-runner-restart-recovery.integration.test.ts`.
They use temporary PostgreSQL, real runner processes, and a fake Codex
provider. They do not use paid inference.

## Risks

- The parser now accepts internally consistent saved prompt text that is
absent from the current source. Inputs must come from trusted server
persistence. Content hashes verify consistency; they do not authenticate
authorship.
- Existing execution-schema, ownership, checkpoint, provider,
permission, and session-compatibility checks still apply.
- This change validates the saved base prompt. It does not make all
additional code-generated instruction strings versioned.
- The process-level recovery proof uses Codex. Other provider coverage
verifies the shared input parser and retained provider configuration.

## Model Used

OpenAI Codex, GPT-6 family, with repository inspection, code editing,
and test tools. The exact serving model ID and context-window size are
not exposed in this session.

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-08 05:57:20 -05:00
DottaandPaperclip b5342febe5 fix(runner): require current-turn completion after connection continuations (#15514)
## Thinking Path

> - Paperclip manages agents, tasks, permissions, and execution budgets.
> - Native tasks can resume after a connection decision in the same
provider conversation.
> - Each turn still needs an accepted completion report.
> - Compact continuation messages did not explain that reports from
earlier turns cannot finish the new turn.
> - The connection evaluator could also grade before the final reply was
stored or reject valid unavailable-access wording.
> - This PR clarifies the current-turn report requirement and fixes
those observation boundaries.
> - The original connection instructions and strict native completion
gate stay in place.

## Linked Issues or Issue Description

Refs #15489. The reduction remains draft while this separate repair is
qualified. Refs #15471 for the earlier connection continuation work.

## What Changed

- Add a current-turn completion reminder to compact continuation inputs.
- Keep final prose insufficient for completion. Preserve permissions and
retry policy.
- Wait for the final successful task run's saved, attributed decline
reply within the existing deadline.
- Use one bounded explanation matcher for both decline checks.
- Wait for a recorded tool-action rejection to dispatch its bound
continuation, with strict company, task, agent and source-run checks.
- Retain the exact grading input before later API refreshes.
- Add failure and delay regressions and update the Runner and evaluator
docs.

## Verification

The fresh comparison has **15/15 original passes on each variant**: 15
unchanged pass pairs, zero new failures, and no pending pair. There are
30 case attempts and **65 actual agent runs** (baseline 33; candidate
32). All runs succeeded. All 30 cleanups passed. No model attempt was
retried.

| Profile | Baseline | Candidate |
| --- | --- | --- |
| Native Codex `gpt-5.6-sol` | 5/5 | 5/5 |
| ACPX Claude `claude-sonnet-5` | 5/5 | 5/5 |
| OpenCode `openrouter/deepseek/deepseek-v4-flash-0731` | 5/5 | 5/5 |

Each profile covers service approval, service decline, connection
decline, provider decline, and selection of the second provider. The
saved replies, approved briefings, decisions, fixture observations,
final task states, and native completion records were inspected. All 18
saved decline-grade snapshots match their original captured inputs and
checks. Result, API snapshot, and final ledger run sets agree.

- [Candidate
campaign](https://github.com/paperclipai/paperclip/actions/runs/37711658378)
· [public candidate
report](https://d1p6rlowie26tp.cloudfront.net/runner-e2e/campaigns/gha-37711658378-1/index.html)
- [Baseline
campaign](https://github.com/paperclipai/paperclip/actions/runs/37711675579)
· [public baseline
report](https://d1p6rlowie26tp.cloudfront.net/runner-e2e/campaigns/gha-37711675579-1/index.html)
- Candidate source: `79905343bba280d462765faad19a26e7f179259e`. Baseline
source: `7c5e120158f1385a1fc5f20be41f66c58a605534`. Both use master
context `fc6304dfe5f2e446e09bd052a7b45f51e930f250`. The trusted workflow
source is separately frozen at
`dd777f4b7343305c4e6f44c422f44a1d78e12e4f`.
- Both variants use the same evaluator, fixtures, models, permissions,
720-second cell deadline, and 1,000-cent company and agent hard stops.
The only production difference is the compact continuation reminder.
- Suite hash:
`aee30b74b4d38ada08777798db0932fbc64e368bb427d29caa8cfd86c7f59747`.
Definition hash:
`ea9e17f54fe0af1acbb2337ddfab8a7e92db8488bd0f59510a63095ca0229b60`.
- Provider-free transport capture: startup/resume input stays at 55,726
bytes. Compact continuation input grows from 53,334 to 53,535 bytes. The
42-tool catalog stays unchanged. These are Paperclip input bytes, not
complete vendor prompt tokens.
- Focused evaluator tests: 31 pass. Native contract, transport delivery,
and session tests: 194 pass. Evaluator support: 1,819 TypeScript tests
and 128 Node tests pass, with one intentional skip.
- Full build, workspace typecheck, and evaluator typecheck pass.
Current-head CI passes all required gates. The current rollup has 51
successful check runs, two intentional Storybook skips, and a successful
Snyk status. Review is 5/5 with zero unresolved threads.
- CI attempt 1 had one initial runtime-fixture health timeout. The exact
test and its full 164-test file pass locally. One CI shard retry passed.
The original CI failure, its dependent verify failure, and the retry
remain visible in [CI
history](https://github.com/paperclipai/paperclip/actions/runs/37711235060).
- The broad local `pnpm test:run` attempt was interrupted after about 49
minutes (exit 130). It recorded one failure in the unchanged Zep
memory-connector disabled-setting test. That test and the full 388-test
tool-access file pass in separate local checks; current-head CI also
passes. The local cause is not established, and this broad local attempt
is **not** claimed as passing. Three earlier local failures also pass in
their isolated checks; their original logs remain retained.
- The first two setup admissions were cancelled before provider jobs to
include the review correction. They made no provider calls. The
completed campaigns above are the first and only model attempts for
these corrected variants.

Cost evidence stays separate from behavior. Original result summaries
report only OpenCode amounts: baseline $0.039192096 and candidate
$0.063221620. Final run ledgers also retain estimates for Claude
(baseline $1.232439000; candidate $1.333611200) and Codex (baseline
$2.340324400; candidate $2.129335600). These estimates do not replace
the original summaries. Local and GitHub runtime are unmetered here.
Invoices are unknown. This is not a cheaper or faster claim.

## Risks

- A single matched trial cannot prove general equivalence or causation.
The reminder is an instruction change, not a new completion enforcement
rule.
- Candidate OpenCode service-decline finished within one continuous run;
its baseline used two. That pair passed the task outcome, but it does
not qualify the reminder on a resumed decline turn. No extra paid run
was used to replace it.
- The text matcher is bounded evidence of an explanation. It does not
prove reasoning or consumption of feedback. Bounded stdout excerpts do
not prove that every extra attempted tool call is absent.
- Missing saved replies or continuations still fail at the original
deadline. Failed native completion remains a failure even when final
prose is correct.
- The unresolved local-suite discrepancy above remains a validation
limit. Full remote CI and both focused local reproductions pass.
- The original connection instructions stay in place. These results do
not qualify the reduction in #15489. Its original 11/15 versus 12/15
grades and two new failing pairs remain unchanged.

## Model Used

OpenAI Codex, based on GPT-6. The exact deployment ID and context window
are not exposed in this session. Capabilities used: reasoning,
repository editing, code execution, test inspection and eval analysis.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either linked existing issues or described the issue in-PR
- [x] I have not referenced internal/instance-local Paperclip issues or
links
- [x] My branch name describes the change and contains no internal
Paperclip ticket id or instance-derived details
- [x] I have run the focused local tests listed above and they pass; the
interrupted broad local run is disclosed above
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-08 04:52:12 -05:00
Devin FoleyandPaperclip e4b39da6f6 Isolate ACPX admission deadline tests from lease ports (#15527)
Apply the reviewed change for Isolate ACPX admission deadline tests from lease ports.

Validation: required local typecheck and tests, passing CI, Greptile 5/5, and independent review of the exact source head.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-07 19:20:08 -07:00
Devin FoleyandPaperclip ed0c6958f8 Explain refused local Hermes gateway connections (#15520)
Apply the reviewed change for Explain refused local Hermes gateway connections.

Validation: required local typecheck and tests, passing CI, Greptile 5/5, and independent review of the exact source head.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-07 18:55:55 -07:00
DottaandPaperclip dd777f4b73 feat(dot): complete onboarding and expand governed Runner capabilities (#15414)
## Thinking Path

> - Paperclip manages AI agents, their work, and their permissions.
> - Paperclip Runner supplies the same admitted tool authority to each
provider.
> - The Dot provider in #15402 needs reliable onboarding and useful
agent capabilities.
> - An idle Dot could not start work, assign a human, read skills, or
produce a workspace artifact.
> - Pairing also relied on a second configuration save before ordinary
admission could work.
> - This pull request adds governed idle admission and shared Runner
tools, and completes pairing atomically.
> - Operators can test Dot with fresh data while keeping normal company,
approval, budget, and run ownership checks.

## Linked Issues or Issue Description

**Subsystem affected**

Paperclip Runner, dedicated Dot MCP access, OAuth onboarding,
experimental settings, and empty worktree startup. This PR builds on
merged provider PR #15402. It reuses the merged MCP gateway from #14846
and assistant connection work from #14933 and #15380.

**Problem or motivation**

An idle Dot could see assignments but could not act on a conversation
request until someone created a task first. Its Runner catalog could not
assign tasks to humans or read pinned skills and workspace files.
First-time OAuth discovery and pairing also needed browser fixes, and a
completed pairing did not persist its binding reference on the agent.

**Proposed solution**

Keep Dot within the existing Runner. Admit a visible agent-authored
intake task for idle requests. Add people, human assignment, cross-task,
skill, and optional sandbox workspace tools through shared authority.
Relay assigned app calls through the configured MCP gateway. Add lease
renewal and follow-up references. Save pairing and its configuration
revision atomically. Show prerequisites and provide a complete copy
prompt.

**Roadmap alignment**

This extends the experimental provider in #15402. It uses the existing
governed gateway, task model, skills, artifact path, and native Runner.
It adds no separate execution subsystem.

## What Changed

- Add a standalone OpenAI Dot agent choice with an independent
experimental opt-in. It works with the general Runner option off.
Require Assistant connections (MCP), authenticated sign-in, and public
HTTPS for pairing.
- Use Dot’s own option for company package import. Allow an unpaired Dot
configuration to save after external billing acknowledgement; task
admission still requires pairing. Prepare the shared dev binary for
Dot-only opt-in.
- Label saved Dot agents as OpenAI Dot. Use prerequisite-check copy in
setup and runtime configuration.
- Route Dot creation directly to pairing after explicit external billing
acknowledgement. Hide local CLI, model, and harness setup for Dot.
Preserve the shared Runner implementation and canonical API type. Other
Runner providers still require their general opt-in.
- Add an empty worktree option with fresh signing keys and no production
data copy.
- Fix public-client OAuth negotiation, discovery compatibility, and
optional separate browser authorization origin.
- Add one-use pairing consent preview, clear copied setup instructions,
and atomic binding persistence and cleanup.
- Add idle request admission with stable request IDs and normal
scheduling, permissions, budgets, and task ownership.
- Add identity and people discovery, human task assignment and
reassignment, and authorized cross-task comments and documents.
- Read assigned skill files from pinned manifests. Relay assigned app
calls through the merged gateway without exposing credentials.
- Add an off-by-default workspace bridge. Constrain paths and writes.
Run commands in a deny-by-default OS sandbox with no network or injected
credentials. Reserve mutations before effects and never blindly repeat
uncertain work.
- Add rolling lease renewal, task pagination, bounded operation limits,
and deduplicated follow-up references without comment bodies in
webhooks.
- Add an off-by-default attachment reading setting. Restrict reads to
files on the current assigned task. Verify size and hash, cache bounded
verified copies per run, paginate text or binary bytes, and recheck live
authority before returning.
- Keep file grants operator-owned. Reject agent self-grants across
configuration routes. Preserve attachment consent in create/import
forms. Close generic API file bypasses while retaining current-run
response snapshots and permitted uploads.
- Keep provider limits explicit. Do not inherit a Dot binding,
attachment permission, or workspace permission when hiring another
agent.
- Include the required Markdown format in cross-task document writes and
validate the API title limit. Verify real creation and revision
persistence.
- Restrict command execution to Linux bubblewrap with descendant
containment. macOS retains workspace file tools and artifact publishing,
while refusing command calls. Explain the platform limit in setup.
- Exclude Paperclip instance state from workspace files, uploads,
artifact publication, and sandbox commands. Protect nested directories
and case variants. Fail closed when the directory protection scan
exceeds 4,096 directories.
- Add static UI compression for slow public tunnels. Document setup, the
complete tool inventory, and qualification limits.

## Verification

- Merge preparation on `00ca2c75b` integrates merged base #15402 and
master `fc6304dfe`. The ancestry commit preserves the reviewed follow-up
source tree. The subsequent security fix excludes instance state from
file tools, uploads, artifact publication, and sandbox commands. It
preserves private task authorization and task monitors. It regenerates
the combined tool catalog, seeded catalog digest, and protocol manifest.
Workspace typecheck, full build, and UI token gates pass. All sixteen
real Dot broker cases and 93 company import cases pass after the review
fixes and creator-attribution test correction. The exported
human-assignment catalog and Unicode page boundaries are also fixed. All
ten catalog tests and nine workspace/skill bridge tests pass. All 35
workspace bridge and authority tests passed after the instance-state
fix, including real macOS commands in that intermediate version. The
subsequent document and descendant-containment fixes pass 44 focused
tests across bridge, authority, and setup UI, with six Linux command
cases skipped on macOS. Real cross-task documents pass the route
validator and persist two revisions. macOS refuses command execution and
does not advertise the tool. Full workspace typecheck and build, changed
server/UI typechecks, and token gates pass again on the final commit.
Greptile rates final head 00ca2c75b 5/5 and its completed check
concludes success; all review threads are resolved. All 58 current-head
checks are complete: 54 passed and 4 intentionally skipped. This
includes full tests, typecheck, build, Runner, browser E2E, release
verification, and Canary Dry Run. The older full local root attempt
finished with 16,602 passes, 93 skips, and ten failures across two
suites: it began before source edits and retained earlier imported
implementations while loading later tests. Both suites pass a clean
final-head rerun (25 passed, six Linux-only command cases skipped on
macOS). This mixed-source full attempt is not a final-head full-suite
pass; use the fresh CI evidence below.
- Full workspace typecheck and build pass for the standalone Dot change
on head `392d54f80`. UI token gates are clean. The full workspace
typecheck passed before the final importer UI edit; the changed UI
typecheck, build, and token gates pass again on the final commit. The
server build passes for its unchanged final source.
- Standalone selection, creation, settings, harness visibility,
inventory, and runtime admission checks pass. OAuth onboarding and the
real Rust/PostgreSQL broker suite pass 27 cases with the general Runner
option disabled. Dot and MCP revocation still block pairing; other
Runner providers remain disabled. Create, hire, conversion, and
inherited-hire route regressions pass 68 cases. The runtime selection
suite passes 20 cases. The setup UI suite passes 50 cases. Company
import and dev binary checks pass 97 cases. Import UI checks pass 29
cases, including Dot-only selection, preservation of imported Dot
agents, generic Runner fallback, canonical configuration serialization,
and required billing acknowledgement. A read of the synthetic instance
reports the native binary required with Dot enabled, the general rollout
disabled, and no persisted native work.
- The latest attachment, operator-consent, generic API file-guard, and
bridge checks pass 80 tests. Cache and native lifecycle checks pass 550
tests; create/import builders pass 45 tests; attachment setup UI checks
pass 16 tests. The real Rust/PostgreSQL Dot broker suite passes 15
cases.
- Earlier authority, human assignment, pinned skill, confinement,
cancellation, inheritance, onboarding, replay, OpenAPI, and gateway
regressions pass their focused rechecks. Workspace writes reject
concurrent stale hashes.
- In the live empty test-drive, turn the general Runner option off and
leave Dot and MCP on. Add agent shows a separate OpenAI Dot choice.
Create rejects missing billing acknowledgement, saves the canonical Dot
configuration, and opens pairing. The existing paired Dot remains ready
and passes its prerequisite checks. No new plugin pairing was needed for
this UI change. The final browser import preview keeps a Dot source
agent as OpenAI Dot, falls back a generic Runner agent while its switch
is off, and offers Dot independently.
- Real Dot completed OAuth, signed MCP Events readiness, and an
event-only assigned document task in an empty synthetic instance.
Pairing saved its binding without a second configuration save.
- Real Dot verified human assignment, cross-task comments and documents,
pinned skill reading, sandbox commands, lease renewal, follow-up input,
and a downloaded artifact whose bytes and hash matched its receipt. An
idle conversation request created an intake, created a task for its
human owner, continued after a definite missing-file read error, and
finalized Done with exit code 0.
- After operator approval, real Dot read a synthetic assigned-task
attachment and wrote its file-only random proof into an agent-authored
document. Its first test required accepting review because the existing
document tool removed the final newline.
- On head `2626c8f9b`, real Dot read a 13,849-byte synthetic attachment
in two pages, used `expectedSha256` on page two, saved exactly its final
random marker, verified readback, and finalized Done with exit code 0. A
direct inbox check was required for this attachment qualification; it
does not claim event-only delivery.
- Previous head `392d54f80` passes all 55 checks (53 passed, two
intentionally skipped), including the full test, typecheck, build,
native Runner, browser, and release verification gates. Greptile rates
this head 5/5; all review threads are resolved.
- Head `2626c8f9b` passed all 56 checks: 54 passed and two intentionally
skipped. This includes full typecheck, build, native Runner, server
tests, serialized suites, browser E2E, and Canary Dry Run. The unchanged
Cursor managed-runtime test exceeded its five-second deadline on the
first attempt; its focused local suite passed all eight cases, and the
single CI rerun plus dependent verify gate passed.
- A prior full local serial test attempt reported 19 failures (16,141
passed, 88 skipped) and stopped before later wrapper groups. It began
before the final source edits. Every failed suite has a passing fresh
recheck; the macOS snapshot stress case passes alone in 227 seconds. The
previous head `000fb9261` passed all 56 CI checks. PRs leave
`pnpm-lock.yaml` unchanged; CI and the refresh bot own dependency
resolution.

## Risks

- Dot remains off by default. Its own opt-in does not enable other
Runner providers. It still requires the MCP option; disabling Dot blocks
new work while keeping existing recovery and saved bindings.
- Dot requires a stable public HTTPS origin. Its base provider in #15402
is merged. Temporary tunnels are useful for testing but are not
permanent deployments.
- Idle intake creates a visible agent-authored task. It does not
fabricate a human message or bypass ordinary admission.
- Workspace commands require Linux bubblewrap with a private PID
namespace; deployment qualification is still needed. macOS file tools
and artifact publishing remain available, but commands are disabled
because sandbox-exec does not contain detached descendants. There is no
unrestricted fallback. Command protection fails closed above 4,096
workspace directories. The historical macOS command walkthrough does not
qualify the current Linux implementation.
- Provider model choice, token usage, cost, native thread control, and
global external stopping remain unavailable. Known Paperclip budget
gates still apply.
- The workspace bridge and attachment reader are separate opt-in
settings. Reading assigned task files sends their contents to OpenAI.
Revocation prevents future reads but cannot withdraw bytes already sent.
Files are read on request; automatic inbound attachment staging remains
disabled.
- An existing event registration can retain earlier instructions that
prohibit extra tasks. Dot asked for permission before a second intake
after the final event-only bootstrap; that extra no-nudge continuation
is not live-qualified under that earlier registration. The later
attachment qualification submitted normally through the composer. The
revised onboarding prompt describes the new idle entry point, and its
protocol polling path is tested.
- OpenAI event delivery can be delayed; a webhook acknowledgement is not
proof that Dot has begun work.
- A running Dot can retain an old plugin catalog after tool refresh.
Refresh and actual tool exposure must be checked before using new
top-level actions.
- Hosted and remote controller modes are not qualified.

## Model Used

OpenAI Codex, based on GPT-6. The exact deployment ID and context window
size are not exposed in this session. Capabilities used: reasoning,
repository editing, code execution, test inspection, and browser
control.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either linked existing issues or described the issue in-PR
following the relevant issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links
- [x] My branch name describes the change and contains no internal
Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass (focused suites and all
fresh failure rechecks pass; the earlier full attempt is disclosed
above)
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-07 19:44:17 -05:00