1966 Commits
Author SHA1 Message Date
DottaandPaperclip efc2e6810e fix: show each task once in dashboard agent cards (#14847)
## Thinking Path

> - Paperclip helps people manage AI agents and their tasks.
> - The dashboard shows recent agent activity in compact cards.
> - Those cards use run records, so two runs for one task can create
duplicate task cards.
> - An operator needs to see each task once when scanning the dashboard.
> - This pull request selects one run per linked task before it applies
the card limit.
> - The live runs page still shows each run for run inspection.

## Linked Issues or Issue Description

**What happened?**

The dashboard showed the same task in two agent cards when that task had
both an active run and a completed run.

**Expected behavior**

The dashboard should show a linked task at most once. It should keep the
active run card when one is present.

**Steps to reproduce**

1. Start an agent run for a task that already has a completed run.
2. Open the company dashboard.
3. Observe two cards linked to the same task.

**Paperclip version or commit**

Reproduced on the pre-change master at `8b4aa0692`.

**Deployment mode**

Local dev, built from source. The bug is in the core dashboard UI and
does not depend on an agent adapter or database mode.

## What Changed

- Select distinct linked tasks from capped active and recent run samples
before applying the dashboard card limit.
- Keep separate cards for runs without a linked task.
- Preserve the dashboard's count of additional distinct cards behind the
live-runs link.
- Add UI and embedded Postgres regression tests for duplicate runs and
document the dashboard rule.
- Give the existing multi-request cross-tenant authorization test enough
time on loaded CI runners.

## Verification

- `pnpm --filter @paperclipai/ui exec vitest run
src/components/ActiveAgentsPanel.test.tsx`
- `pnpm --filter @paperclipai/ui exec vitest run
src/api/heartbeats.test.ts`
- `pnpm exec vitest run server/src/__tests__/dashboard-service.test.ts
server/src/__tests__/agent-live-run-routes.test.ts`
- `pnpm exec vitest run
server/src/__tests__/agent-cross-tenant-authz-routes.test.ts`
- `pnpm --filter @paperclipai/ui typecheck`
- `pnpm --filter @paperclipai/server typecheck`
- `pnpm --filter @paperclipai/ui build`
- `pnpm -r typecheck`
- `pnpm build`
- `pnpm check:token-gates`
- Review the dashboard with an active and a completed run on the same
task. Confirm that it shows one card. Open Live agent runs to inspect
both run records.

## Risks

- A very high volume of recent runs for one task can fill the capped
sample and leave older tasks off the dashboard. The Live runs page
remains available for full run inspection.
- The dashboard may fetch up to 50 distinct run representatives to
preserve its overflow count. The default run API response and persisted
data are unchanged.

> 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, GPT-6. The runtime does not expose the exact model ID or
context window size to this task. The model used reasoning, tool calls,
and code 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
- [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-01 12:18:35 -05:00
Devin FoleyandPaperclip 6f2ce27ca7 fix(workspaces): prepare checkouts without a local seed config (#14810)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Task preparation can create an isolated Git worktree and run its
setup script.
> - The Paperclip repository setup script also prepares a seeded
development instance.
> - A server configured through environment variables can have no local
seed config.
> - This stops ordinary task preparation before the agent starts.
> - This pull request prepares checkout dependencies when no seed source
exists, while preserving errors for invalid sources and existing
development instances.
> - Tasks can start without creating or claiming a seeded development
runtime.

## Linked Issues or Issue Description

**What happened?**

A task with the Paperclip repository fails during setup when the host
has no repository-local or default instance config. The automatic
worktree provisioner requires a seed source even when the task only
needs the checkout.

**Expected behavior**

A plain checkout should prepare its dependencies without a local
development database. A missing custom source, invalid source path, or
existing development instance with a missing source should still fail.
Starting a seeded runtime must still require a valid source.

**Steps to reproduce**

1. Run an environment-configured Paperclip server without a local
instance config.
2. Add the Paperclip repository to a project.
3. Start a task that uses an isolated Git worktree without a custom
provision command.
4. Observe the setup error before agent execution.

**Paperclip version or commit**

Reproduced against `0d3e7bf6ac` with a real script subprocess and
workspace realization regression.

**Deployment mode**

Environment-configured server with external PostgreSQL.

**Additional context**

Searched open and closed GitHub PRs and issues. Related work: Refs
#14795 (seed-source diagnostics) and Refs #11733 (source validation).
This change keeps source validation and seed-readiness checks in place.

## What Changed

- Permit dependency setup when the default seed config is absent
(including the Docker image config path) and the worktree has no
development-instance state.
- Keep missing custom configs, invalid paths, and lost sources for
existing instances as errors.
- Create no config, environment file, or seed manifest for a plain
checkout.
- Keep dependency install failures visible and allow normal instance
setup once a source becomes available.
- Cover the setup script, seed-runtime refusal, and automatic server
worktree realization.
- Document the difference between checkout preparation and
seeded-runtime readiness.

## Verification

- Regression tests failed before the fix for absent-source checkout
preparation and dependency setup.
- `bash -n scripts/provision-worktree.sh`
- `node --test scripts/__tests__/provision-worktree-self-heal.test.mjs`
— 34 passed; 1 existing flock-dependent test skipped on macOS.
- Server regression — 2 passed, covering an unset config and the Docker
image default path.
- `pnpm build` — passed.
- `pnpm -r typecheck` — passed.
- All CI checks passed, including the full test shards, build,
typecheck, browser tests, and canary dry run.
- The first local `pnpm test:run` encountered two chat-test failures
because skill discovery selected an unrelated parent directory. Both
tests pass at the PR commit in a clean temporary checkout. The full
local run was not completed; the redundant clean run was stopped after
the complete CI suite passed.
- `git diff --check` and added-line secrets/PII scan passed.
- Greptile: 5/5, no comments. The branch has no merge conflicts.
- No live tenant deployment or task retry was performed.

## Risks

- A new checkout with no implicit seed config now completes dependency
setup. It has no seeded development instance. A runtime request still
fails until a valid source exists.
- Existing instances and custom source paths retain their failure
behavior. The script does not synthesize a source from environment
credentials or copy a live database.
- No schema, API, or task-setting changes. Revert the commit to restore
the previous setup behavior.

## Model Used

OpenAI Codex (GPT-6), with tool-assisted analysis, code edits, and local
tests. The runtime did not expose a verified model variant 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-01 10:00:25 -07:00
DottaandPaperclip 6395cae072 fix(runner): ship provider pack in the standard Docker image (#14854)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Remote OpenCode and ACPX runs need a provider pack from the
application build.
> - Cloud now builds its application image from the standard production
image.
> - The provider pack was added only to the legacy cloud image target.
> - The standard image therefore cannot supply the pack to downstream
Cloud images.
> - This pull request adds the pack to the production image and lets the
cloud target inherit it.
> - Remote runs can then use the pack that matches the application
source commit.

## Linked Issues or Issue Description

Refs #13827. Refs #14024.

The standard production image does not include the remote provider pack.
Downstream Cloud images inherit that omission. Remote OpenCode and ACPX
runs fail with `runner_remote_provider_artifact_incompatible` and ask
for `PAPERCLIP_RUNNER_REMOTE_PROVIDER_PACK_PATH`.

## What Changed

- Build and copy the provider pack into the standard production image.
- Set the pack path and check that an unprivileged user can read its
artifacts and execute Node.
- Let the legacy cloud target inherit the pack from production.
- Add regression checks for production packaging and cloud inheritance.
- Document stamped image behavior and the default pack path.

## Verification

- The 12 focused Docker stamp and provider-pack reuse tests pass on
commit `4a11f8d52aead55f85527c8e82c6d7f2644ce0da`.
- The new packaging regression failed against the old Dockerfile and
passed with the fix.
- On the current commit, `pnpm build` and `pnpm -r typecheck` pass. All
seven standard-image contract tests also pass.
- The current-head CI build, typecheck, test, browser, and native Runner
checks passed. The local full suite hit one chat-channel assertion
failure; that exact test passed in isolation. The remaining local run
was stopped after CI completed to avoid duplicating its full suite. An
earlier run on the pre-rebase base had a heartbeat comment batching
timeout; the external chat wait integration suite passed all 142 tests
in isolation.
- [The stamped preview image build
passed](https://github.com/paperclipai/paperclip/actions/runs/36885002850/job/110446106393),
including the production-stage provider pack build, copy, and
unprivileged artifact readability/executable check. Publication,
compatibility validation, and deployment of this exact commit to a
staging QA instance passed.
- Reproduced the exact missing-pack error on an existing staging image
with Paperclip Runner, ACPX, and Claude in a remote Daytona computer.
The legacy Claude adapter succeeds with the same account and computer.
After deploying this commit, the same native task succeeded: it computed
`5050` with a real remote shell command, wrote a proof file, read it
back in a separate call, uploaded the file as a deliverable, and
completed the task. The uploaded file contents and Done state persisted
after a page reload. The run trace confirms Paperclip Runner, ACPX, and
Claude. The first run took 2m 59s, including approximately 97s of remote
artifact preparation. A second native run read the unchanged file from
the prior run and completed successfully. Its startup took about 120s;
this verifies repeated execution and file persistence, not fast
provider-pack reuse.

## Risks

- Stamped standard images now include the provider pack and its build
cost. A pack build failure now fails the production image build.
- Unstamped local builds still skip pack generation. Setting the path
alone does not create a pack.
- No database, provider authentication, or runner verification rules
change.

## Model Used

OpenAI Codex, GPT-6. The exact serving model identifier and context
window are not exposed in this session. Capabilities used: repository
inspection, code editing, shell verification, and browser testing.

## 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-01 11:07:50 -05:00
DottaandPaperclip 4ac374103f fix(connections): repair Asana MCP and add shared-app sign-in (#14756)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Connections let agents use provider tools through the permission
gateway.
> - Asana provides an official remote MCP server, but its v2 server
requires a registered MCP OAuth app.
> - Setup can discover retired v1 endpoints and send a callback that
differs from the displayed URL.
> - This pull request repairs custom app setup and adds sign-in through
Paperclip's shared app.
> - Users can choose their own app without enrolling with Paperclip
Cloud.
> - Agents can use Asana tools after the user connects their account and
sets action permissions.

## Linked Issues or Issue Description

Related: #14739 supplies the personal credential repair used by resumed
Asana setup. No duplicate Asana authentication PR was found.

**What happened?**

Asana setup failed even with a user-created app. Root discovery metadata
still points at v1. MCP v2 uses the Asana OAuth issuer and requires an
MCP app with a client secret. Local setup also displayed a localhost
callback while an Origin header could make authorization use a numeric
loopback callback.

**Expected behavior**

Sign in with Paperclip's app when its broker profile is available. Keep
custom MCP app setup available without Cloud enrollment. Use the correct
issuer, callback, client credentials, and resource throughout setup.

**Steps to reproduce**

1. Open Asana in the connection catalog.
2. Supply an Asana MCP app's client ID and secret.
3. Start OAuth on a local instance opened with a numeric loopback
address, or resume a draft that cached v1 metadata.
4. Observe the wrong discovery endpoint or callback mismatch.

**Paperclip version or commit**

Reproduced from b54b2dc35c. Rebased onto
master at `0829d94af` after the single-screen setup change in #14811.

**Deployment mode**

Local development from source. The managed path also supports enrolled
self-hosted instances.

## What Changed

- Add the `asana.mcp` managed profile and the default Sign in with Asana
method.
- Use Asana's reviewed v2 protected-resource metadata before cached
endpoints.
- Require a custom MCP app's client secret and retain saved credentials
during setup or reconnect. Repair only the known Asana v1
issuer/resource binding, retaining company and callback checks.
- Expose a boolean for the acting user's saved client secret. The form
offers secret reuse only when that user has an active grant with the
required reference.
- Let users select their own app from the enrollment and
shared-app-unavailable screens, or from Advanced on the single-screen
setup page.
- Canonicalize HTTP loopback callbacks even when the request includes an
Origin header.
- Extend signed broker claims and provider URL validation for Asana.
Require refresh credentials on managed authorization.
- Document setup, distribution, and shared-app rollout requirements.
- Resolve permission-profile name collisions when finishing another
account. The live staging test found this after renaming the first Asana
connection; OAuth succeeded but profile finalization failed.

## Verification

- Final live staging proof used app commit
`c6053157c4e42ac017727117b754ae77fa5c45fa` and the real Cloud broker at
`767b63835170f664542afd0df99a76615e204b62`. In the embedded browser,
default shared sign-in required no client credentials, returned through
the central Cloud callback to the tenant, and discovered 39 actions. Get
me succeeded through the gateway as the selected QA agent (2.1 seconds).
The custom-app connection also returned a real result on this final
build (0.9 seconds).
- Retried the shared draft that failed during the first staging test. It
completed after the profile-name fix, retained the selected agent, and
kept the existing custom connection intact. Two database regressions
reproduced the collision before the fix and passed afterward. The
updated transaction rollback test also passes.
- Shared reconnect returned to the same staging connection with 39
actions. Earlier staging checks verified the custom-app fallback when
the shared profile was unavailable, saved-secret reuse on reconnect, and
Off blocking the action test. Allowed was restored after that check.
- Local live-provider checks also repaired a saved Asana v1
issuer/resource binding without reentering the secret and verified that
numeric-loopback setup uses the displayed localhost callback. Expiring
the local managed access-token timestamp triggered a real Asana refresh
and a successful Get me call. These early local broker tests used
enrollment/authentication and storage fixtures; the final staging proof
used deployed Cloud identity and persistent storage.
- The new production app is registered and configured, but production
sign-in has not been deployed or verified. Live provider revocation was
not run because the existing staging test app is shared with other
connections.

- After rebasing onto the single-screen setup flow, full `pnpm -r
typecheck`, `pnpm build`, and `pnpm check:token-gates` pass. Focused
verification passes 365 service and 36 broker-client tests. Broader
checks pass all 833 shared-package tests and all 530 connector-page
tests. The shared suite uses `TMPDIR=/private/tmp` to avoid macOS
temporary-directory symlinks in its canonical-path tests. The UI tests
verify the shared-app default and switching to a custom app with its
required client secret.
- Embedded-browser smoke on the current rebased build verified the
shared sign-in default, Advanced → custom app (client ID and secret
required), and switching back to Paperclip. Both existing Asana
connections remained connected after restart. No new provider
authorization was performed during this smoke.
- The full local `pnpm test:run` was interrupted when the execution
session restarted. Before interruption, it reported one runtime-slot
restart test failure. That test passed on an isolated retry after
clearing two unused PostgreSQL shared-memory segments. The full local
suite did not complete; CI must pass on the current head before merge.
- All 52 CI and security checks pass on
`9318fd4e9b616cdc3de12f40cdb9bd32d865af4c` (CI run `36882064080`),
including all eight browser shards, nine serialized-server shards,
build, typecheck, and canary dry run. Two optional Storybook checks were
skipped. Greptile review 4 reports 5/5 on this exact commit, with all
review threads resolved. Its updated summary identifies the current SHA;
this comment-triggered review did not publish a separate GitHub check
run.
- Provider revocation is unit-tested in the companion broker. Live
provider revocation was not run because the existing test app is shared
with other connections.

## Risks

- The shared Paperclip Asana MCP app has been registered with its
production callback and Any workspace distribution. Its secret is
provisioned in the production secret store, and the runtime client ID
and secret reference are configured. The production profile is enabled
in the saved deployment configuration. The companion broker has merged
and passed staging deployment; production sign-in still requires a
production deployment and live verification. Custom setup remains
available.
- Asana MCP uses the provider's fixed `default` grant. Paperclip action
policies limit agent tool use; they do not narrow provider consent.
- The callback correction affects HTTP loopback OAuth flows. Public
HTTPS callbacks retain their existing behavior.
- Reviewed discovery URLs now override stale cached endpoints. Tests
cover the Asana v1-to-v2 repair.
- No schema migration. Connection removal retains the existing
local-only revocation behavior.

## Model Used

OpenAI GPT-6 through Codex, with code execution, browser testing, and
GitHub tooling. The exact model variant 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-01 10:24:44 -05:00
dependabot[bot]andPriya Raman 8b4aa06920 build(deps): bump multer from 2.2.0 to 2.4.0 (#14493)
Bumps [multer](https://github.com/expressjs/multer) from 2.2.0 to 2.4.0.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/expressjs/multer/releases">multer's
releases</a>.</em></p>
<blockquote>
<h2>v2.4.0</h2>
<h2>Highlights</h2>
<p><strong>multer finally supports Google Cloud Functions and Firebase
🎉</strong></p>
<p>These platforms read the request body before your code runs, so
multer's classic <code>req.pipe(busboy)</code> received nothing: empty
<code>req.body</code>, empty <code>req.files</code>, and nearly a decade
of duplicated issues.</p>
<p>The new <code>streamHandler</code> option closes that gap: you decide
how the body reaches the parser, so the pre-read <code>rawBody</code>
just works (see image).</p>
<pre lang="js"><code>const multer = require('multer')
<p>const upload = multer({<br />
storage: multer.memoryStorage(),<br />
streamHandler: (req, busboy) =&gt; {<br />
// Cloud Functions / Firebase expose the pre-read body here<br />
if (req.rawBody) busboy.end(req.rawBody)<br />
else req.pipe(busboy)<br />
}<br />
})</p>
<p>app.post('/upload', upload.single('file'), (req, res) =&gt; {<br />
res.json({ name: req.file.originalname, size: req.file.size })<br />
})<br />
</code></pre></p>
<p>This landed thanks to community PRs going back to 2017; their authors
are credited as co-authors in the release.</p>
<h2>Important: Security</h2>
<ul>
<li>Fix <a
href="https://www.cve.org/CVERecord?id=CVE-2026-88932">CVE-2026-88932</a>
(<a
href="https://github.com/expressjs/multer/security/advisories/GHSA-3pph-fpjx-jg34">GHSA-3pph-fpjx-jg34</a>)</li>
</ul>
<h2>What's Changed</h2>
<ul>
<li>docs: remove README translations by <a
href="https://github.com/UlisesGascon"><code>@​UlisesGascon</code></a>
in <a
href="https://redirect.github.com/expressjs/multer/pull/1463">expressjs/multer#1463</a></li>
<li>ci: add macOS to the test matrix by <a
href="https://github.com/kilisamemarisaaa"><code>@​kilisamemarisaaa</code></a>
in <a
href="https://redirect.github.com/expressjs/multer/pull/1464">expressjs/multer#1464</a></li>
<li>feat. improve wording for LIMIT_UNEXPECTED_FILE error code by <a
href="https://github.com/flashbag"><code>@​flashbag</code></a> in <a
href="https://redirect.github.com/expressjs/multer/pull/426">expressjs/multer#426</a></li>
<li>feat: add filename to file errors by <a
href="https://github.com/UjjwalKumar239"><code>@​UjjwalKumar239</code></a>
in <a
href="https://redirect.github.com/expressjs/multer/pull/1416">expressjs/multer#1416</a></li>
<li>refactor: remove concat-stream dependency by <a
href="https://github.com/Phillip9587"><code>@​Phillip9587</code></a> in
<a
href="https://redirect.github.com/expressjs/multer/pull/1356">expressjs/multer#1356</a></li>
<li>fix: reject non-integer fileSize limits by <a
href="https://github.com/abhu85"><code>@​abhu85</code></a> in <a
href="https://redirect.github.com/expressjs/multer/pull/1395">expressjs/multer#1395</a></li>
<li>fix: allow exactly limits.parts parts by <a
href="https://github.com/deepakganesh78"><code>@​deepakganesh78</code></a>
in <a
href="https://redirect.github.com/expressjs/multer/pull/1446">expressjs/multer#1446</a></li>
<li>fix: do not consume maxCount for files skipped by fileFilter by <a
href="https://github.com/Sagargupta16"><code>@​Sagargupta16</code></a>
in <a
href="https://redirect.github.com/expressjs/multer/pull/1426">expressjs/multer#1426</a></li>
<li>fix: validate all limits at construction time by <a
href="https://github.com/ShubhamOulkar"><code>@​ShubhamOulkar</code></a>
in <a
href="https://redirect.github.com/expressjs/multer/pull/1335">expressjs/multer#1335</a></li>
<li>test: cover storage engine _removeFile invocation semantics by <a
href="https://github.com/kilisamemarisaaa"><code>@​kilisamemarisaaa</code></a>
in <a
href="https://redirect.github.com/expressjs/multer/pull/1460">expressjs/multer#1460</a></li>
<li>feat: accept a function for limits by <a
href="https://github.com/hossein-zare"><code>@​hossein-zare</code></a>
in <a
href="https://redirect.github.com/expressjs/multer/pull/1133">expressjs/multer#1133</a></li>
<li>fix: add flush option to disk storage to fsync files before
completion by <a
href="https://github.com/kilisamemarisaaa"><code>@​kilisamemarisaaa</code></a>
in <a
href="https://redirect.github.com/expressjs/multer/pull/1458">expressjs/multer#1458</a></li>
<li>feat: expose busboy defCharset, highWaterMark and fileHwm options by
<a
href="https://github.com/UlisesGascon"><code>@​UlisesGascon</code></a>
in <a
href="https://redirect.github.com/expressjs/multer/pull/1465">expressjs/multer#1465</a></li>
<li>docs: describe the file stream contract for storage engines by <a
href="https://github.com/UlisesGascon"><code>@​UlisesGascon</code></a>
in <a
href="https://redirect.github.com/expressjs/multer/pull/1468">expressjs/multer#1468</a></li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/expressjs/multer/blob/main/CHANGELOG.md">multer's
changelog</a>.</em></p>
<blockquote>
<h2>2.4.0</h2>
<ul>
<li>Fix <a
href="https://www.cve.org/CVERecord?id=CVE-2026-88932">CVE-2026-88932</a>
(<a
href="https://github.com/expressjs/multer/security/advisories/GHSA-3pph-fpjx-jg34">GHSA-3pph-fpjx-jg34</a>)</li>
<li>Add <code>filename</code> to <code>LIMIT_FILE_SIZE</code> and
<code>LIMIT_UNEXPECTED_FILE</code> errors (<a
href="https://redirect.github.com/expressjs/multer/pull/1416">#1416</a>)</li>
<li>Accept a function for <code>limits</code>, called with the request,
to set limits per request (<a
href="https://redirect.github.com/expressjs/multer/pull/1133">#1133</a>)</li>
<li>Add opt-in <code>flush</code> option to <code>DiskStorage</code> to
fsync files before the callback runs (<a
href="https://redirect.github.com/expressjs/multer/pull/1458">#1458</a>)</li>
<li>Expose busboy's <code>defCharset</code>, <code>highWaterMark</code>
and <code>fileHwm</code> options (<a
href="https://redirect.github.com/expressjs/multer/pull/1465">#1465</a>)</li>
<li>Add <code>streamHandler</code> option to feed busboy from
pre-consumed bodies (Google Cloud Functions, Firebase) (<a
href="https://redirect.github.com/expressjs/multer/pull/1466">#1466</a>)</li>
<li>Allow <code>multer.diskStorage()</code> to be called without options
(<a
href="https://redirect.github.com/expressjs/multer/pull/1471">#1471</a>)</li>
<li>Decode WHATWG-escaped characters (<code>%0A</code>,
<code>%0D</code>, <code>%22</code>) in field names, matching
<code>file.originalname</code> since 2.3.0: <code>req.body</code> keys,
<code>file.fieldname</code> and <code>err.field</code> now carry the
real name. If you matched the escaped spelling as a workaround, use the
real name now (<a
href="https://redirect.github.com/expressjs/multer/pull/1473">#1473</a>)</li>
<li>Report the decoded filename in <code>err.filename</code> on
<code>LIMIT_FILE_SIZE</code> errors, matching
<code>file.originalname</code> (<a
href="https://redirect.github.com/expressjs/multer/pull/1478">#1478</a>)</li>
<li>Reject non-integer or negative <code>limits</code> values at
construction time; a float limit silently disabled the check (<a
href="https://redirect.github.com/expressjs/multer/pull/1395">#1395</a>,
<a
href="https://redirect.github.com/expressjs/multer/pull/1335">#1335</a>)</li>
<li>Accept requests with exactly <code>limits.parts</code> parts;
<code>LIMIT_PART_COUNT</code> now fires only when the limit is exceeded.
If you set <code>parts</code> one higher to work around this, you can
drop the extra one (<a
href="https://redirect.github.com/expressjs/multer/pull/1446">#1446</a>)</li>
<li>Files skipped by <code>fileFilter</code> no longer count towards
<code>maxCount</code> (<a
href="https://redirect.github.com/expressjs/multer/pull/1426">#1426</a>)</li>
<li>Change the <code>LIMIT_UNEXPECTED_FILE</code> message to
&quot;Unexpected file field&quot; (<a
href="https://redirect.github.com/expressjs/multer/pull/426">#426</a>)</li>
<li>Remove the <code>concat-stream</code> dependency (<a
href="https://redirect.github.com/expressjs/multer/pull/1356">#1356</a>)</li>
<li>Docs: add JSDoc to the public API and document the storage engine
stream contract (<a
href="https://redirect.github.com/expressjs/multer/pull/1467">#1467</a>,
<a
href="https://redirect.github.com/expressjs/multer/pull/1468">#1468</a>)</li>
<li>Docs: add FormData upload examples (<a
href="https://redirect.github.com/expressjs/multer/pull/896">#896</a>)</li>
<li>Docs: remove the translated READMEs (<a
href="https://redirect.github.com/expressjs/multer/pull/1463">#1463</a>)</li>
<li>Internal: run the test suite on macOS (<a
href="https://redirect.github.com/expressjs/multer/pull/1464">#1464</a>)</li>
</ul>
<h2>2.3.0</h2>
<ul>
<li>Fix <a
href="https://www.cve.org/CVERecord?id=CVE-2026-77078">CVE-2026-77078</a>
(<a
href="https://github.com/expressjs/multer/security/advisories/GHSA-wc9g-mqfw-jrwm">GHSA-wc9g-mqfw-jrwm</a>)</li>
<li>Fix <a
href="https://www.cve.org/CVERecord?id=CVE-2026-77037">CVE-2026-77037</a>
(<a
href="https://github.com/expressjs/multer/security/advisories/GHSA-qfvm-cv95-jqjf">GHSA-qfvm-cv95-jqjf</a>)</li>
<li>Fix <a
href="https://www.cve.org/CVERecord?id=CVE-2026-77063">CVE-2026-77063</a>
(<a
href="https://github.com/expressjs/multer/security/advisories/GHSA-qvfw-j98x-7q72">GHSA-qvfw-j98x-7q72</a>)</li>
<li>Fix <a
href="https://www.cve.org/CVERecord?id=CVE-2026-82333">CVE-2026-82333</a>
(<a
href="https://github.com/expressjs/multer/security/advisories/GHSA-535w-7cp7-47q4">GHSA-535w-7cp7-47q4</a>)</li>
<li>Add <code>MulterError</code> codes <code>INVALID_FIELD_NAME</code>
and <code>STREAM_DESTROYED</code></li>
<li>Add opt-in <code>limits.fieldArrayIndexLimit</code> to bound numeric
array indexes in field names (<a
href="https://redirect.github.com/expressjs/multer/pull/1438">#1438</a>)</li>
<li>Accept files whose size is exactly <code>limits.fileSize</code> (<a
href="https://redirect.github.com/expressjs/multer/pull/1407">#1407</a>)</li>
<li>Preserve the caller's async context (<code>AsyncLocalStorage</code>)
when calling <code>next()</code> (<a
href="https://redirect.github.com/expressjs/multer/pull/1124">#1124</a>)</li>
<li>Decode WHATWG-escaped characters (<code>%0A</code>,
<code>%0D</code>, <code>%22</code>) in <code>file.originalname</code>
(<a
href="https://redirect.github.com/expressjs/multer/pull/1421">#1421</a>)</li>
<li>Do not crash when <code>fileFilter</code> invokes its callback more
than once (<a
href="https://redirect.github.com/expressjs/multer/pull/1427">#1427</a>)</li>
<li>Use a fallback message for <code>MulterError</code> codes without a
mapping (<a
href="https://redirect.github.com/expressjs/multer/pull/1448">#1448</a>)</li>
<li>Docs: clarify <code>preservePath</code> and <code>parts</code>, use
<code>crypto.randomBytes</code> in the <code>DiskStorage</code> example
(<a
href="https://redirect.github.com/expressjs/multer/pull/1414">#1414</a>,
<a
href="https://redirect.github.com/expressjs/multer/pull/1430">#1430</a>,
<a
href="https://redirect.github.com/expressjs/multer/pull/1436">#1436</a>)</li>
<li>Docs: add Indonesian, Japanese and Tamil translations and refresh
all translations from the current README (<a
href="https://redirect.github.com/expressjs/multer/pull/1431">#1431</a>,
<a
href="https://redirect.github.com/expressjs/multer/pull/1354">#1354</a>,
<a
href="https://redirect.github.com/expressjs/multer/pull/1462">#1462</a>)</li>
<li>Internal: run the test suite on Windows (<a
href="https://redirect.github.com/expressjs/multer/pull/1334">#1334</a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/expressjs/multer/commit/35979e5afbb814bdb4b750ce028b125eb84c53af"><code>35979e5</code></a>
2.4.0 (<a
href="https://redirect.github.com/expressjs/multer/issues/1469">#1469</a>)</li>
<li><a
href="https://github.com/expressjs/multer/commit/b888532fe2e10ceb13da44286448cb2bb4ce9720"><code>b888532</code></a>
chore(deps): bump github/codeql-action/upload-sarif to 4.37.9 (<a
href="https://redirect.github.com/expressjs/multer/issues/1474">#1474</a>)</li>
<li><a
href="https://github.com/expressjs/multer/commit/e6bcd7db69315714fb9a38b1cd1e0f582cbce65a"><code>e6bcd7d</code></a>
chore(deps): bump github/codeql-action/analyze from 4.37.4 to 4.37.9 (<a
href="https://redirect.github.com/expressjs/multer/issues/1475">#1475</a>)</li>
<li><a
href="https://github.com/expressjs/multer/commit/00dec43b394c5bfaf4efb6d0fe8467bad05525ed"><code>00dec43</code></a>
chore(deps): bump github/codeql-action/init from 4.37.4 to 4.37.9 (<a
href="https://redirect.github.com/expressjs/multer/issues/1476">#1476</a>)</li>
<li><a
href="https://github.com/expressjs/multer/commit/8d5c3b72e430e7edaa2749e96dcb75bf18d84733"><code>8d5c3b7</code></a>
feat: allow diskStorage without options (<a
href="https://redirect.github.com/expressjs/multer/issues/1471">#1471</a>)</li>
<li><a
href="https://github.com/expressjs/multer/commit/02f6e8265b6bf6b6921a819db3b84276efa03ed2"><code>02f6e82</code></a>
fix: report the decoded filename on LIMIT_FILE_SIZE (<a
href="https://redirect.github.com/expressjs/multer/issues/1478">#1478</a>)</li>
<li><a
href="https://github.com/expressjs/multer/commit/bc3f72d5edaa19b993771348e3fb47b366316a88"><code>bc3f72d</code></a>
fix: decode escaped field names, not just filenames (<a
href="https://redirect.github.com/expressjs/multer/issues/1473">#1473</a>)</li>
<li><a
href="https://github.com/expressjs/multer/commit/2661325ba8ca2a72b7fb554b63d2df51da9290c4"><code>2661325</code></a>
docs: add JSDoc to the public API (<a
href="https://redirect.github.com/expressjs/multer/issues/1467">#1467</a>)</li>
<li><a
href="https://github.com/expressjs/multer/commit/53337f9713619ef3381ee6b4e541f926dbaac305"><code>53337f9</code></a>
fix: remove late-completing uploads aborted before the engine names
them</li>
<li><a
href="https://github.com/expressjs/multer/commit/7f2c9ab5f35c0478a7b3bb0f5e1af9b536780132"><code>7f2c9ab</code></a>
feat: add streamHandler option to feed busboy from pre-consumed bodies
(<a
href="https://redirect.github.com/expressjs/multer/issues/1466">#1466</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/expressjs/multer/compare/v2.2.0...v2.4.0">compare
view</a></li>
</ul>
</details>
<details>
<summary>Maintainer changes</summary>
<p>This version was pushed to npm by <a
href="https://www.npmjs.com/~GitHub%20Actions">GitHub Actions</a>, a new
releaser for multer since your current version.</p>
</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: Priya Raman <noreply@paperclip.ing>
2026-10-01 15:00:48 +00:00
DottaandPaperclip 0829d94af2 fix(auth): derive low-trust human direction from existing execution records (#14775)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Low-trust review contains work that may include hostile input.
> - Its default intake boundary currently blocks direct human chat and
tasks outside that boundary.
> - Human direction should authorize the assigned work while preserving
containment.
> - Existing conversations and execution requests already identify
direct human instructions.
> - This pull request derives exact-task authority from those records
and the current assignee.
> - The agent can perform that work without gaining access to unrelated
tasks or privileged tools.

## Linked Issues or Issue Description

**What happened?**

A low-trust agent with a project boundary rejects its owner's direct
Agent Chat before provider execution. Human-assigned tasks outside that
project fail the same check.

**Expected behavior**

An authorized human can talk to the agent or assign it a task. The exact
task runs with its existing sandbox, credential, and tool restrictions.

**Steps to reproduce**

1. Enable Agent Chat and isolated workspaces. Configure a sandbox agent
with low-trust review scoped to an intake project.
2. Send the agent a direct board chat message, or assign it a
projectless task.
3. Observe `low_trust_boundary_mismatch` before execution.

Related: #14766 adds private task directories for repo-free low-trust
execution. It is now merged into master and included in the branch base,
so CI and staging verify the combined behavior.

## What Changed

- Derive owner-chat access from existing conversation identity.
- Derive exact-task access from the existing human requester and
server-owned request origin, including coalesced requests. Plugin and
external sender attribution do not authorize work.
- Follow existing `retryOfRunId` database links for automatic
continuations, checking company, agent, and task throughout; cancelled
ancestors cannot grant authority.
- Require a live run and current assignment. Preserve sandbox,
credential, privileged-tool, responsible-user, and quarantined-output
checks.
- Retain board backlog assignments in existing request records without
starting execution. Reassignment cancels old human requests in the
common service transaction, including plugin writes; late settlement
cannot revive them.
- Add real database and HTTP coverage for request provenance, retry
ancestry, cancelled runs, concurrent reassignment, spoofing, and
containment. Document the rule.
- Preserve legacy board assignment requests through their existing
source, reason, and human requester.
- Use the existing wrapped-error helper for concurrent chat-question
idempotency; a deterministic race test reproduces the CI failure before
the fix and passes after it.
- No new schema, migrations, or user-identity fields. Existing requester
columns hold attribution.

## Verification

- Passed the focused database, policy-retention, HTTP, and reassignment
tests locally. The HTTP test creates a task through the real board route
and checks the resulting persisted wakeup before exercising agent reads,
comments, mutations, and review handoff.
- Database tests hold a reassignment transaction open to verify coherent
authorization before and after commit, with a two-connection pool. They
cover retries, coalesced requests, cancelled ancestry, invalid
cross-company/agent/task links, cycles, and forged attribution.
- Full local `pnpm -r typecheck` and `pnpm build` passed on the final
commit (`d107c26df`). [Latest-head
CI](https://github.com/paperclipai/paperclip/actions/runs/36815589542)
passed: 54 successful checks, two expected skips, including all eight
browser-test shards. Greptile is 5/5 on this exact commit with no
unresolved threads. Local tests were targeted; the full test suite ran
through CI’s test matrix.
- The revised HTTP suite passed all 13 tests; database authorization
tests passed all 11, including legacy compatibility and late watchdog
settlement; the backlog route contract passed all 3 tests. Another 102
tests covering durable chat admission, wake queues, and Cursor execution
passed.
- All 90 interaction-service tests passed with both create calls
deliberately held until their optimistic reads complete, forcing
duplicate-key recovery. That forced race failed before switching to the
shared wrapped-error helper.
- Previous staging proof covered owner chat and projectless task
persistence. The simplified revision has not been redeployed; that
earlier proof is not claimed for the new implementation.

## Risks

- This is an authorization change: only the live run's exact task
qualifies, and normal responsible-user restrictions still apply.
- Existing request and retry records are authoritative. Merely naming a
responsible/originating user or an external connector sender does not
qualify.
- Reassignment invalidates existing human request records
transactionally. A cancelled run or request cannot regain authority when
the task is assigned back.
- Ordinary task exceptions require server-owned origin or the legacy
board assignment source/reason/actor combination. Existing owner chats
use conversation identity.

## Model Used

OpenAI GPT-6 in Codex, with reasoning, repository tools, code execution,
and browser testing. 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-01 09:45:18 -05:00
467125fafb feat(connections): one-screen connector setup with stated defaults (#14811)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - Agents use Connections (the Apps catalog) to act in services like
Notion, GitHub, Google Workspace and Railway
> - Each connector asked the user to answer setup questions before it
went to the provider. Most of the questions already had the correct
answer selected
> - ROADMAP.md lists "simpler setup" for Apps and Connections as ongoing
work. This change continues that work
> - This pull request removes the questions that Paperclip can answer
itself. It states the defaults in one line and moves the choices behind
"Change" and onto the Permissions tab
> - The benefit is that most connectors take one click in Paperclip and
then the provider's own consent screen

## Linked Issues or Issue Description

No public issue exists. This is the description, from the enhancement
template.

**What existing behavior does this improve?**
The setup flow for tool connectors in the Apps catalog.

**Subsystem affected**
Apps and Connections: `ui/src/features/connections`,
`ui/src/pages/apps`, the `packages/shared` app definitions, and the
OAuth routes in `server/src/routes/tool-access.ts`.

**Current behavior**
Every connector opened with an Access step. The step asked who can use
the connection and which agents get it, and both answers were already
selected. 18 connectors also asked "How do you want to connect?" when
Paperclip could rank the methods. The Google apps and Postman also asked
"What should Paperclip be able to do?" before sign-in. The four gateway
connectors (Zapier, Arcade, Composio, Executor) used a separate two-step
wizard. Asana was pinned to a customer-owned OAuth app, so the user had
to register an app in Asana's developer console. The "Set all" control
on the Permissions tab changed only one action. After the user approved
access, Railway's consent page showed "you can close this window" and
did not return to Paperclip.

**Proposed behavior**
One screen per connector, with one primary button. The screen states the
defaults in one sentence, for example "Connects for everyone in your
organization, available to all agents". A "Change" link opens one
Advanced panel. When the provider's metadata allows dynamic client
registration, Paperclip registers a client itself. Connecting lands on
the Permissions tab. On that tab, "Set all" changes every action in the
group.

**Reason and benefit**
The user makes fewer decisions before the connection exists. Most
choices are easier to make after the connection, on the Permissions tab,
where a change has an immediate effect.

**Breaking changes**
None. No schema or API change. Existing connections keep their settings.

## What Changed

- **No Access step.** `ConnectionSetupFlow` no longer has the Access
step. The flow shows the resolved default above the primary button and
on the completion screen. The access controls moved into one Advanced
panel. The panel opens automatically only when a setting in it is
required.
- **A default method for every app.** The flow always picks the ranked
default method. Alternate methods are in the Advanced panel. The Google
and Postman capability choice is not asked before sign-in. The
write-capable method is the default.
- **Gateway connectors.** `RemoteMcpProductionSetup` (Zapier, Arcade,
Composio, Executor) no longer has its own Access step. Its commit path
and the main commit path use one helper, `askFirstCatalogEntryIdsFor`,
for server-suggested defaults.
- **Dynamic registration from live metadata.**
`canRegisterOAuthClientDynamically` now allows registration when the
provider advertises a registration endpoint, even if the catalog entry
lists only customer-owned clients. The Asana and Linear definitions and
catalog text match live probes. Asana issues clients for loopback
callbacks only, so a hosted deployment still needs an Asana app.
- **Connection setup states.** New
`packages/shared/src/connection-setup-state.ts` sorts each method into
`instant`, `authorize`, `paste` or `register`. The gallery card verb
("Connect" or "Add key") comes from this resolver and the instance's
ownership availability.
- **Generic MCP.** The generic path no longer asks "Does it need a key?"
first. A credential challenge from the server shows the key field.
- **Permissions tab.** Each action row shows its risk level. Each group
has a "Set all" control. The control sends one change for the whole
group. Before, each row's save started from the same render, so the
saves overwrote each other. The Zapier/Arcade/Composio/Executor setup
screen had the same defect.
- **OAuth callback interstitial.** A cross-site browser navigation to
`/api/tools/oauth/callback` gets a small same-origin "Finishing your
connection…" page. That page repeats the request, and the repeat does
the code exchange. Railway's consent page replaces itself after about
two seconds, and the code exchange plus tool discovery takes longer than
that. The interstitial uses only a meta refresh, because the OAuth code
is single-use. Requests without `Sec-Fetch-Site: cross-site` take the
old path.
- **Linear registers through its MCP server.** Linear pins the console
endpoints at `linear.app`. Pinned endpoints now replace discovery only
when the method cannot register, or when the connection has an
operator-entered client. So a Linear connection now finds the
registration endpoint at `mcp.linear.app`.
- **Own-OAuth-app recovery stays on the one-click screen.** When the
method also accepts a customer-owned client, the client fields are in
the Advanced panel. The panel opens after a failed sign-in. "Try again"
resumes the draft with the operator's client.
- **E2E specs** follow the one-screen flow. The Access-step clicks are
removed, the specs open **Change** before they pick agents, and they
expect GitHub's **Add key** verb.
- **Default permissions do not change.** New connections still allow
every action. The user can set actions to Ask first or Off on the
Permissions tab.

## Verification

- `cd ui && npx vitest run src/pages/apps src/features/connections
--no-file-parallelism`
- `cd packages/shared && npx vitest run src/app-definitions.test.ts
src/connection-setup-state.test.ts`
- `cd server && npx vitest run src/__tests__/tool-access-service.test.ts
src/__tests__/remote-mcp-connectors.test.ts`
- `pnpm check:token-gates`
- New tests:
- `PermissionsPanel.group.test.tsx` checks that "Set all" sends one
change for the whole group. It fails on the old code.
  - `action-permissions.test.ts` checks the group update.
  - `connection-setup-state.test.ts` checks the four setup states.
- A server test checks that a cross-site callback gets the interstitial
and does not use the OAuth state, and that the same-origin repeat
completes the connection.
- Manual check on a hosted staging deployment. GitHub, Google Drive,
Composio, Notion, PostHog and Railway each connected from one screen and
returned to the Permissions tab. On Railway, "Set all" changed all 65
write actions, and the change remained after a reload.
- Visual changes: snapshot baselines are intentionally not updated. See
the `doc/design/DECISION-SHEET.md` entry "Per-change snapshot
verification demoted to dormant (Jul 13 2026)".

## Risks

- **Fewer confirmation clicks.** Organization-wide access is the
default, and the user does not confirm it on a separate step. This was
already the preselected answer. The flow shows the default before the
user clicks and again after the connection.
- **Google write scope.** Google apps now request the write-capable
scope by default. A narrower scope needs a new sign-in.
- **Dynamic registration from live metadata.** A provider can advertise
registration and then reject a redirect URI. Asana rejects hosted
callbacks, for example. In that case registration fails, and the
customer-owned client path remains available for recovery.
- **Callback interstitial.** The OAuth callback adds one same-origin
step for cross-site browser navigations. Browsers without `Sec-Fetch-*`
headers use the old direct path.
- Chat and bot connectors (Discord, Telegram, Microsoft Teams, iMessage)
do not change.

> 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 (Anthropic), model ID `claude-opus-5-5`, used through
Claude Code with tool use (shell, file editing, browser automation) and
extended thinking. It wrote the code, the tests and this description. A
human product owner directed the work and tested it by hand.

## 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: scotttong <squadbot000@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 23:13:47 -07:00
Devin FoleyandPaperclip 4b9a6000f7 Add bounded evidence for directory lock timeouts (#14787)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Agent files use directory locks during collection and cleanup.
> - A lock timeout can fail finalization after the model turn completes.
> - The timeout currently identifies no owner state or waiting
operation.
> - This pull request adds bounded evidence to the existing run failure
report.
> - Operators can distinguish a known local holder from a possible old
lock without changing lock safety.

## Linked Issues or Issue Description

**What happened?**

A directory lock timeout does not distinguish active local work from an
owner record left by an earlier process. The stored execution stage can
also precede the cleanup operation that failed.

**Expected behavior**

The failure report should identify the waiting operation and expose
bounded ownership clues. It must preserve the timeout and keep unknown
ownership protected.

**Steps to reproduce**

Hold a directory merge lock while a second caller reaches its
acquisition deadline. The regression tests exercise a live holder and an
older owner record with a live PID.

Related: #9667 proposes stale-lock recovery under a single-server
assumption. This change only adds evidence and does not adopt that
assumption. #14575 and #14665 add other run failure diagnostics.

## What Changed

- Record lock owner state, capped age and wait duration, same-process
and process-age comparisons, and whether this module holds the lock.
- Label agent-directory release, collection, checkpoint, and warm
handoff timeouts with a fixed operation code.
- Validate each field before the existing event-local Sentry report
accepts it. Exclude owner records, PIDs, paths, and absolute timestamps.
- Limit the extra diagnostic owner read to 100 ms with best-effort
abort; malformed JSON is `invalid` and unreadable owner records remain
`unknown`.
- Document the diagnostic limits and verify that contenders never
reclaim protected locks.

## Verification

- Focused lock, diagnostic, real Sentry SDK, and database-backed
agent-directory tests: 126 passed, including stalled-read and
malformed/missing/unreadable-owner regression coverage.
- Final revision `0691613dcc`: all 54 reported checks successful, with
two intentionally skipped Storybook checks. Greptile: 5/5, zero
unresolved review threads; no merge conflicts.
- `pnpm -r typecheck`: passed.
- `pnpm build`: passed.
- `pnpm test:run`: complete suite coverage ran with the existing
repository shard flags: four general-server shards, four serialized
shards, two general-workspaces-a shards, and general-workspaces-b. The
full run is not green because of the base failures below.
- The broad run found 13 failures in the unchanged macOS skill-cache
tests. All 13 reproduce on the clean base revision. Open PR #14290
covers that existing failure.
- Two unchanged CLI archive tests hit their five-second limits during
the broad run; all 17 tests in that file pass on recheck. A CLI auth
socket error also cleared on recheck (19 tests), and its full serialized
shard passed on rerun.

## Risks

This is a diagnostic change, not a stale-lock fix. Owner observations
can race with release. Wall-clock shifts can affect the age comparison.
A local-holder flag covers only this module instance. None of these
fields authorizes reclamation or proves a file save. Lock acquisition,
release, retries, task status, and recovery guards retain their current
behavior. No schema change or deployment action is required.

## Model Used

OpenAI Codex, based on GPT-6, with code execution and repository tools.
The exact model build and context window were not exposed to this agent.

## 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 (focused checks pass;
existing base failures 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-09-30 18:35:12 -07:00
DottaandPaperclip f7e36ba3e2 fix: isolate repository-free low-trust tasks in private directories (#14766)
## Thinking Path

> - Paperclip manages work by agents within company boundaries.
> - Email tasks can run under the low-trust review preset.
> - These tasks must use an isolated workspace and a sandbox.
> - The default workspace strategy assumed that the project had a Git
repository.
> - A project without a configured workspace failed before the agent
could start.
> - This change gives each such task a private directory and keeps the
sandbox requirement.

## Linked Issues or Issue Description

**What happened?**
An inbound email assigned to a low-trust agent failed with
`git_worktree_base_not_git_checkout` when its boundary project had no
configured workspace. Setup had accepted the project and sandbox.

**Expected behavior**
The agent can process email without a repository. Its workspace stays
isolated from other tasks and the shared agent home.

**Steps to reproduce**
1. Select a low-trust agent with an active sandbox and a project
boundary.
2. Leave the project without a configured workspace.
3. Receive an email through AgentMail.
4. Observe that startup fails before provider work starts.

**Paperclip version or commit**
Reproduced against `5edf55d73`.

**Deployment mode**
Hosted staging with sandbox execution.

Related: #13256 added email tasks. #13636 fixed default isolation for
projects without workspaces; the explicit isolation used by low-trust
tasks still needed this path.

## What Changed

- Select private task directories for low-trust sandbox tasks with no
configured workspace or explicit workspace strategy.
- Keep each directory scoped to its company and task. Retain files
across turns and reassignment and reject symlink paths and mismatched
workspace reuse.
- Preserve Git validation for configured workspaces and explicit
strategies, plus the existing authorization and remote gates for
referenced projects.
- Add a startup regression and directory isolation tests. Document the
supported repository-free path.

## Verification

- The startup regression failed before the fix with the same Git
validation error.
- 260 targeted email, workspace policy, heartbeat, referenced-project
and directory tests pass.
- Full `pnpm -r typecheck` and `pnpm build` pass on the latest commit.
- All CI checks, including the complete sharded test suite and canary
dry run, pass on `b4ccd9802b09b2e95499df72d48b4a3906b8c328`.
- The final commit also passes the same server shard locally: 60 files,
1,024 passed / 6 skipped tests. The earlier all-groups local run was
interrupted during follow-up edits; complete-suite verification comes
from CI on the final commit.
- Deployed the reviewed commit to staging and independently verified the
full serving SHA. Two real Codex runs in Daytona succeeded and finalized
the same private company/task workspace. The first wrote a 35-byte
marker; the second read the existing file without modifying it and
returned the independently verified SHA-256
`ce3bbeb44d07ca6822826d3a5945752a38d30b356d10829f3159a191e5aa92a6`.
- Live runtime caveat: Codex reported a nested `bwrap` loopback
permission error and used its configured escalated execution inside
Daytona. The outer Daytona sandbox remained active for both runs.
- The startup regression uses a real database, production trust checks,
workspace persistence, sandbox lease acquisition and realization, and a
fake provider. It checks reassignment and allows only an authorized
referenced project.
- The transfer regression runs production archive/sync-back/merge code
against distinct filesystem roots: create output in one sandbox, restore
it, then read and update it in a fresh sandbox. The provider I/O is
emulated; live staging verification is separate.

## Risks

- The new default applies only to low-trust sandbox tasks without
workspace configuration. Standard agents and explicit Git strategies
keep their existing behavior.
- Task directories retain work across turns and consume instance
storage. The change does not migrate or copy existing shared files.
- No database migration or credential changes are required.

## Model Used

OpenAI GPT-6 through Codex, with reasoning, repository inspection, code
execution, and browser tools. The exact runtime model revision 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-09-30 18:06:07 -05:00
Devin FoleyandPaperclip 3bbb8d0f69 Add bounded AgentMail failure diagnostics (#14768)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - AgentMail connections create inboxes and handle email tasks.
> - A failed provider request currently records only its HTTP status.
> - The same 403 can mean a permission denial, a resource limit, or
another provider restriction.
> - This pull request records a fixed operation name and a documented,
allowlisted error code.
> - Operators can distinguish these failures without exposing provider
payloads or changing retry behavior.

## Linked Issues or Issue Description

**What happened?**

An AgentMail inbox creation failure reports only `AgentMail request
failed (403)`. The response body is deliberately excluded because it can
contain private mail or credentials. That also discards the provider
code needed to identify the cause.

**Expected behavior**

Keep the HTTP failure visible with a fixed operation name and a safe
provider code. Never copy arbitrary error text, resource identifiers,
suggested fixes, or URLs into diagnostics.

**Steps to reproduce**

1. Make an inbox creation request through `agentmailApi` with a fake
provider returning HTTP 403 and `code: "missing_permission"`.
2. Observe that the old error lacks the operation and provider code.
3. With this change, verify the error includes `operation=create_inbox,
code=missing_permission`, preserves status 403, and excludes all other
response fields.

Related work: #13256 introduced the AgentMail connection. The provider
documents stable codes in its [error
reference](https://docs.agentmail.to/errors).

## What Changed

- Add a fixed method/route-to-operation map and an allowlist of
documented provider codes.
- Read at most 8 KiB for diagnostics, with a one-second deadline. Cancel
unread bodies and preserve the HTTP error if reading or parsing fails.
- Keep the existing error prefix, status, retry delay, and failure
handling.
- Add regression coverage and document the diagnostic limits.

## Verification

- `pnpm exec vitest run server/src/__tests__/agentmail-api.test.ts` — 44
tests passed.
- `pnpm build` — passed.
- `pnpm -r typecheck` — passed before the review correction. Final `pnpm
--filter @paperclipai/server exec tsc --noEmit` also passed.
- Full local `pnpm test:run` did not finish successfully; three
company-skills-service failures were observed outside the changed
module. The final-head CI server suites passed. The remaining
workspaces-b CI retry covers an unrelated HTTP/2 port collision.
- The diff passed a scan for configured secrets, private deployment
references, and non-fixture email addresses.

## Risks

- A failed request can now wait up to one extra second while reading its
diagnostic code.
- New, missing, malformed, or oversized provider codes report `unknown`.
A future provider code needs an explicit allowlist update.
- This is a diagnostics change. It does not establish or repair the
cause of an existing provider denial.
- No schema, credential policy, or retry behavior changes.

## Model Used

OpenAI Codex, GPT-6, with reasoning, tool use, and code execution. The
exact served 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 at 20853e31abacf53a32f1a63467ee208a719bbf00; the
locked-body finding is fixed and its thread resolved
- [x] I will address all Greptile and reviewer comments before
requesting merge


Final verification (September 30): all final-head GitHub checks pass at
`20853e31abacf53a32f1a63467ee208a719bbf00`, including the targeted
workspaces-b rerun after the unrelated EADDRINUSE failure. Greptile
scored 5/5 on this head and no review threads remain unresolved. The
branch is mergeable. The local full-suite run did not yield a passing
completion; CI completed successfully across all suites. This public PR
remains open for maintainer merge.

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-09-30 15:29:15 -07:00
DottaandPaperclip e2908fff5c fix: enforce terminal outcomes during recovered sandbox cleanup (#14767)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Native runners can keep a reusable sandbox warm after successful
turns.
> - Failed turns must stop their sandbox before a later retry resumes
it.
> - Workspace recovery can release a lease outside the executor's normal
teardown.
> - Successful file copy-back can then retain a sandbox even when its
run failed.
> - This pull request checks the durable run outcome at the shared
release boundary.
> - Ordinary teardown and recovery now apply the same retention rule.

## Linked Issues or Issue Description

**What happened?**

A real Daytona verification on `5edf55d73` produced a failed native
turn. The runner process exited, but workspace recovery retained the
sandbox without stopping it. The recovery callback used successful
workspace copy-back to select warm retention. It bypassed the
terminal-state check in normal heartbeat teardown.

**Expected behavior**

Keep a sandbox running only after a successful run. Failed, cancelled,
timed-out, and interrupted runs must convert requested warm retention to
stop-and-retain. Preserve the existing ownership hold before release.

**Steps to reproduce**

1. Persist a terminal failed native run whose workspace copy-back
succeeds.
2. Release its environment lease from the recovery path with a stored
`keep_running` disposition.
3. Observe that the provider receives `keep_running` on the base commit.
4. With this fix, the provider receives `stop_and_retain` and the lease
status follows the durable run outcome.

**Paperclip version or commit**

Base: `5edf55d7350c7f08c9dd132c7e0f1421fa0bf2fb`.

**Deployment mode**

Native runner with a reusable Daytona sandbox.

Related: #14747 retires unsuccessful warm runner sessions. This change
closes the separate recovery lease-release path. Related search found no
duplicate fix.

## What Changed

- Read the durable run status at the shared lease-release boundary.
- Apply the existing terminal-outcome retention rule before calling the
environment runtime.
- Use that same durable status for the lease-state mapping.
- Add five database-backed regressions for four unsuccessful outcomes
and successful warm retention.
- Document the recovery rule.

## Verification

- Before the fix: the four unsuccessful-outcome regressions fail; the
successful case passes.
- After the fix: 163 tests pass across the lease-release, native
lifecycle, and explicit continuation suites.
- Repository typecheck and build pass.
- `pnpm test:run` encountered the existing local
`native-session-resume.test.ts:1125` assertion failure; a focused rerun
reproduced the same failure. This was also recorded before this
follow-up with the unmodified base executor. The full command was
stopped after that confirmation, so later local groups were not
completed.
- All 56 latest-head checks are successful or intentionally skipped (54
passed, 2 skipped), including the complete CI test groups and browser
E2E suite. Greptile is 5/5 on `e7da3b3ad`, with no unresolved review
comments.
- Deployed exact PR head `e7da3b3adbf7a13642c0e56f5b0f0c4666adf358` to
the staging workspace and independently verified the serving commit. A
real failed native turn persisted `keep_running` and completed workspace
finalization, reproducing the recovery-path conditions; Paperclip
automatically issued stop-and-retain, and an independent Daytona read
confirmed `stopped`. No manual stop was used.
- Retried that failed run through the public API after correcting its
temporary API-key credential. The same stopped sandbox resumed
successfully. Three successful turns retained one live runner PID/start
time and the same native, runner, and provider sessions.
- Verified exact canonical note contents, deletion persistence, and an
unchanged 8 MiB binary after every turn. Subsequent checkpoints
copied/hashed only 58 and 87 bytes. After sandbox deletion, canonical
files still matched. Temporary secrets were removed and
agent/configuration policy restored.
- Live acceptance used temporary API-key authentication. The separate
managed-subscription authentication issue and browser Retry control were
not tested by this campaign.

## Risks

- Recovery callers can no longer use stale success status to retain a
failed run's sandbox.
- The existing native ownership hold still blocks release while
ownership is unresolved.
- Successful warm turns and explicit destroy dispositions keep their
existing behavior.
- No database migration, API contract, dependency, or UI change is
included.

## Model Used

OpenAI Codex, GPT-6, with reasoning, tool use, code execution, and test
analysis. The exact served 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-09-30 17:20:25 -05:00
DottaandPaperclip 33f2b3a159 fix: separate GitHub tools and code review bot connections (#14750)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - The Connectors catalog lets people give agents tools or connect
agents to conversations.
> - GitHub put these two uses behind one card and an extra choice.
> - People should choose the connection they need from the catalog.
> - This pull request keeps GitHub for tools and adds GitHub Code Review
Bot as a separate card.
> - Each card opens its setup directly. Both use the existing connection
code.

## Linked Issues or Issue Description

**What existing behavior does this improve?**

GitHub connector discovery and setup.

**Current behavior**

With chat connectors enabled, GitHub opens a menu that asks whether to
use tools or create a bot. Saved tools and bots share the same catalog
entry.

**Proposed behavior**

GitHub opens tool account access. GitHub Code Review Bot opens agent
selection. Saved bots and drafts appear under the bot card.
Chat-disabled instances show only GitHub tools.

**Reason and benefit**

The catalog names the two uses and removes an extra setup choice. The
bot keeps the existing GitHub provider, credentials, endpoint IDs, setup
steps, and runtime.

**Additional context**

Related work: https://github.com/paperclipai/paperclip/pull/12843 and
https://github.com/paperclipai/paperclip/pull/14594 established GitHub
account identity. This change preserves that tool flow. No duplicate
catalog split was found.

## What Changed

- Split the generated app definitions into GitHub tools and GitHub Code
Review Bot. Reuse the existing GitHub logo and channel method.
- Open bot setup directly, including old resume and reconnect links.
- Put existing bot endpoints and drafts under the bot card. Hide
duplicate internal chat applications.
- Keep pasted GitHub URLs mapped to the tool connection.
- Add seven Storybook states for the catalog, saved connections,
disabled chat, both setup paths, mobile, and light mode.
- Fix narrow-screen bot rows so the label cannot overlap status and
setup actions.
- Update catalog, route, browser, and API tests, plus the GitHub
connector guide.

## Verification

- [Hosted
Storybook](https://d1p6rlowie26tp.cloudfront.net/storybook/branches/codex~2Fgithub-review-connection/?path=/story/connections-github-and-code-review-bot--catalog):
seven states built from this branch. The deployment passed its
public-file verification.
- All GitHub checks pass on `d13a2cd53561645bb2a15c6f8e75a61a936d6459`.
Two optional Storybook jobs skip under their normal trigger rules; the
manual Storybook deployment passes. The branch has no merge conflicts.
- Greptile: 5/5 on the current head, with no review comments or
unresolved threads.
- `pnpm -r typecheck`, `pnpm build`, `pnpm check:token-gates`, and `pnpm
build-storybook` passed. The final Storybook fixture also passed UI
typecheck and the hosted build.
- Targeted catalog, URL matching, routing, grouping, brand, and chat UI
contract tests passed.
- GitHub provider browser tests: 2 passed. These cover direct tool setup
and the bot setup and management lifecycle with provider responses
mocked.
- Embedded-browser test on an isolated local instance: opened both
cards, selected an agent, saved a bot draft, and resumed the same
endpoint under the bot card after a reload.
- Storybook Tool Setup and Bot Setup assertions pass in the published
preview. Chat Disabled assertions pass locally. Inspected mobile and
light mode, including the draft-row layout and official GitHub marks.
- Local full-suite limitation: `pnpm test:run` was not clean. A
cross-company route assertion failed in the aggregate run and passed in
isolation; a workspace-runtime test reached its 30-second hook timeout.
Some isolated database reruns skipped when the embedded-PostgreSQL
availability probe failed. The local aggregate was stopped after CI
completed. The corresponding full CI suites pass all 360 tool-access
tests and all 162 workspace-runtime tests.
- No live GitHub authorization or installation was performed. The
isolated instance correctly stopped at the cloud enrollment or public
HTTPS prerequisites.

## Risks

- Low scope: catalog presentation and routing change. There is no
database migration or provider credential change.
- Existing GitHub bot URLs now open bot setup directly. The tool route
remains `/apps/connect?source=github`.
- The bot remains behind the existing chat-connectors feature flag.
Existing endpoints retain `provider: github`.
- Channel applications are represented by endpoint rows. Regression
tests cover legacy bot applications, tools, active bots, and drafts
together.

## Model Used

OpenAI GPT-6 through Codex, with reasoning, code execution, and
embedded-browser tools. The exact deployed model ID, context window
size, and reasoning setting are not exposed to 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-09-30 17:15:02 -05:00
DottaandPaperclip 018993140f feat: let agents name prompt-only tasks (#14761)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Users create tasks with a title and a description.
> - A required title adds work when the prompt already explains the
request.
> - An agent can name the task once it reads that request.
> - This pull request accepts prompt-only tasks and starts them with a
short prompt slice.
> - A scoped title tool lets the assigned agent replace that slice early
without changing execution state.
> - A live browser eval checks the real agent call, saved title, audit
entry, and preservation of user titles.

## Linked Issues or Issue Description

**Subsystem affected**

Cross-cutting: task creation, shared contracts, database, server, runner
tools, and board UI.

**Problem or motivation**

Users must currently write a title before they can submit a detailed
task prompt. The agent has enough context to write a useful title
itself.

**Proposed solution**

Make the title optional when a description is present. Save the first
120 characters of the normalized prompt as a provisional title. Ask the
assigned agent to call `set_task_title` early. Use an atomic
provisional-title guard to preserve titles supplied or edited by users.
Keep explicit titles supported.

Related: #14543 and #14556 concern empty-title submission. This change
intentionally enables that submission when a prompt is present, instead
of requiring a title.

## What Changed

- Add the `titleNeedsGeneration` field with an idempotent migration.
Keep existing titles unchanged.
- Add `PUT /api/issues/:id/title` and the native and legacy
`set_task_title` tool. Enforce company access, active-run ownership,
shared, bounded retry receipts across native/HTTP calls, and
transactional audit logging. Refresh external-object links after commit,
with the same feature gate and plugin detectors as ordinary title edits.
- Add early naming guidance in Standard, Ask, and Plan task context.
Preserve the description, status, and assignment.
- Allow prompt-only root and child task creation, plus draft restoration
in the New Task dialog. Keep user titles supported.
- Add an opt-in Product E2E suite for prompt-only Standard and Ask
tasks, plus an explicit-title control. It checks actual provider calls
within the first five tools, persisted state, audit attribution, and the
reloaded UI.
- Preserve a closed vocabulary of API key maintenance phrases in
declared prose while rejecting opaque credential suffixes. Add one
bounded naming retry after wording is rejected, without treating the
rejected call as a saved title.
- Repair the native cleanup receipt check exposed during full
verification: accept matching input digests, retain legacy input checks,
and reject conflicting receipts.

## Verification

- Live Product E2E on `f43478473800e3a46b85c5ee79677efdb15108e7`: **3/3
passed** with native Codex `gpt-5.4-mini`, first attempts only,
automatic retries disabled. Standard and Ask each saved “Rotate expired
API key” on their first tool call, with matching persisted state and a
single same-run audit entry. The explicit-title control retained its
user title with zero title writes. All three verified the reloaded
browser UI.
- Campaign: `local-2026-09-30T21-30-11-021Z`. Earlier failed campaigns
are retained separately; they exposed credential-prose handling and
prompted the naming recovery fix. No failed result was regraded or
deleted.
- Reproduce with `pnpm test:e2e:runner -- --id
task-titles.runner-codex-mini.local.prompt-title-standard --id
task-titles.runner-codex-mini.local.prompt-title-ask --id
task-titles.runner-codex-mini.local.preserve-explicit-title
--max-automatic-retries 0` and an authorized provider key.
- Full `pnpm -r typecheck` and `pnpm build` passed on the latest commit.
The runner build used the configured external eval source tree.
- Product E2E unit suite: **61 files, 818 tests passed**; E2E typecheck
and UI token gates passed.
- Title API/native regressions cover prompt-only and explicit child
creation, user edits, ownership/company isolation, external reference
refresh, cross-surface retry replay, and the 64-key limit without
receipt eviction. All passed. Prompt-context coverage: **44 tests
passed**.
- Rust credential regressions: **35 tests passed**, including benign
maintenance qualifiers and opaque credential rejection in every declared
prose field. Catalog/report reconciliation: **28 tests passed**. Native
recovery: **560 tests passed**.
- Broad local `pnpm test:run`: **14,555 tests passed** in the general
server group; two suites failed to initialize embedded PostgreSQL and
the existing 40,000-file Git streaming stress test exceeded its
300-second macOS timeout. All three suites then passed in isolation (**5
tests passed**) without code or timeout changes. The original full local
command exited nonzero and is not being represented as a clean full run.
- Latest-head GitHub checks are green: **53 passed, 4 skipped, zero
failed or pending**, including all test shards and the canary packaging
dry run. Greptile reviewed the same commit at **5/5**, with zero
unresolved review threads.

## Risks

- The additive database field must reach the server and UI together. The
migration uses `IF NOT EXISTS` and defaults existing tasks to a final
title.
- Title generation depends on the assigned agent running. Tasks without
a run keep their provisional title.
- Live qualification covers the native Codex path in Standard and Ask
modes. API/legacy and Plan behavior have deterministic coverage.
- The credential-prose exception validates the entire suffix against a
closed maintenance vocabulary. Unknown suffixes, assignments, quoted
values, credential prefixes, and diagnostics retain strict checks.

## Model Used

OpenAI Codex, based on GPT-6, with reasoning, tool use, and code
execution. The exact deployment ID and context window are not exposed in
this session. The live eval uses the native Codex `gpt-5.4-mini`
profile.

## 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-09-30 16:48:24 -05:00
Devin FoleyandPaperclip 0ea6b10967 Record ACP activity and workspace restore failure evidence (#14665)
## Thinking Path

Paperclip records terminal run failures for operators. A timeout's own
log and cleanup output update the run's last-output timestamp, so that
timestamp can make a long-silent provider look active. Snapshot runtime
activity before finalization and include the saved workspace restore
classification to make the next failure actionable without copying tool
payloads.

## Linked Issues or Issue Description

**What existing behavior does this improve?**
Terminal run diagnostics in the existing opt-in Sentry integration.

**Current behavior**
Reports cannot distinguish runtime events from finalization logging and
omit the already-persisted workspace restore code. A later successful
run also does not establish that earlier workspace files were restored.

**Proposed behavior**
Record runtime-event age/count and pending-tool inventory at
finalization, before status reads and cleanup. Forward only finite
counts, a completeness boolean, and known restore codes through the
existing reporter.

**Reason and benefit**
Operators can distinguish a silent turn with unfinished tools from
recent runtime activity and see restore failures without retrieving
private run output. Neither signal certifies productive work or
successful recovery.

**Breaking changes**
None. Error grouping, execution deadlines, cancellation, recovery
policy, and the Sentry opt-in remain unchanged.

Related diagnostic work: #14573, #14575, #14639.

## What Changed

- Snapshot ACP activity before success/failure finalization, including
thrown relay failures.
- Forward bounded numeric/boolean evidence and shared workspace restore
codes; exclude commands, tool IDs, paths, and arbitrary result data.
- Document limitations and test silence, empty streams, timeout, cleanup
delay, incomplete tool inventory, and privacy.

## Verification

- `pnpm -r typecheck` passed after the final implementation.
- Changed suites: 252 tests passed; all 29 database reporter tests
subsequently passed after restoring the embedded-Postgres package
library symlinks. The migration test also passed (30 database cases
total).
- `pnpm build` passed during implementation. Final head
`fe78dba6f592b1abccac7cdbf341bd2e0b0d30cb` passed all 53 CI checks,
including complete test coverage, typecheck, build, and browser/runner
gates; two unrelated checks intentionally skipped.
- Full local test attempts initially hit missing embedded-Postgres
library symlinks; the dependency setup was repaired and database tests
passed. Duplicate local full-suite runs were stopped after full CI
completed. This PR does not claim a completed full local suite.
- Review regression: completed, failed, and cancelled tools are excluded
from the pending count; focused activity/timeout tests and adapter-utils
typecheck passed.
- Reviewed the diff for secrets, customer data, and internal references.

## Risks

Low risk, diagnostic-only. The existing tool inventory is incomplete for
some runtime events, so the report carries its completeness flag. Event
age is measured at finalization and does not prove useful work or
identify the underlying provider failure. No schema changes or new
capture gate.

## Model Used

OpenAI GPT-6 via Codex, with repository inspection, code execution, and
tests. Exact model build identifier is not exposed by this session.

## Checklist

- [x] Thinking path and model are specified
- [x] Checked ROADMAP.md; this is a maintenance correction, not planned
feature work
- [x] Searched for duplicate and related PRs
- [x] Described the issue using the enhancement template
- [x] No internal issue references, customer data, or private instance
links
- [x] Descriptive branch name
- [x] Focused regression tests pass
- [x] Added tests and updated documentation
- [x] Risks documented
- [x] Required validation and CI gates are green (full suite validated
in CI; local scope documented above)
- [x] Greptile is 5/5 with no unresolved findings
- [x] I will address review comments before requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-09-30 14:27:53 -07:00
DottaandPaperclip 5edf55d735 fix: retire failed warm sessions before sandbox stop (#14747)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Native runner sessions can stay warm between turns in a reusable
sandbox.
> - Heartbeat stops that sandbox when a turn fails or is cancelled.
> - The native executor treated every returned terminal result as a
successful warm release.
> - A failed session could therefore retain a transport for a stopped
sandbox.
> - This pull request retires unsuccessful sessions before heartbeat
stops their sandbox.
> - A retry can start without inheriting that stale transport.
Successful turns stay warm.

## Linked Issues or Issue Description

**What happened?**

A structured failed or cancelled terminal result did not throw. The host
kept its native session in the warm cache even though heartbeat stopped
the reusable sandbox. Later session retirement could use the stopped
provider transport and reject the retry.

**Expected behavior**

Retire the unsuccessful session and collect its managed files before
returning to heartbeat. Keep successful sessions warm.

**Steps to reproduce**

1. Run a native session with a warm lifecycle and a reusable sandbox.
2. Return a structured failed or cancelled result from the provider.
3. Stop the sandbox after the executor returns.
4. Retry with a changed native session identity.
5. Verify that the previous session was closed before step 3 and is not
closed again during retry.

**Paperclip version or commit**

Developed from `b54b2dc35`, the current `origin/master` at
implementation time.

**Deployment mode**

Native runner with a reusable Daytona sandbox. The same warm-session
release path also serves local providers.

Related work: #14735 added incremental managed-file checkpoints for warm
turns. #14734 preserves tool outcomes during shutdown. This change fixes
the host's handling of unsuccessful terminal results.

## What Changed

- Retain a warm session only when its terminal run state is `succeeded`.
- Use the existing failed-session retirement path for structured
failures and cancellations.
- Preserve the existing checkpoint-before-retirement path, including
when provider shutdown fails. Collect stopped files after successful
shutdown, including edits made during shutdown.
- Retire the warm owner if the checkpoint or its receipt callback
rejects, then propagate the initiating error.
- Add ten regression cases for failure and cancellation, with and
without managed files. They check cleanup order, cache removal, retry
with a new session identity, and edits preserved when close rejects.
- Document the lifecycle rule.

## Verification

- The failed and cancelled managed-file regressions fail on unpatched
master because the provider is not closed.
- All 516 native executor tests pass, including ten new regressions.
- `pnpm -r typecheck` and `pnpm build` pass. `pnpm test:run` finished
its general-server group with 14,537 passed, 75 skipped, and one
existing failure in `native-session-resume.test.ts`
(`retainedNativeCleanupJournalMatches`, line 1125). A separate run using
the unmodified `origin/master` executor fails the same assertion. The
command stops before later local groups; all equivalent CI groups pass
on this head.
- All 56 PR checks are successful or intentionally skipped. Greptile
reviewed this head at 5/5 with no remaining findings.
- A real Daytona public-API probe forced a Codex authentication failure,
waited for a confirmed sandbox stop, corrected the credential, and
retried successfully in the same resumed sandbox. It verified the agent
note in canonical storage and deleted the test sandbox.
- Pumpkin staging on this exact commit: forced a structured
authentication failure, confirmed sandbox stop, corrected the
credential, and retried successfully in that same sandbox. Three
successful turns kept the same live runner PID/start ticks, native
session, runner instance, and provider session. Canonical downloads
verified the note, all 8 MiB binary bytes, and deletion persistence.
Subsequent checkpoints hashed/copied only 52 and 78 bytes. After sandbox
deletion, canonical files still matched. Temporary secrets, agent
configuration, and test policy were cleaned up or restored.
- Unpatched live probes with both 5-second and 90-second retry delays
also succeeded. The unit regressions prove incorrect retention; the
original stopped-lease exception was not reproduced in those probes. The
staging recovery campaign used the public retry API after an explicit
reset of the disposable task’s already-deleted old sandbox/session. The
UI did not expose a Retry control on the inspected task or run detail
views.
- Temporary API-key authentication was used for the campaign. This
change does not repair the original managed-subscription authentication
401.

## Risks

- Failed and cancelled turns now close their provider sooner. Successful
warm-turn behavior is unchanged.
- Cleanup uses the existing failed-session path. Its existing handling
of cleanup errors is unchanged.
- No database migration, API contract change, or dependency change is
included.

## Model Used

OpenAI Codex, GPT-6, with reasoning, tool use, code execution, and test
analysis. The exact served 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 (516 relevant executor
tests; the full local suite has the independently reproduced baseline
failure 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-09-30 15:36:06 -05:00
DottaandPaperclip ad55d0a281 fix(connections): repair personal credentials and request write access (#14739)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Agents use Apps through a gateway that checks identity, company
access, and action policies.
> - Personal pasted credentials can point to company secrets. Setup can
show success while the gateway rejects every call.
> - Several OAuth methods also omit the scopes needed for their
supported write actions.
> - This pull request gives setup, health checks, and invocation the
same credential rules. Owners repair existing connections by
reconnecting.
> - New connections request reviewed permissions for their supported
actions. Read-only choices remain available under Advanced.
> - Agents can use the connections people give them, while existing
consent, identity boundaries, and action restrictions remain enforced.

## Linked Issues or Issue Description

Refs #14009 and #14008. This addresses the personal-credential defect.
The separate GitHub organization-identity selection defect is outside
this change.

Related work: #13942 fixed part of new personal-key setup. #14200
independently fixes legacy personal reconnect and protects managed-agent
profile credentials during removal. This PR covers that ownership
invariant across key and secret-URL setup, reconnect, health, discovery,
and invocation, and keeps owner reconnect as the repair path. #14059
tracks requested versus provider-asserted OAuth scopes; it remains
separate work. I searched open PRs and issues for Zapier, Airtable
scopes, connector writes, and personal credential failures.

**What happened?**

A Zapier secret URL saved through personal setup can become a company
secret referenced by a user grant. Health checks bypass the gateway's
ownership check, so the connection appears healthy but calls fail with
`grant_credential_invalid`. Custom-header paths can also receive a
duplicate `credentials.` prefix. Omitted OAuth scopes make write access
depend on provider defaults.

**Expected behavior**

Personal invocation credentials belong to the selected user. Setup,
health, and actual calls enforce the same rule. New connections request
documented permissions for supported read and write actions. Existing
tokens gain no permissions without provider consent.

**Steps to reproduce**

1. Connect Zapier or a generic secret URL with the personal identity.
2. Allow an agent to use the connection and complete setup.
3. Invoke a tool through a run-scoped gateway. The legacy layout fails
ownership validation despite successful setup.

**Paperclip version or commit**

The implementation started from
`44736c9c7c67b7b646ead9d51721db10f5b83835` and was rebased onto master
at `94e8dec56`.

**Deployment mode**

Built from source. Regression tests use isolated PostgreSQL fixtures and
controlled MCP transports.

## What Changed

- Share credential writing, ownership validation, and canonical paths
across initial setup, resume, reconnect, rotation, health, discovery,
and gateway calls. Keep OAuth client-registration secrets separate from
invocation credentials.
- Existing personal connections with company-scoped credentials require
owner reconnect with a fresh key or secret URL. Reconnect creates a
correctly owned value and updates the existing grant and declarations.
There is no automatic ownership backfill or new startup hook.
- Preserve PostgreSQL timestamp precision when reconnect checks whether
a grant changed. Previously, converting the timestamp to a JavaScript
Date could reject reconnect with a false concurrent-change error.
- Protect credentials used by other grants, connections, bindings,
managed-agent profiles, routine triggers, or secret proposals from
connection removal.
- Review all 117 tool methods, including 84 OAuth methods. Record
explicit scopes or documented provider-default exceptions with official
evidence. Add Airtable's seven scopes, Hugging Face repository/job
scopes, and other documented MCP permissions.
- Prefer available write-capable methods. Put explicit read-only choices
under Advanced. Explain pasted-key permissions and offer reconnect for
missing OAuth consent. Preserve existing grants, policies, Google
availability gates, and curated scope allowlists.
- Reconnect generic secret URLs and custom headers using their stored
credential fields. Refresh the catalog after setup, correct reconnect
feedback and error guidance, and let Cancel exit invalid setup while
Save & exit retains draft-saving behavior.
- Apply ownership checks to the new GitHub repository/skill connection
picker. Align the permission audit with the Google scope reductions
merged on master.
- Add run-scoped gateway, ownership, owner-reconnect, OAuth URL,
insufficient-scope, UI, and catalog-wide regression coverage. Update the
connector playbook and permission audit.

## Verification

Latest commit `97bc0b86e0eae0ec892e4ac44beff1a66164b20e` passes all
CI/status gates (55 completed check runs, no failures or pending checks)
and has a completed Greptile review at **5/5 with no outstanding
findings**. GitHub reports the PR as mergeable/CLEAN.

- **Embedded browser:** used the actual server and built UI from this
worktree, a fresh isolated database, and local HTTP MCP fixtures.
Completed personal bearer-key, secret-URL, and custom-header setup;
reproduced the legacy ownership failure; reconnected through the owner’s
form; and completed writes afterward. Read-back was verified for
bearer-key and secret-URL connections. Public organization-wide setup
appeared immediately in Browse without reload. Zapier URL
validation/Cancel and Google’s enrollment gate were also exercised.
- **Persistence and invocation:** verified user ownership, canonical
`credentials.authorization` / `remote.url` / `headers.X-Api-Key`
declarations, and unchanged connection/grant identity. The old company
secrets retain their ownership. Separate HTTP calls through an actual
run-scoped gateway session completed a write and read-back.
- **Backend coverage:** the final gateway suite passes all 82 cases,
including catalog Zapier and generic inline reconnect. It checks
company/user isolation, canonical declarations, same-endpoint URL
validation, fresh credentials, retained restrictions, and real gateway
read/write execution using fixture transport. A timestamp with
PostgreSQL microseconds covers the former false reconnect conflict.
- **Local checks:** 368 catalog, gateway, repository, and UI tests
passed before the final extra Zapier case; 49 GitHub skill access tests
also passed. All three Apps browser regressions pass, including
reconnect through the actual form and catalog visibility without reload.
Full `pnpm -r typecheck`, `pnpm build`, server typecheck after the final
patch, and token gates passed. Full tool-access service runs hit varying
15-second Google fixture timeouts; both affected cases and the updated
reconnect assertion pass in isolation (3 tests). The complete test
matrix passes in CI on this head.
- **Verification limits:** no live provider account was available for
Zapier/Airtable/OAuth consent or account-bound write proof. Public
metadata and local fixtures do not establish provider consent. The
original development database clone failed on a pre-existing missing
`tool_connections_transport_check` constraint; browser acceptance used a
fresh isolated database created by the normal CLI onboarding flow.

## Risks

- Existing broken personal connections stay unusable until their owner
reconnects. Health, discovery, and invocation return an actionable
ownership error; startup does not rewrite credential ownership.
- Scope changes affect new authorization requests. Providers may still
require resource selection, account roles, paid plans, or app
verification. Existing consent and action restrictions remain unchanged.
- Shared credentials are retained rather than reassigned or revoked.
Provider-default exceptions and unavailable live checks are documented
in `doc/connections/CONNECTOR-PERMISSION-AUDIT.md`.
- No new endpoint, database table, lockfile change, or CI workflow
change is included.

## Model Used

OpenAI Codex, based on GPT-6, with reasoning, code editing, shell
execution, web research, and browser tools. The exact deployment model
ID and context window were 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-09-30 14:32:34 -05:00
DottaandPaperclip cbd278dc03 fix(interactions): derive chat recipients and validate explicit users (#14742)
## Thinking Path

> - Paperclip helps people manage AI agents and their work.
> - Agents use saved questions to get human input and continue the same
task.
> - The standard question example recently told models to copy a user
ID.
> - A model can omit an identity prefix and create a question its
intended recipient cannot answer.
> - Agent Chat already knows the conversation owner, so the server can
supply that identity.
> - This pull request removes the blanket instruction and validates
explicit recipients before saving.
> - Ordinary questions stay simple, and explicit addressing remains
available for decisions that need a particular person.

## Linked Issues or Issue Description

Refs #14707, #14188. Related: #14238 handles legacy email recipients;
this change prevents invalid recipients in new cards and retains exact
ID matching.

**What happened?**

A model copied a Cloud user ID without its prefix into
`addresseeUserId`. Creation succeeded. The intended user's answer then
failed the exact recipient check.

**Expected behavior**

Ordinary chat questions use the saved conversation owner. A task may
optionally name a specific recipient. The API rejects an unknown or
unauthorized recipient before it creates a card.

**Steps to reproduce**

Create a chat question for a user whose ID is `paperclip-id:example`.
Supply `example` as the addressee. Before this change, creation accepts
the invalid recipient and the owner cannot answer. With this change,
creation returns 422. Omitting the field saves the full owner ID and
allows that owner to answer.

## What Changed

- Remove `addresseeUserId` from standard question examples and remove
the blanket requester-ID instruction.
- Derive the recipient of ordinary chat questions from the persisted
conversation owner. Reject conflicting explicit user IDs.
- Keep explicit task recipients optional. Validate supplied user IDs
with the existing board mutation policy, including company, viewer, and
Cloud restrictions.
- Preserve explicit agent routing, connector intents, confirmations,
exact recipient checks, idempotent retries, and no-login local-board
authority in local-trusted mode.
- Update the blocker grader to accept an omitted recipient and verify
the actual requester answered.
- Add database and HTTP tests for prefixed identities, denied
recipients, concurrent retries, saved answers, and response delivery.

## Verification

- Database interaction service suite: 90 tests passed, including
implicit local-board creation/answering and authenticated/Cloud denial.
- Interaction HTTP route suite: 84 tests passed.
- Affected interaction/native/connector/documentation suites: 231 tests
passed across six files after valid-user fixtures were updated.
- Resolver and interaction unit suites: 29 tests passed.
- Product E2E unit/calibration suite: 793 tests passed; Product E2E
typecheck and blocker catalog discovery passed.
- Generated API-reference and capability contract checks passed.
- `pnpm -r typecheck` and `pnpm build` passed.
- Full local `pnpm test:run` did not finish green: its initial
general-server pass had 14,416 passing assertions, one unrelated
native-resume assertion failure on macOS, and three teardowns from an
intermediate fixture cleanup fixed above. Separate broad local groups
also encountered timeout/live-port failures under host load. Local UI
(7,026), CLI (502), shared (817), and skills-catalog (20) tests passed;
the complete final-head CI matrix is the broad verification gate.
- After two CI cold-start readiness timeouts, a separate test-only
commit gives the first exposure lifecycle fixture the existing normal
30-second readiness budget. Its real HTTP, ordering, and cleanup
assertions remain intact; the targeted case and final Linux CI shard
passed. Production deadlines are unchanged.
- A separate OpenCode fixture failed twice on GitHub-hosted Ubuntu
because its cached Node executable was group-writable; the same case
passed on AWS runners. The fixture now qualifies its own Linux copy with
mode `0500` and the actual copy digest. Host files and production
security checks are unchanged. The focused macOS case passed; the new
Linux-copy branch also passed on the final AWS-hosted Linux runner
(1,125 passing Runner tests, 3 skipped). The final run was not on a
GitHub-hosted runner.
- Final-head [CI run
36762078176](https://github.com/paperclipai/paperclip/actions/runs/36762078176)
passed for `116b968b24fa0a8c5724a7bf96e73a8dda5f0425`: 54 successful
checks and two conditional Storybook skips, with no pending or failed
checks. The 27 general/serialized test jobs reported 28,635 passing
tests. Typecheck, build, Runner, browser E2E, and Canary gates passed.
Greptile reviewed that exact head at 5/5; both review threads are
resolved, with no open follow-ups.
- No live provider replay is claimed by this PR.

## Risks

- New explicitly addressed cards reject users who cannot mutate the
issue, including viewers, inactive members, and invalid IDs. Callers
that supplied invalid recipients must correct their request.
- Existing addressed cards are not rewritten. Existing authorization
checks remain strict.
- Chat inference applies only to questions without an agent addressee.
Connector intents and governed confirmations retain their own recipient
paths.
- No schema change or migration is required.

## Model Used

OpenAI Codex, GPT-6 (exact serving variant and context window are not
exposed in this environment). Used reasoning, tool use, code editing,
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
- [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-09-30 14:16:15 -05:00
DottaandPaperclip b54b2dc35c fix: preserve warm Codex turns with incremental managed file checkpoints (#14735)
## Thinking Path

> - Paperclip manages AI agents and keeps their instructions and files
durable.
> - Native Codex runners can keep a process alive between compatible
turns.
> - Managed file collection stopped that process after each turn, which
defeated warm reuse.
> - Agent folders can contain large images and other files, so full
copies on every turn are expensive.
> - This change keeps one managed directory for the live session and
saves only file changes after each turn.
> - Ownership, authorization, instruction changes, and process
retirement still control when reuse is safe.

## Linked Issues or Issue Description

Related: #13710 introduced native warm session reuse. This fixes managed
file collection that still forced those sessions to stop. No duplicate
open PR or issue was found.

**What happened?**

With managed instructions and warm native Codex enabled, consecutive
turns reused a Daytona sandbox but started a new runner process each
time. The managed directory collector required process termination
before saving files.

**Expected behavior**

Compatible turns keep the same process and managed `AGENT_HOME`. Each
completed turn saves added, changed, and deleted files before the next
turn starts. Unchanged large files do not transfer again.

**Steps to reproduce**

1. Use a native Codex agent with managed instructions and a reusable
Daytona environment.
2. Enable warm session reuse and run three turns on the same task.
3. Write a large binary on the first turn, edit a small note on each
turn, and delete a file on the second turn.
4. Compare process identity across turns and read the canonical files
through the public agent-files API.

**Paperclip version or commit**

Reproduced on `d30b03bd8c17604cdab1533eeeeb087aba30e8b1`.

**Deployment mode**

Local server with remote Daytona execution; cloud native runner uses the
same path.

## What Changed

- Retain the managed directory only for the verified owner of a live
native Codex session.
- Checkpoint each completed turn before releasing the session for reuse.
Retry unstable captures, then stop and collect when a warm checkpoint
cannot be validated.
- Compare metadata and cached hashes, stream only changed file payloads,
record deletions, and validate path, content, quota, and authorization
before saving.
- Rotate sessions when canonical files, loaded instructions,
credentials, or launch policy change. Fence stale collection and cleanup
callbacks from later owners.
- Keep cleanup and recovery aware of the current session owner. Recheck
canonical files under the writer lock at handoff, attach the successor
collector before fallible bookkeeping, and emit one final save receipt
on checkpoint fallback. Preserve storage warnings across unchanged
checkpoints.
- Add regression coverage and a three-turn Daytona test with independent
public API file checks, an unchanged 8 MiB binary, deletion checks, and
strict process identity checks.
- Document checkpoint consistency, lifecycle behavior, and local run-log
counters.
- Replace a timing assumption in the Daytona teardown test with explicit
transfer-arrival gates after CI exposed an unset release callback.

## Verification

- Full local `pnpm -r typecheck` and `pnpm build` passed. Server checks
were repeated after the final storage-warning fix.
- Runner E2E typecheck and 749 runner E2E unit tests passed.
- Focused file checkpoint, directory ownership, instruction collection,
native session, and merge tests passed. After review fixes, the
managed-directory and native-session suites passed 550 tests, including
intervening canonical edits, same-run fresh restore, failed handoff
collection, and one-call fallback collection. Server typecheck passed
again. The Daytona plugin suite passed 218 tests. The quota-warning
regression failed before the fix and passed afterward.
- Three real Daytona campaigns passed before the final handoff review
fixes. The latest kept PID 547 across all three turns. The first
checkpoint copied 8,388,635 bytes; the next two copied 36 and 54 bytes.
Public API reads verified the binary, note contents, and deletion after
every turn. Test cleanup deleted the sandbox.
- The final head was also deployed to an isolated cloud staging instance
and passed three UI-triggered native Codex turns with managed
instructions. All three retained the same process ID/start time, native
session, provider session, runner instance, and Daytona sandbox.
Checkpoints copied 8,388,643 bytes on turn 1, then only 52 and 78 bytes
on turns 2 and 3; those warm captures also hashed only 52 and 78 bytes.
Independent canonical API reads verified every byte of the unchanged 8
MiB binary and the exact note contents after every turn; the deleted
file returned 404 after turns 2 and 3. After restoring the original
lifecycle and agent-auth configuration, removing the temporary secret,
pausing the test agent, and deleting both test sandboxes, independent
canonical API reads still verified the entire binary, the final 78-byte
three-line note, and the deletion. The native runner flag remained
enabled and the final serving revision remained the PR head.
- Two earlier staging attempts are preserved as failures and are
excluded from the acceptance result: a saved ChatGPT login failed with a
provider routing 401, and its subsequent stopped-sandbox retry failed
before provider startup with a closed-lease admission error. The
successful campaign used a fresh sandbox and a temporary encrypted
API-key binding. The stopped-lease retry remains unexplained; this
campaign does not establish recovery of that failed sandbox.
- All [Paperclip CI
gates](https://github.com/paperclipai/paperclip/actions/runs/36750397355)
pass on `26ef2ef56a389259246809805c0b34a4747eb86b`, including full test
partitions, build, typecheck, runner verification, E2E shards, and the
Canary clean public-npm install. Greptile reviewed that exact head at
5/5 with no unresolved review threads or outstanding findings.
- Full local repository coverage used the existing CI partitions, but
the 40,000-file Git streaming stress test timed out and its local retry
was interrupted by macOS thermal emergency sleep; this is not a green
full local suite claim. The exact stress test passed on the final head
in [CI server shard
2/12](https://github.com/paperclipai/paperclip/actions/runs/36750397355/job/110008294290),
in 111.9 seconds.
- Repeat the live test with configured credentials and a Linux runner
artifact: `pnpm test:e2e:runner -- --id
daytona-warm-continuity.runner-codex.daytona.warm-three-turn`.

## Risks

- This is a file-level checkpoint, not an atomic snapshot of the whole
folder. Background writes after a capture are saved by the next
checkpoint or final stopped collection.
- Metadata scans still visit all paths. Modified files transfer in full;
unchanged files do not rehash or transfer.
- Incorrect ownership or reuse could collect the wrong directory. Run
ownership fences, current authorization, stable capture validation, and
stopped collection fallbacks are covered by tests.
- Warm reuse remains opt-in. No database migration or fleet default
changes.

## Model Used

OpenAI GPT-6 through Codex, with reasoning, code editing, tool use, and
test execution. The exact serving model ID and context-window size are
not exposed by 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-09-30 13:33:37 -05:00
DottaandPaperclip d432dc7fa3 Add GitHub-synced skill sources (#14713)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Company skills supply instructions and files to those agents.
> - GitHub imports already exist, but users cannot manage repositories
as skill sources.
> - Repository refresh also needs caller-authorized access and complete
local packages.
> - This pull request adds Sources inside Skills and reuses GitHub
connections from Apps.
> - Installed snapshots let agents use skills without fetching GitHub
during a run.
> - Manual refresh preserves skill identity and leaves failed imports on
their last good version.

## Linked Issues or Issue Description

**Subsystem affected**

Cross-cutting: skills UI, server, database, shared contracts, and
runtime materialization.

**Problem or motivation**

Users keep skills in GitHub repositories. They need a clear way to
select, import, and refresh those skills. Existing imports do not expose
repository management or consistently preserve supporting files.

**Proposed solution**

Add company-scoped skill sources. Browse repositories from all
accessible GitHub connections, or paste a public repository or branch
URL. Select whole skill packages, inspect included files and reference
warnings, and install complete, immutable snapshots. Refresh each source
manually.

**Alternatives considered**

Project repository settings hide the workflow from Skills. A second
GitHub connector would duplicate credentials and grants. Upstream
editing and PR creation are separate work.

**Roadmap alignment**

This implements the Skills Manager direction in ROADMAP.md. The
maintainer requested this scope and reviewed the component and full-app
journey stories before implementation.

Related reports: Refs #10285, Refs #10949, Refs #13464. Related work:
#14356, #13656, #9268.

## What Changed

- Add source and entry records, an idempotent migration, company-scoped
APIs, and legacy GitHub import adoption.
- Reuse current caller grants and credential refresh. Combine and
deduplicate repository inventories across accessible connections. Pasted
public URLs also prefer the active user’s authorized connections. Tokens
stay in the Git child environment, never argv or disk.
- Fetch a shallow Git snapshot at one immutable commit. Scan the full
local tree, including hidden and nested folders. Read Git objects
without checkout or archive transformations and enforce nested package
boundaries.
- Bound Git downloads to 128 MiB and three minutes. Cancel active
process groups and remove incomplete downloads. Preserve cancellation
and deadlines while progress drains; close stalled HTTP progress streams
after 30 seconds. Reuse caller-scoped temporary snapshots for
preview/import after reauthorization.
- Index repository package boundaries once and cap expanded work at
1,000 packages, 10,000 files, and 100 MiB, including repeated copies of
shared blobs. Bound path depth and the shared path index. Discovery
keeps audited manifests without retaining all package bodies.
- Resolve moving branches before fetching so unchanged discovery reuses
caller-scoped snapshots. Limit active scans, scan frequency, and new
downloads per caller and company; quotas apply before metadata reads and
across connections, and cached scans do not consume the download quota.
- Store complete versions with script content, binary bytes, and
executable modes. Preserve these through copies, runtime caches, and
runner packaging.
- Stage downloads before publication. Use source leases, revision
checks, and transactional activity records. Keep installed versions
after failures, upstream deletion, deselection, and disconnect.
- Add the approved import flow, Sources page, selection tree,
provenance, read-only Studio behavior, and saved return from GitHub
setup.
- Add package manifests, commit-pinned file previews, and separate
runtime requirements and reference warnings. Supporting files are
included together; nested skills remain independently selectable.
Preview requests reauthorize the caller and re-audit package content.
- Show installed skills as compact links beneath each source. Repository
titles open GitHub. Keep Refresh, Select skills, and Disconnect source
in a three-dot menu. Source rows omit the branch, imported count, and
refresh timestamp; action alignment and repository titles work at narrow
widths.
- Stream discovery metadata over an opt-in NDJSON response. Show
measured Git download progress and real package/file counts, animate
newly checked skills, support cancellation, and require a complete scan
before selection. Keep the existing JSON API.
- Retain component stories and add a separate full-app journey story
group. Include fixed progress states and interactive scan,
large-repository, interruption, and saving stories.
- Update Skills documentation and product contracts. Suppress private
GitHub skill references in telemetry. Privacy review requested for the
telemetry changes.

## Verification

- Local repository typecheck, full build, token gates, and Storybook
build passed during this work. Focused transport, authorization,
scanner, persistence, route, and UI tests pass. The final UI refinement
passes all eight focused UI tests, UI typecheck/build, and token gates.
The scanner resource and repeated-discovery fixes pass 132 focused
scanner, transport, authorization, source-service, route, and rate-limit
tests, plus server typecheck/build. Full-suite verification comes from
CI; the older full local Vitest run was stopped after unrelated chat
failures and a font-test failure, all of which passed in fresh focused
runs. At commit `1098d5996`, all 54 active checks pass; two optional
Storybook jobs are skipped. CI covers repository typecheck, build, the
full test suites, browser shards, and the canary dry run. Greptile is
5/5 with no open findings; the security scan also passes.
- Adversarial scanner tests verify repeated-blob byte accounting with
and without declared sizes, package/file/path caps, one-time repository
indexing, metadata-only discovery audits, and nested package boundaries.
Additional tests cover branch movement, snapshot reuse, caller/company
quotas, isolation across connections, active-lease cleanup, quota
recovery, and rejection before any metadata API call.
- Real Git tests verify hidden paths, exact binary bytes, executable
modes, export-ignore preservation, symlink/submodule reporting, pinned
commits, caller-scoped cache reuse, cancellation, cleanup, and
credential isolation. Regression tests hold both download slots with
permanently blocked progress callbacks, verify timeout/cancellation
cleanup and retry, and exercise HTTP backpressure cancellation. Access
tests cover automatic public-URL connection selection and revoked
grants. Database tests verify company and grant audiences.
- Live isolated browser test: the public `anthropics/skills` scan now
completes and discovers all 20 skills without connecting an account.
Imported canvas-design with all 83 files, opened it from Sources, and
verified the installed binary-font preview/download control. Package
previews also expose the complete file inventory before import.
Cancelled an active Git download and retried successfully to all 20
discovered skills; the browser displayed measured download progress. The
current audits reject four other packages; eligible selections remain
importable.
- Browser checks verify the simplified source rows at desktop and narrow
widths, keyboard navigation into the actions menu, Refresh from the
menu, selection, and fixture disconnect with installed skills retained.
Storybook includes a menu-open checkpoint and a 320px layout.
- Storybook includes receiving/preparing download checkpoints and a
timed full-app import journey, plus cancellation, retry,
large-repository, and saving states. Streaming tests cover split UTF-8
frames, incomplete streams, late responses, cross-company requests, HTTP
errors, and JSON compatibility.
- Earlier live acceptance on this PR imported `stitch-skill` with
`DESIGN.md`, assigned it to an agent, disconnected its source, and ran a
successful Studio test that read both installed files. An editable copy
changed independently. Both Skills variants, mobile selection, and
return from GitHub setup were exercised.
- Private access, revoked credentials, OAuth success return,
binary/script preservation, concurrent refresh, transaction rollback,
version pins, and legacy adoption have automated coverage. A real
private-repository OAuth grant was not created during this test.

## Risks

- The migration groups recognizable legacy imports without provider
calls. Their first successful refresh completes the local package
snapshot.
- Reference checks are advisory. They cover Markdown links and explicit
relative resource paths, not arbitrary runtime dependency graphs.
Preview text is capped at 64 KiB; imported bytes remain complete.
- Git must be installed on the server. Shallow fetches still download
the branch snapshot, including files outside selected packages.
Downloads have size/time/concurrency limits. Temporary caches are
bounded and caller-scoped. GitHub API quota still applies to repository
metadata and the connection picker; content no longer uses per-file API
requests. Failed scans retain installed content.
- Sources depend on the current caller's GitHub access. A saved
connection does not grant access to another person's token.
- GitHub script support and immediate manual refresh are explicit
maintainer-approved requirements. The operator trusts the selected
repository and accepts upstream script and executable-mode changes on
refresh. Static audits are not a sandbox or a guarantee of safe code;
agents may later invoke installed helpers under their runtime
permissions. Import and refresh do not execute scripts, hooks, package
installation, or builds. Raw URL and skills.sh imports keep their prior
script restrictions.
- Source originals remain read-only. Refresh affects subsequent unpinned
runs; explicit pins and active runs retain their versions.
- The telemetry change removes source-managed GitHub identifiers from
skill-reference events. It introduces no event or field. Please review
the privacy boundary.

## Model Used

OpenAI Codex, based on GPT-6, with reasoning, code execution, and
browser 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-09-30 13:32:58 -05:00
scotttongandClaude Opus 5.5 6aa908ef15 fix(heartbeat): cancel queued runs whose claim is permanently rejected (#14738)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - The heartbeat scheduler claims queued runs for each agent in
`startNextQueuedRunForAgent`, and startup recovery calls it through
`resumeQueuedRuns`
> - `claimQueuedRun` can throw a 4xx `HttpError` that the run's own rows
decide, for example the 403 from #14043 ("Queued-message interrupt
authority is unavailable")
> - The claim loop does not catch that error. The run stays `queued`, so
every recovery pass and every restart claims it again and gets the same
error
> - During periodic recovery the error is logged, but it stops the claim
loop, so all queued runs of every agent after it wait. During startup
recovery the error is rethrown, so the server cannot boot
> - We saw this on a self-hosted instance: one card-answer run from
#14043 put the server in a crash loop for about 11 hours (216 failed
boots) until the run was cancelled by hand in the database
> - This pull request cancels a queued run when its claim fails with a
403 that cannot clear, keeps a run queued when its 4xx rejection can
clear later, and in both cases continues with the rest of the queue
> - The benefit is that one bad queued run can no longer stop the server
from starting or stall other agents. #14510 fixes the specific identity
mismatch; this change is the safety net for this whole class of error

## Linked Issues or Issue Description

Refs #14043

Refs #14510, #13539, #13315

## What Changed

- `server/src/services/heartbeat.ts`: The claim loop in
`startNextQueuedRunForAgent` catches errors from `claimQueuedRun` for
each run.
- A 403 is a permanent rejection. In the claim path it only comes from
the run's persisted identity (an unverifiable interrupt receipt, a
manual wake without a user), and those rows do not change. The loop
cancels that run with error code `queued_run_claim_rejected`.
`cancelRunInternal` also cancels the wakeup request and releases the
issue execution lock.
- The cancel runs after the agent start lock is released (`.finally()`),
because `cancelRunInternal` promotes the next queued run under the same
lock. A cancel inside the lock waits 30 seconds for the stale-lock
timeout.
- Any other 4xx (for example a 422 `responsible_user_unresolved`, or a
409) can clear later. The run stays queued, the loop logs a warning, and
it continues with the next run. A later recovery pass tries the run
again.
- Non-HTTP errors and 5xx errors (for example database errors) keep
propagating, as before. Startup still fails when the database or another
dependency is broken.
- If a cancel itself fails, the loop logs the error. The run stays
queued for the next recovery pass.
- `server/src/__tests__/heartbeat-queued-run-claim-isolation.test.ts`:
New embedded-Postgres tests with a mocked adapter:
- A queued-comment interrupt run with an unverifiable receipt is
cancelled, `resumeQueuedRuns()` resolves, and a second pass stays clean.
- A claimable run behind a rejected run of the same agent is claimed and
executed.
- A run with an unresolvable responsible user (422) stays queued, and
the claimable run behind it is executed.
- A rejected run for one agent does not stop the queue of another agent.

## Verification

- `cd server && npx vitest run
src/__tests__/heartbeat-queued-run-claim-isolation.test.ts` passes.
- Without the change in `heartbeat.ts`, all four tests fail (the 403
`Queued-message interrupt authority is unavailable` and the 422
`responsible_user_unresolved` escape `resumeQueuedRuns()`).
- All `heartbeat*`, `*queued*` and `run-identity` server suites pass
locally (1252/1253). The one local failure, `heartbeat-process-recovery`
"redacts opaque environment-bound credentials from Sentry diagnostics",
fails the same way on unchanged `master` on my machine and passes in CI.
- `pnpm -r typecheck`, `pnpm test:run` and `pnpm build` pass locally.

## Risks

- Behavior shift: a queued run whose claim fails with a 403 is now
cancelled, not left queued. Such a run could never start before this
change, so no runnable work is lost. The cancel reason and the
`queued_run_claim_rejected` error code make the cancel visible on the
run.
- A run with another 4xx rejection stays queued, as before, but it no
longer stops the rest of the queue. It logs a warning on each recovery
pass until the cause clears.
- Low risk otherwise: no schema, API or UI change.

> 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`) in Claude Code, with tool use and
code 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
- [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: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 10:41:17 -07:00
DottaandPaperclip 94e8dec56b fix(runner): preserve tool outcomes through shutdown and restart (#14734)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - The runner sends authorized tool calls to the server and saves their
results.
> - A provider turn can stop while a server write is still running.
> - The old shutdown path invented a failed result that could conflict
with the real result.
> - Truncated execution input and incomplete recovery records made the
failure harder to diagnose.
> - This pull request preserves exact inputs and actual outcomes through
shutdown and restart.
> - Tests force the race and crash boundaries so safe retries do not
repeat writes.

## Linked Issues or Issue Description

**What happened?**

Stopping a turn during a server tool call could record a false failure,
then reject the actual result as a conflict. The diagnostic input
formatter could truncate instruction content before execution. A crash
during saved-result delivery could leave that delivery permanently
indeterminate. Cleanup could hide the first failure, and a retry could
overwrite earlier run logs.

**Expected behavior**

Keep dispatched tools pending until their actual result is known.
Preserve accepted input bytes. Accept identical result delivery without
failing the task. Reject conflicting results with enough evidence to
diagnose them. Recover saved-result delivery without repeating the
business operation.

**Steps to reproduce**

1. Hold an instruction update at the filesystem commit barrier.
2. Stop its provider turn before the server returns the result.
3. Release the write, deliver its result, and replay the same result.
4. Repeat with a restart before and after the delivery receipt is saved.
5. Check that there is one write and one audit row, and that the exact
result survives.

**Paperclip version or commit**

The change was developed from `44736c9c7` and rebased onto `0e5830887`.

**Deployment mode**

Self-hosted server with the native runner. Tests use local runner
processes, scripted providers, and PostgreSQL.

Related work: #12353 added durable semantic tool receipts; #12384 added
durable Codex tool recovery; #12404 bound semantic tools to ACPX
sessions. #14633 covers separate native-provider cancellation and
qualification work. This PR addresses server semantic-tool outcomes and
their durable delivery. No duplicate fix was found. AgentMail discovery
is outside this PR.

## What Changed

- Close turn admission without inventing results for dispatched tools.
Keep pending calls and accept late actual results.
- Accept identical result replay with a diagnostic warning. Include call
identity and both result hashes in real conflict errors.
- Preserve exact execution arguments. Reject prohibited or oversized
input before dispatch. Keep diagnostic previews redacted and bounded.
- Commit instruction-attempt evidence before the filesystem write. Save
completed mutation receipts so concurrent and restarted duplicates
return the first result. Recheck authorization before replay. An attempt
without a completed result stays unknown and cannot execute again.
Definite pre-write failures save and replay their original error without
another write.
- Recover an interrupted saved-result delivery only for backends with
durable result receipts. Never replay an ordinary business operation
with an unknown outcome.
- Preserve the initiating error when cleanup also fails. Record
incomplete settlement evidence. Propagate typed unknown-outcome errors
through the native tool wrapper without creating a false completed tool
result.
- Append run-log attempts and restore the durable log before appending
after local file loss. Reject incomplete restores. Publish a restored
prefix only if the destination is absent so concurrent attempts cannot
overwrite new lines.
- Add deterministic race, crash, replay, authorization, exact-content,
and log-restoration tests. Document their assertions in
`packages/paperclip-runner/docs/durable-recovery.md`.

## Verification

- Current head: `7e088f4c7fba8ebabf98ae95485a5753b013d489`. All 55
applicable checks pass; four conditional/manual checks are skipped. This
includes build, typecheck, Rust, both runner TypeScript shards, server
and workspace tests, all eight browser shards, isolated runner
compilation, and the clean-install release dry run. [CI
run](https://github.com/paperclipai/paperclip/actions/runs/36746101110).
- Greptile reviewed this exact head at 5/5 with zero new findings. All
three earlier review threads are resolved.
- Focused local verification includes 11 instruction integration tests,
23 surrounding authority/tool tests, 26 run-log tests, and 169
controller/driver tests. The post-rebase controller/transport/runtime
selection passed 415 tests. The full Rust release suite passed 617 tests
with two ignored. The real-process SIGKILL recovery test passed three
consecutive runs.
- The fault matrix in
`packages/paperclip-runner/docs/durable-recovery.md` uses explicit
barriers, real PostgreSQL rollback, durable journal reloads, and killed
runner processes. It covers late results, identical and conflicting
replay, exact long content, concurrent log restoration, lost commit
acknowledgements, and definite failure replay after the original CAS
base becomes valid again. No paid model calls are needed.
- Full local recursive typecheck and build passed during implementation.
Server typecheck and the runner TypeScript build passed after the review
fixes. The broad local repository test run was stopped after repeated
database startup timeouts. Four timing/launch failures in an earlier
broad runner run passed focused reruns without changed assertions or
timeouts. These are local verification limitations; the complete
current-head CI suite is green. An earlier CI workspace job received an
infrastructure shutdown signal; its current-head replacement passed.

## Risks

- A stopped turn can remain blocked when a dispatched operation has no
proven result. The system does not guess its outcome or rerun its
effect.
- Conflicting results still fail settlement. Existing failed or
conflicting journals are not repaired automatically.
- Accepted semantic input is limited to 480 KiB of encoded JSON to fit
the encrypted transport. Larger input fails before execution.
- Instruction filesystem writes and database receipts are not one atomic
storage operation. A separately committed attempt and audit record
survive rollback. An attempt without a completed success or definite
pre-write failure receipt remains blocked as an unknown outcome. It is
not replayed or reported as success.
- Run-log restoration now reads the durable object before appending when
the local log is missing. Failed or incomplete reads reject the append.
- No schema migration, dependency change, workflow change, or AgentMail
change is included.

## Model Used

OpenAI Codex, GPT-6, with reasoning, tool use, code execution, and test
analysis. The exact served 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 (focused suites; the broad
local run limitation is 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-09-30 11:54:56 -05:00
DottaandPaperclip 3c561642b4 fix(chat): resolve approvals and preserve unanswered questions (#14613)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Agents ask for decisions and optional details through cards in chat.
> - A clear approval in a message can leave the matching card pending.
> - An unanswered question can also block an unrelated later reply.
> - Decisions need a saved source message, while optional questions need
to remain answerable in history.
> - This pull request records conversational decisions and lets users
move on from questions and answer them later.

## Linked Issues or Issue Description

**What happened?**

Native Claude and Codex could act on approval in chat while the original
approval card stayed pending. Pending question forms stayed above the
composer, were absent from history, and could suppress later chat
replies. A late native question answer could wait for a finished run to
reconnect.

**Expected behavior**

The active agent records a clear approval or refusal against the exact
card and user message. Ambiguous replies do not grant consent. Users can
send another message without answering a question. The question remains
pending in history and can be reopened and answered later. The saved
answer reaches the agent.

**Steps to reproduce**

1. Ask an agent to propose work with a confirmation card, then approve
it in chat.
2. Check that the original card records that approval before work
starts.
3. Ask an interactive question, send an unrelated message, and reload.
4. Open the unanswered question from history and submit an answer.

Related work: #14408 added completion delivery. #14607 tests completion
reporting turns. Neither records conversational answers on approval
cards.

## What Changed

- Add a confirmation endpoint backed by a user comment, with schema
validation, OpenAPI discovery, and native Plan-mode access. Ask mode
remains read-only.
- Check company, active run, actor, current session, message provenance,
revision, and resolver policy. Save the decision and audit in one
transaction. Retries do not repeat effects. Emit resolution telemetry
after commit.
- Give fresh and resumed chat turns the actual pending confirmation
identities. Teach agents to save clear conversational decisions before
acting and to clarify ambiguity.
- Keep unanswered Agent Chat questions as compact history entries. A
newer user message closes the old form. Question cards never contribute
to composer pending counts or navigation, including after dismissing a
fresh form. The history card is the sole reminder; clicking it restores
that exact form and draft.
- Preserve Agent Chat questions when later messages or questions arrive.
Historical ordinary inputs no longer gate later chat replies.
Current-run requests, task execution, and governed approvals keep their
gates. Remove the special acknowledgement-publication proof helpers that
this rule replaces.
- Route answers to finished native runs through durable fresh-wake
delivery, with existing idempotency and source-question context. Settle
late replies against contiguous completed conversation turns and freeze
their history replay; failed, unhandled, and newly arriving messages
remain actionable.
- Add real-component Storybook scenarios, database and UI regressions,
and a three-turn native Claude/Codex E2E case. Capture distinct,
UI-ready screenshots and report the individual assertions.

## Verification

- Focused decision/publication/UI regressions after merging master: 288
passed; subsequent UI draft, failed-send, and conversation checks: 199
passed.
- Native question and durable delivery regressions: 106 passed,
including all four terminal run states and exactly-once late delivery.
Seven targeted regressions fail against the original implementation and
pass with the fix.
- Latest conversation/decision/native-delivery regressions after the
master merge: 121 passed. Covers completed progress, missing or failed
intervening turns, new messages during a late reply, stale sessions, and
frozen retry/replay boundaries. Four new assertions fail before the
ordering fix.
- E2E support suite after the master merge: 792 passed. Negative
controls reject expired cards, wrong questions/answers, stale or missing
replies, unrelated clarification forms, and unexpected tasks.
- The embedded-browser walkthrough caught one additional defect:
dismissing a fresh question still showed a composer badge. Both Cancel
and close-button regressions failed before the fix. The fix at
`65f2ade12` passes 170 chat-thread tests and 792 E2E support tests.
After merging master, 232 chat-thread/confirmation tests, server/UI
typechecks, and token gates pass. The preview and two-provider live E2E
pass at `e5512a206`; Greptile is 5/5 with zero unresolved threads at
that commit. All 55 checks are now successful at `e5512a206` (four
conditional checks skipped), including the aggregate verification gate
and clean-install canary test. The first attempt was interrupted by
simultaneous CI worker shutdowns; one failed-job rerun passed without
code changes.
- [Published
Storybook](https://d1p6rlowie26tp.cloudfront.net/storybook/branches/codex~2Fchat-approval-resolution/?path=/story/chat-comments-agent-chat-unanswered-questions--moved-on):
nine real-component scenarios. Manually exercised move on, reopen,
preserve draft, answer later, answer one of multiple questions, and a
custom mobile answer in the embedded browser. Retested fresh Cancel and
close-button dismissal in the updated build, then reopened and submitted
the preserved Green selection and inspected its answered receipt. Static
preview has no live model/backend; its callbacks are fixture responses.
- [First live
campaign](https://d1p6rlowie26tp.cloudfront.net/runner-e2e/campaigns/gha-36714504406-1/)
reproduced the late-answer completion-state defect on both providers
despite correct saved answers and acknowledgements. It also exposed a
valid imperative clarification rejected by the old oracle. Both issues
are fixed with regression controls; this failing run is retained as
evidence.
- [Four-cell
qualification](https://d1p6rlowie26tp.cloudfront.net/runner-e2e/campaigns/gha-36717804064-1/)
passed 4/4 at `2bf8a1009`: unanswered-question return and ambiguous
confirmation, each on native Claude and Codex. Inspected saved state,
source-message decisions, visible cards, and agent replies. Both
late-answer chats settled to waiting; no unrequested tasks were created.
[Final branch
rerun](https://d1p6rlowie26tp.cloudfront.net/runner-e2e/campaigns/gha-36719666238-1/)
passed 2/2 at `142630720`: the same unanswered-question journey after
merging master, plus an additional screenshot and browser assertion for
the actual late-answer acknowledgement.
- [Composer-reminder
E2E](https://d1p6rlowie26tp.cloudfront.net/runner-e2e/campaigns/gha-36727006818-1/)
passed 2/2 at `5b62c52d9`: native Claude and Codex, three turns each,
with explicit no-badge assertions before and after reload. Inspected
saved pending/answered state, both screenshots with a clear composer,
and actual Blue acknowledgements; all five behavioral matchers passed
per provider and neither created tasks. Cost coverage is partial; this
is bounded workflow qualification.
- [Fresh-dismissal
E2E](https://d1p6rlowie26tp.cloudfront.net/runner-e2e/campaigns/gha-36742773318-1/)
passed 2/2 at `e5512a206`: native Claude and Codex, including fresh
Cancel, clear composer, reopen, unrelated message, reload, late Blue
answer, and actual agent acknowledgement. All five behavioral matchers
pass per provider. Inspected the fresh-dismissal screenshots and saved
pending/answered identity; neither created tasks. Cost coverage is
partial (4/6 runs).
- Prior evidence remains available in [the earlier
campaign](https://d1p6rlowie26tp.cloudfront.net/runner-e2e/campaigns/gha-36642252725-1/).
Its early loading screenshot and overwritten final capture prompted the
UI-ready, distinct screenshot fixes.

## Risks

- The model interprets intent. The server verifies permission and
provenance; it does not infer consent from text. Ambiguous and unrelated
replies are not approvals.
- Historical questions can accumulate. They remain visible, pending, and
answerable; no automatic answer or expiry is invented.
- The change to completion gates is scoped to Agent Chat and ordinary
historical inputs. Current-turn and governed approvals retain their
existing controls.
- Live qualification is limited to the selected stories. Broader native
onboarding finalization remains separate work.
- No database migration. Telemetry adds no fields or values; the
contract and README document the commit boundary. Privacy review was
requested on the PR.

## Model Used

OpenAI Codex, GPT-6 family, with reasoning, repository tools, code
execution, and browser-test orchestration. The exact model ID and
context-window size are not exposed to 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-09-30 11:46:46 -05:00
DottaandPaperclip 0e5830887b perf: reveal task content sooner and parallelize issue reads (#14727)
## Thinking Path

> - Paperclip helps people manage AI agents and their work.
> - A task page must show saved replies quickly so a person can read the
work.
> - The title could appear while the conversation waited for unrelated
metadata and transcripts.
> - Thread requests also waited for enriched task details, while the
server read several independent fields in sequence.
> - This change shows saved content as soon as it is ready, starts
thread reads earlier, and runs independent server reads together.
> - Native event history takes priority over legacy log fallback, and
mentioned tasks load on intent.
> - Content-free timing spans make the remaining server delays visible
without recording task content.

## Linked Issues or Issue Description

**What happened?**

Task titles and properties appeared quickly, but saved conversation
content stayed hidden for several more seconds while metadata and run
transcripts loaded.

**Expected behavior**

Saved replies and the task description should be readable without
waiting for supporting history. Returning to a cached task should show
content within a frame or two.

**Steps to reproduce**

1. Open a task with saved comments and completed runs.
2. Delay the task activity and runs responses by five seconds in the
browser.
3. Observe whether saved content remains hidden until those responses
finish.
4. Navigate away and return to the task to check cached navigation.

**Paperclip version or commit**

The change was developed from `1b48e73e0` and rebased onto `44736c9c7`.

**Deployment mode**

Built from source, tested in an authenticated staging deployment and
with local response replay.

Related: #14667 overlaps the transcript reveal behavior and adds
separate retry UX. This PR also changes navigation prefetch, parent
metadata gates, native log fallback, server read scheduling, and timing
spans. #12647 proposes a separate SQL predicate optimization in the runs
service. #13597 and #13095 are earlier loading fixes.

## What Changed

- Start activity and runs when the task page mounts, alongside task
details and comments, using the route reference for shared query keys.
Hover/focus prefetch does not start full history reads.
- Reveal saved comments and descriptions while metadata and transcripts
load. Preserve strict waits for linked-comment navigation and tasks with
only runtime content.
- For settled native runs, fetch legacy logs only when event history is
empty or fails. Preserve live-log subscriptions for queued and running
native runs. Fetch mentioned-task details on hover or focus.
- Run independent issue-detail enrichment and run metadata reads in
parallel while preserving recovery dependencies.
- Add `Server-Timing` phases and opt-in OpenTelemetry spans, plus
regression tests and observability documentation.

## Verification

- **313 tests passed** across the initial seven focused component,
cache, timing, and scroll suites. After review fixes, **313 tests
passed** across five task-page, cache, prefetch, and live-transcript
suites (`pnpm exec vitest run` with `--maxWorkers=1`; these sets
overlap).
- `pnpm -r typecheck` and `pnpm build` passed locally before the final
UI-only review fixes. UI typecheck/build and `pnpm check:token-gates`
passed after those fixes. The final commit also passes full typecheck
and build in CI.
- The full local Vitest run was attempted. Several unrelated embedded
PostgreSQL fixtures failed to start, and parallel test workers hit
timeouts. Focused reruns passed. A later local full-suite rerun was
stopped after the complete CI suite passed; it is not claimed as a local
full-suite pass.
- Final commit `d1e147145`: **54 checks passed, 2 skipped**, including
all server/workspace test shards, all eight browser E2E shards, full
build/typecheck, Runner checks, release registry, and canary
clean-install verification. [CI
run](https://github.com/paperclipai/paperclip/actions/runs/36734642034).
Greptile **5/5** after two reviews; both findings fixed and all review
threads resolved. No merge conflicts.
- Live browser tests on an existing task with two saved replies: median
full reload to visible content fell from **1.92 s** (3 samples) to
**1.40 s** (5 samples). Cached return fell from **421 ms** (1 sample) to
**29 ms** (3 samples). These are observed samples, not a performance
guarantee.
- With activity and runs delayed by five seconds, saved content appeared
in **1.38 s** on desktop and **1.33 s** on mobile. The inspected comment
did not move when metadata arrived. Verified history expansion, task
properties, pending-input navigation, dashboard return, and mobile
layout.
- A separate local replay with fixed responses reduced visible-content
time from **5.12 s** to **2.15 s**. This isolates frontend behavior and
is not a live-server benchmark.

## Risks

Progressive history can change the thread after first paint. Existing
anchor behavior is retained and covered by tests and delayed-response
browser checks. Query aliases must stay aligned for invalidation.
Parallel reads can increase short bursts of database work; dependent
recovery operations remain ordered. Full reloads still depend on network
and task-detail latency.

No schema or authorization change. OpenTelemetry remains disabled
without an operator endpoint. The added spans use a closed set of phase
names and carry no task IDs, task content, or exception text.

I checked `ROADMAP.md`; this is a performance fix within the existing
task page.

## Model Used

OpenAI GPT-6 in Codex. The runtime does not expose a more specific model
ID or context-window size. The agent used reasoning, code editing,
terminal tools, and Chrome performance profiling.

## 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-09-30 10:26:28 -05:00
DottaandPaperclip a36cbffa9e fix(connections): broaden natural-language and aggregator search (#14725)
## Thinking Path

> - Paperclip manages agents and the services they need for work.
> - Agents use connection search to discover a setup path before they
request access.
> - Tool-only filtering hid channel and AI methods from this search.
> - Requiring every query word to match rejected normal task
descriptions.
> - A small aggregator index also omitted supported apps such as
Circleback.
> - This pull request broadens retrieval and returns purpose-specific
setup guidance.
> - Agents can choose a relevant result while existing access and
provider-choice checks still apply.

## Linked Issues or Issue Description

**What happened?**

A search such as “AgentMail create an email address and manage an agent
mailbox” returned no usable result. “Help me find tools for circle back”
also missed Composio's supported Circleback toolkit. Queries longer than
200 characters failed validation.

**Expected behavior**

Return useful native and verified aggregator matches from
natural-language queries. Include channel/email methods when Chat
connectors is enabled. Identify each method's purpose and the correct
setup path.

**Steps to reproduce**

Use the queries above with `connections_search` from an active task.
Enable Chat connectors for the AgentMail case. The regression suite
reproduces these misses before the change.

Related routing work: #13941. This change does not change the runner
failure path or add channel setup to tool-only connection cards.

## What Changed

- Rank name and capability matches. Accept extra words, split names,
small spelling errors, and queries up to 4,000 characters.
- Include tool, channel/email, and AI methods. Return company-prefix
setup links for channel and AI flows.
- Add a dated snapshot of 1,583 official Composio toolkit names and a
refresh script. Merge duplicate MCP variants for search and link each
support claim to official evidence.
- Find authorized indexed aggregator namespaces within longer queries.
Return multiple app matches when the agent needs to choose.
- Prefer exact app names over fuzzy matches for other apps; retain
existing AI readiness.
- Preserve native preference, company and identity boundaries,
administrative denials, and saved provider consent.
- Add relevance and database regressions, extend native tool-authority
coverage, and document search behavior.

## Verification

- Red: 15 new assertions failed against the previous implementation; the
existing baseline passed. Added red-green regressions for Motion versus
fuzzy Notion and existing AI access during review. A further regression
covers mixed ready/unconfigured AI results and their per-result setup
guidance.
- Green: all 103 tests in the eight focused shared, database,
runtime-tool, fixture, and route suites pass on the latest commit.
- `pnpm -r typecheck` and `pnpm build` passed.
- Latest-commit CI passed: 54 successful checks and two skipped checks,
including the full test matrix, browser E2E, typecheck, build, and
canary dry run.
- The long local `pnpm test:run` attempt began before the review fixes
and retained transformed pre-fix search code; it also hit an unrelated
timing failure. Fresh serial reruns of the affected search suites and
three timeout cases passed all 124 tests. Parallel local route shards
hit two additional database setup timeouts; both suites passed all 17
tests on a fresh serial rerun. The complete corresponding CI suites also
passed. Duplicate broad local runs were stopped after CI completed. The
local UI suite independently passed all 7,007 tests.
- Greptile: 5/5 on `cc6a0180d`; all review findings resolved.
- Browser verification passed in a disposable local instance through
real process-agent search requests: AgentMail opened its setup flow with
the requester selected; the saved Circleback choice produced the
Composio setup card; a paragraph-length Notion query produced its setup
card. No provider credentials or external accounts were created.
- The browser test caught an invalid UUID-based setup URL. The fix uses
the company prefix and has a regression assertion.
- A 3,971-character catalog query found Circleback first in a local 10
ms spot check after sharing query preparation across the catalog scan.
This is a single measurement, not a performance guarantee.

## Risks

- Broader retrieval can return extra candidates. Named services rank
first; agents must select the relevant method.
- The public support snapshot can age. It proves catalog support, not
account authorization or the availability of every requested action.
- Channel and AI methods use existing setup links. The tool connection
card still accepts tool methods only.
- No schema, migration, credential, or runner lifecycle changes.

## Model Used

OpenAI Codex (GPT-6). The session does not expose a more specific model
identifier or context-window size. Used reasoning, repository search,
code execution, tests, 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-09-30 10:20:50 -05:00
DottaandPaperclip dd7fc1f90a fix: raise the native journal read limit to 256 MiB (#14711)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Native sessions persist control-plane state so they can resume
safely.
> - The state includes committed provider history needed for recovery.
> - The server, runnerd recovery, and durable control plane validate
this state before trusting its identity.
> - Their differing 64 MiB and 192 MiB limits can reject a valid journal
before recovery.
> - This pull request aligns all three local state limits at 256 MiB.
> - Larger files remain bounded, while recovery can read larger valid
histories.

## Linked Issues or Issue Description

Refs #13882
Refs #14312

## What Changed

- Raise the server and runnerd recovery limits from 64 MiB to 256 MiB,
and align the durable control-plane limit from 192 MiB to 256 MiB.
- Add coverage for a valid history above 64 MiB and rejection above 256
MiB.

## Verification

- Matching server recovery passed with more than 64 MiB of actual
committed event payloads (128 events with 512 KiB deltas).
- The real runnerd exact-authority resume regression with the test Codex
provider passed with 193 MiB of valid JSON whitespace appended. It
crosses the former 192 MiB core limit and confirms the same provider
identity. This exercises the runner process and durable control plane
with a simulated provider, not a live OpenAI API call. This test used
approximately 1.15 GiB peak RSS.
- The actual runnerd reader accepted valid 256 MiB JSON and rejected
valid 256 MiB + 1 byte. The reader call took 231 ms; the fresh process
peaked at 1,244 MiB RSS.
- Server tests reject mismatched identity above 64 MiB and files above
256 MiB.
- `pnpm -r typecheck`, `pnpm build`, and `git diff --check` passed.
- Full local `pnpm test:run`: 13,730 passed, 575 skipped, 7 failed
across 6 files. All failures were embedded PostgreSQL startup errors
after five attempts. They affected agent hiring, instruction revisions,
environment images, reviewed chat bindings, issue monitoring, and legacy
continuation authority. The focused journal tests passed; the latest
pushed head passed all ordinary CI checks. Superagent is the only
blocking check.

## Risks

- **Open review concern:** Greptile is 5/5, but Superagent is
`ACTION_REQUIRED` with two P2 findings on the server and runnerd
readers. Both flag the increased synchronous parsing and memory cost.
This PR keeps the requested fixed-limit change small. It does not add a
worker parser or a process-wide memory budget. This resource tradeoff
needs review before merge.

- Large state parsing is synchronous and can consume several times the
file size in memory.
- Remote checkpoint archive and expanded-size limits remain 64 MiB, so
this change alone does not make larger remote checkpoint transfers
portable.

## Model Used

- OpenAI Codex, GPT-6, with delegated assistance from `gpt-6-luna` at
high reasoning effort; tool use and code execution. The GPT-6 context
window is not exposed in this task 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 (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-09-30 10:08:25 -05:00
DottaandPaperclip d30b03bd8c test: add persistent E2E coverage for human blocker decisions (#14707)
## Thinking Path

> - Paperclip manages work for AI agents.
> - Agents use the coordination skill when work needs human authority or
a scope decision.
> - PR #14188 replaced automatic manager escalation with direct blocker
handling.
> - This behavior needs real browser, server, database, and provider
tests.
> - The test must verify saved human input, task ownership, and resumed
work.
> - This pull request adds six reusable Product E2E cases and improves
the skill examples that they exercise.

## Linked Issues or Issue Description

Refs #14188.

The merged change needs repeatable behavior coverage. The new suite
tests missing administrator access, missing hiring permission, and
requester scope questions. Searches found no duplicate blocker-guidance
suite. This extends the existing eval system described in ROADMAP.md.

## What Changed

- Add the explicit-only `blocker-guidance` Product E2E suite. It has
three local scenarios on legacy Codex and legacy Claude.
- Use the production UI and public APIs to create work, save a
human-only question or confirmation, answer it after reload, and resume
the same task.
- Check requester identity, ownership history, manager activity, hiring,
saved answers, and completion. Keep direct text input as a separate UX
result.
- Save pending and final screenshots, API checkpoints, skill hashes,
provider evidence, and billing data through the existing report
pipeline.
- Isolate the Claude fixture home. Verify the served skill bytes before
dispatch so an old installed skill cannot silently replace the evaluated
skill.
- Improve the coordination and hiring skill examples. Include the
human-only policy, requester address, wake behavior, and handling of
authorized scope changes.
- Grader v5 requires the exact approved public welcome note as a new
worker comment. Browser input checks reject unwritable scope cards
before clicking, and confirmation direction must be saved in the
resolution before the worker wakes.
- Add grader calibration and browser-input tests. Update the fixture
guide and generated capability inventories.

## Verification

- `pnpm build`: passed after rebasing onto current master.
- `pnpm -r typecheck`: passed.
- `pnpm test:e2e:runner:typecheck`: passed.
- `pnpm test:e2e:runner:unit`: 742 tests passed.
- `pnpm test:e2e:runner:browser-support blocker-input.spec.ts`: 10 tests
passed.
- `pnpm test:e2e:runner -- --list --suite blocker-guidance`: six cells
found.
- Capability inventory and generated-contract checks: passed.
- `pnpm exec vitest run
server/src/__tests__/hiring-operational-examples.test.ts`: four tests
passed after synchronizing the generated API reference and section
anchor.
- Full general and serialized test suites: passed in CI on
`6652cee74517039676bad6a720f213625d265acd`. The redundant local `pnpm
test:run` was interrupted after complete CI coverage passed; it is not
claimed as a completed local full-suite run.
- Final GitHub checks: 54 passed, two optional Storybook checks skipped.
The runtime-exposure startup test hit a 10-second readiness timeout
once, passed a targeted local reproduction, and its CI shard passed the
single retry without code changes.
- Current-head Greptile: 5/5, clean check, zero unresolved threads.
- Historical live measurement on September 29 at
`4edc77ae2b95b10dd61426ce3f042bac00527ad9`: three independent six-cell
runs scored 5/6, 6/6, and 6/6. Claude Sonnet 4.6 passed 9/9. Codex
`gpt-5.6-sol` passed 8/9. These runs predate this rebase.
- Version 5 changes the scope answer to an exact approved publication
draft. The historical runs do not qualify that new requirement; the
two-provider scope pilot at `49a1f4eab369948b9e3b34a6ce436489e875e4ec`
passed Codex and failed Claude. Claude posted the correct salary-free
sentence but omitted its required reference line from that comment,
placing the reference in a separate completion message. The
`public-welcome-note` check correctly failed. An earlier Claude
database-startup failure was retained separately; its fresh-instance
retry reached the model. This pilot is not a six-cell qualification.
- The failed Codex scope case omitted `addresseeUserId`. The strict
routing check remains. All 18 attempts had clean evidence manifests and
passed cleanup.
- To repeat with provider credentials: `pnpm test:e2e:runner -- --suite
blocker-guidance --max-parallel 1`. This is a paid, opt-in suite and is
excluded from `--all`.

## Risks

- The live suite measures variable model behavior. The retained 17/18
historical result and the current 1/2 scope pilot are not all-pass
qualifications. These paid cases are opt-in; their observed model
failures remain visible independently of deterministic CI checks.
- A separate generic task-replacement diagnostic still exposed a Claude
refusal. The ordinary cases use specific business decisions. The
diagnostic is not a standalone catalog case in this change.
- Earlier measurements included an old installed Claude skill and test
defects. Their grades remain retained and are not combined with the
three final repetitions.
- Skill examples can affect when agents ask for human input. Downstream
permission checks still apply.
- Native runners, Daytona, agent-requester routing, and real external
connection authorization are outside this suite.
- Raw provider traces and credentials remain private. No screenshots,
raw reports, secrets, workflow changes, or lockfile changes are
committed.

## Model Used

OpenAI GPT-6 through Codex assisted with this change. The exact deployed
variant and context window size are not exposed in this session. The
assistant used reasoning, repository edits, tool use, and shell
execution. The evaluated models were `gpt-5.6-sol` and
`claude-sonnet-4-6`.

## 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-09-30 07:56:54 -05:00
DottaandPaperclip 1b48e73e0b feat(ui): add secondary navigation for agent chat (#14706)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Agent Chat already provides a persistent conversation with each
agent.
> - Its shortcuts share the primary navigation and do not give chats a
dedicated place.
> - People need to find agents, start a chat, and switch conversations
without moving the page layout.
> - This pull request adds a secondary chat sidebar and a landing page
around the existing chat surface.
> - The same conversation, composer, history, and context panel remain
in use.

## Linked Issues or Issue Description

Refs #13283 and #13420. This extends the existing experimental Agent
Chat navigation after review of the component and page stories. It
supports the CEO Chat roadmap item through the existing task-backed
conversation model.

**Subsystem affected**

The board UI and the company-scoped conversation list API.

**Current behavior**

Chat shortcuts sit inside the primary navigation. There is no dedicated
landing page with a searchable conversation list. A separate landing
header also moves the sidebar when an agent is selected.

**Proposed behavior**

Show a Chat entry in primary navigation. Keep a searchable agent sidebar
beside the chat content. The plus button starts or reopens the current
user's single conversation with that agent. Keep the header and sidebar
in the same positions before and after selection.

**Reason and benefit**

People can find agents and return to persistent conversations without
leaving the chat area or creating duplicate chats.

**Breaking changes**

The experimental chat navigation changes. Explicitly adding a chat now
resolves its conversation immediately. Direct visits to unused agent
chat URLs remain read-only. The existing per-agent routes and message
contracts remain compatible. No database migration is required.

## What Changed

- Add an account- and company-scoped conversation list endpoint with the
existing access checks, feature gate, and OpenAPI entry.
- Add the live secondary sidebar, landing page, avatars, search, loading
states, errors, and retry controls.
- Make the agent picker wait for chat creation and display failures.
Existing agents reopen the same conversation. A dismissed selection
cannot close a reopened picker or navigate over a newer choice.
- Preserve recent-activity ordering and terminated agents’ chat history.
Scope live list refreshes to the current user’s conversation events. A
failed historical-agent lookup leaves healthy chats usable and offers a
focused retry.
- Keep the sidebar and header stable across chat routes. Keep mobile
selection in the navigation drawer.
- Use the production components in Storybook. Prepare the theme and
mobile viewport before mounting the page to avoid the startup flash.
- Update product documentation, the design guide, and navigation tests.
Replace old browser expectations for stars and recent shortcuts with
persistent conversation and layout coverage.

## Verification

- `pnpm -r typecheck`, `pnpm build`, and `pnpm check:token-gates` pass
after rebasing onto master.
- Focused UI tests pass, including 105 sidebar, picker, and live-update
checks after review fixes. The 33 conversation service and route tests
and 10 OpenAPI checks pass, including ownership, feature gating, and
concurrent creation.
- The full local test run passed 14,163 server tests before three
environment or timeout failures. The embedded Postgres startup,
connector socket, and native runner failures all passed direct reruns.
- Browser test-drive verification covers a real provider reply, add and
reopen, persisted history after reload, no-match search recovery, mobile
drawer dismissal, and top-aligned context panels.
- Browser measurements confirm that the sidebar has the same position
and dimensions on the landing page and an agent conversation.
- Storybook builds and its add-and-reopen interaction passes.
- The revised browser regression passes locally against a freshly built
throwaway instance. It covers stable sidebar geometry, add/reopen
uniqueness, drafts, search, history, and terminated-agent history after
reload. The full CI browser suite also passes.
- Latest commit `b323577d9523180104df4000eaceedea2772608c`: all 54
completed checks pass, including the complete server/workspace/browser
suites, aggregate verification, build/typecheck, security scans, and
canary packaging. The two Storybook jobs are skipped by their workflow
conditions. [CI
run](https://github.com/paperclipai/paperclip/actions/runs/36714052050).
- Greptile reviewed this same commit at 5/5 with no remaining actionable
findings; all review threads are resolved.
- Reviewer path: enable Agent Chat, click Chat, use plus to choose an
agent, send a message, switch away, and reopen that agent. One
conversation must remain, with its history intact.

## Risks

- The new sidebar lists persistent conversations instead of starred and
recent shortcuts.
- Chat creation is asynchronous. Errors stay visible in the picker, and
delayed responses cannot navigate into a previous company or account.
- The shell adjustment is limited to chat routes and preserves the
existing conversation implementation.

## Model Used

OpenAI GPT-6 through Codex, with reasoning, code execution, and browser
tools. The session does not expose the exact API 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
#123` / `Refs #123` 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-09-30 07:35:32 -05:00
DottaandPaperclip d72389bee2 feat: add Browser Use Cloud connector and live task browsers (#14627)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - The Apps gateway gives agents governed access to external tools.
> - Browser Use Cloud can run browser work, but a tool result alone does
not let a person watch or take over.
> - A task needs a durable browser session, a visible viewer, and
recorded costs.
> - This pull request adds a Browser Use Cloud v4 connection and
interactive browser tabs on tasks.
> - People can follow the work, interact with the page, and retain the
browser after the agent finishes.

## Linked Issues or Issue Description

**Problem or motivation**

Agents need governed access to Browser Use Cloud. People need to see and
interact with the same browser from the task. A browser must remain
available after a run finishes and appear at the correct point in the
task feed.

**Proposed solution**

Add a native REST connection for the v4 API. Bind each session to its
company, task, agent, and credential grant. Open its interactive viewer
in the task side panel. Record provider costs as financial events. Use
`browser-use-cloud` as the app and connector key. Keep its skill with
the connector and deliver it only with authorized connection tools.

**Alternatives considered**

A v3 MCP connection would expose tools without the v4 lifecycle
integration. An external viewer link would leave the task. A fixed
viewer size would prevent pages from responding to changes in the task
pane.

**Roadmap alignment**

This extends the governed Apps gateway and Connected Apps roadmap. It
uses the existing task, grant, secret, approval, and financial records.
The work was requested by the maintainer. A search found no duplicate
Browser Use connector PR or issue.

## What Changed

- Add the Browser Use Cloud app, brand asset, API-key connection, and
profile settings under the `browser-use-cloud` key.
- Bundle the `browser-use-cloud` skill with the connector. Keep it out
of global `skills/` discovery. Deliver it only with authorized task/run
connection tools. Remove retired connector skill keys from runtime
overlays and preserve unrelated browser skills.
- Expose seven v4 tools through the governed gateway and deliver them to
native and CLI agents.
- Persist sessions, browsers, runs, event and recovery cursors, shutdown
leases, and cumulative cost accounting. Recover uncertain paid starts
without replaying them.
- Enforce task ownership, credential grants, approvals, revoked access,
and budget limits.
- Add interactive task browser tabs and compact chronological feed
entries. Retain the viewer across tab switches and keep visible idle
browsers open.
- Add debounced automatic viewport fitting, standard size presets, and a
viewer ownership lease.
- Add lifecycle, authorization, accounting, viewport, UI, and Storybook
coverage.
- Add an idempotent database migration after the current master
migration. Preserve deployed migration hashes. Migrate pre-release Cloud
connection and financial keys without replacing grants, credentials, or
browser history.
- Document provider behavior, live acceptance results, and the lack of
documented passkey forwarding.

## Verification

- Full workspace typecheck and production build pass on the updated
branch.
- Token gates, brand asset validation, module boundaries, and migration
ordering pass.
- Cloud tests verify global skill exclusion, authorized task/run
delivery, unassigned agents, disabled connections, revocation, adapter
isolation, and secret exclusion. The existing AgentMail connector
assignment test also passes.
- Migration replay runs twice against existing browser work and
financial records. It preserves the records and avoids duplicate costs.
- The focused provider, app catalog, OpenAPI, connection gateway, and
migration regression suites pass. Recovery coverage includes lost
replies, process crashes, provider rejection, and browser arrival
acknowledgement.
- All 54 checks pass on `2974b5f03641ad0cea3c941d8c02579316fa8c92`,
including the full test matrix, browser E2E shards, build, typecheck,
security, and release canary. Two optional Storybook jobs are skipped.
- Greptile is 5/5 on the same commit, with zero unresolved review
threads. The corrected review uses the actual master-to-head diff.
- The local `pnpm test:run` started and was stopped after the full CI
matrix passed. It did not complete locally; the full-suite result above
comes from CI.
- Earlier live acceptance used an isolated company with a capped
provider credential. The agent opened paperclip.ing, the embedded viewer
accepted navigation, and the same browser stayed available after
completion and tab switches.
- The local Storybook build passes. Stories cover the panel, footer,
feed entries, settings, lifecycle failures, and viewport modes with an
offline viewer fixture.

## Risks

- Browser Use charges for hosted work. Provider caps and local budget
checks reduce exposure; reported costs can arrive after work completes.
- Viewer and CDP URLs grant access to the browser. The server validates
and restricts them. They are excluded from agent results and durable
event data.
- Runtime resizing of v4 agent browsers uses a provider option confirmed
by live testing but absent from its published agent schema. Resizing
during a click may invalidate coordinates. Fixed presets remain
available.
- Viewport ownership is process-local and resets on restart. The
lifecycle and accounting records remain in the database.
- The original intermittent embedded-viewer stall has not been fully
diagnosed. A bounded reconnect and active-session recovery cover the
observed failure paths.
- Live tests did not cover every revocation, approval, rate-limit, or
restart case. Deterministic integration tests cover those paths. Passkey
forwarding is not claimed.
- Unknown create outcomes keep the credential available for cleanup.
Run-list absence cannot prove a paid POST was rejected, so recovery
stays pending until it can identify provider work.

## Model Used

OpenAI Codex, GPT-6. Used reasoning, repository search, code execution,
browser interaction, and test tools. The exact serving model ID and
context-window size were 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-09-30 07:13:16 -05:00
DottaandPaperclip 2f6fa3b6dc fix: recover provider authentication inside tasks (#14629)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Agents need a working model provider connection to run a task.
> - A provider can reject a stored credential after the task starts.
> - The failed run must ask the responsible user to repair that
connection.
> - This pull request adds that request directly to the task and reuses
Connections sign-in.
> - The user can choose an API key or subscription, then continue the
task with a fresh session.

## Linked Issues or Issue Description

**What happened?**

A run that ended with `acpx_auth_required` or another known provider
authentication error did not immediately offer an inline way to connect
the provider. A repair form could also lock the user to the failed
account's sign-in method.

**Expected behavior**

Show a provider connection card in the task as soon as the
authentication failure is saved. Allow the responsible user to connect
or repair the provider with any supported sign-in method. Keep the
connection name automatic and resume the task after successful setup.

**Steps to reproduce**

1. Run a task with a supported provider and an expired or invalid
credential.
2. Let the run fail with a provider authentication error.
3. Open the task and attempt to repair the connection.

Related work: Refs #13724 and #13726. This change adds the inline task
repair flow and method choice.

## What Changed

- Classify provider authentication failures and create one connection
request for the current task. A persisted blocked classification
suppresses automatic retries only after the repair card is created;
unsupported providers retain their existing recovery path.
- Mark only the attributed, unchanged credential as needing sign-in.
Preserve credentials that were refreshed after the failed run started.
- Reuse the provider sign-in controls inside the task. Allow API key and
subscription choices for Claude, Codex, and Grok. Keep names hidden and
generate a default from the user, provider, and method.
- Keep the existing account when reconnecting with the same method.
Create and select another account when the method changes. Validate
updates to explicit agent bindings through the normal agent save path.
- Require explicit adoption for legacy agent authentication. Validate in
the agent environment, then commit the binding, connection install,
audit, and card completion in one transaction. Keep failed setup and
account selection visible and retryable.
- Add regression tests and update the specification and Connections
documentation.

## Verification

- Fresh local verification: 199 tests passed across the inline form,
provider method selector, default naming, authentication and recovery
classifiers, run liveness, OpenAPI routes, database adoption/rollback,
and Cursor execution suites. The adoption database suite also passed
against disposable Docker PostgreSQL.
- Full repository `pnpm build` and `pnpm -r typecheck` passed on the
latest commit. Token gates are clean.
- Embedded browser: opened real task cards from seeded authentication
failures; switched Claude from API key to subscription and back;
switched Codex from subscription to API key; confirmed the name field
stays hidden. Provider sign-in was not completed with real credentials.
- The broad local `pnpm test:run` started before review fixes and was
interrupted after the working tree changed; it is not counted as a
passing full run. Fresh focused tests passed. CI supplies the full test
and browser suite results for the current commit.
- CI is green on commit `4b97a4e447045ff3d7516525a187a5d1d21e0d4c`: 54
checks passed and two Storybook checks were skipped by their path rules.
The workspace preview job passed on one rerun after a local-server
startup timeout; its rerun passed 835 tests.
- Greptile is 5/5 on the same commit with no actionable findings and no
unresolved review threads.

## Risks

- Incorrect authentication classification could prompt for a connection
unnecessarily. Tests exclude tool authorization, quota, and unrelated
runtime failures.
- A method change selects the new personal provider default, which also
applies to other agents that use that user's default. Explicit account
bindings use the existing permission and runtime validation path.
- Credential invalidation must not race with refresh or reconnect. The
code compares the saved credential generation and grant update time
under locks.
- No database migration or new credential storage format is required.

## Model Used

OpenAI GPT-6 through Codex. The exact model ID and context window size
were not exposed in this session. Capabilities used: reasoning,
repository editing, shell commands, database tests, and embedded-browser
interaction.

## 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 (focused tests listed
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-09-30 06:39:37 -05:00
Devin Foley f38b5693f6 fix: always enable keyboard shortcuts (#14643)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - The web UI has keyboard shortcuts for the inbox, task lists, cases,
and task detail, plus global shortcuts such as `c`, `/`, `?`, `[`, and
`]`
> - Shortcut enablement was an instance-wide General setting until
#14141 moved it to a per-user preference that defaults to off
> - The move did not carry the old instance value over, so every
existing user lost shortcuts on upgrade and had to find a new toggle
under Profile settings
> - A toggle that only turns off a standard, input-safe feature costs a
setting, a database column, two API routes, and a React context for
little benefit
> - This pull request removes both the instance setting and the personal
preference and enables keyboard shortcuts for every signed-in user
> - The benefit is one less thing to configure, no silent loss of
shortcuts on upgrade, and less code to maintain

## Linked Issues or Issue Description

Refs #14141 (the change that introduced the personal preference).

**What existing behavior does this improve?**

Keyboard shortcuts in the web UI stay off unless each user turns them on
in Profile settings.

**Subsystem affected**

Web UI shortcuts, Profile settings, instance general settings, the
`/api/auth/preferences` routes, and the `user` table.

**Current behavior**

Shortcuts default to off per user. #14141 moved the toggle from Instance
settings → General to Profile settings and did not carry the old
instance value over. Users who had shortcuts on lost them after the
upgrade and had to find the new toggle.

**Proposed behavior**

Keyboard shortcuts are always enabled for every signed-in user. There is
no instance setting and no personal preference. Shortcuts already ignore
key presses inside text inputs and modal dialogs, so an opt-out is not
needed.

**Reason and benefit**

Fewer settings, no silent loss of shortcuts on upgrade, and removal of a
database column, two API routes, a query hook, and a React context that
existed only to gate this feature.

**Breaking changes**

`GET` and `PATCH /api/auth/preferences` are removed. `PATCH
/api/instance/settings/general` no longer accepts `keyboardShortcuts`;
that schema is strict, so the key now returns 400.
`instance.general.keyboardShortcuts` is no longer a valid
`PAPERCLIP_HIDDEN_SETTINGS` key; the parser ignores unknown keys with a
warning.

## What Changed

- Removed the Keyboard shortcuts section from Profile settings, the
`useUserPreferences` hook, `queryKeys.auth.preferences`, and
`authApi.getPreferences` / `authApi.updatePreferences`.
- Removed `GeneralSettingsContext`. The inbox, legacy inbox, task list,
legacy task list, cases, and task detail pages no longer gate their key
handlers.
- Removed the `enabled` option from `useKeyboardShortcuts`. The app
shell always registers the global shortcuts.
- Removed `GET` and `PATCH /api/auth/preferences`, their OpenAPI
entries, and the `currentUserPreferencesSchema` /
`updateCurrentUserPreferencesSchema` validators.
- Removed `keyboardShortcuts` from `InstanceGeneralSettings`, the
general settings zod schema, the settings service defaults, and
`HIDEABLE_GENERAL_SECTIONS`.
- Added migration `0289_drop_user_keyboard_shortcuts`, which drops
`user.keyboard_shortcuts`.
- Updated `AGENTS.md`, `doc/SPEC.md`, `doc/SPEC-implementation.md`, and
`docs/deploy/environment-variables.md`.
- Parsed the stored general settings row with
`instanceGeneralSettingsSchema.strip()` in the feedback vote path, so a
retired key left in the row cannot reset the sharing preference to
`prompt` and overwrite the stored choice.
- Kept every bare global shortcut (`c`, `?`, `[`, `]`, `/`) out of open
modal dialogs in `useKeyboardShortcuts`; only `/` had that guard before.
- Updated the affected tests and added a Profile settings test that
asserts the toggle is gone, a hook test for the modal dialog guard, and
a feedback service regression test for the retired-key case.

## Verification

- Typecheck passes for `@paperclipai/shared`, `@paperclipai/db`
(including the migration numbering and safety checks),
`@paperclipai/server`, and `ui`.
- `pnpm exec vitest run
server/src/__tests__/instance-settings-routes.test.ts
server/src/__tests__/openapi-routes.test.ts
server/src/__tests__/auth-routes.test.ts
server/src/__tests__/sentry.test.ts` → 119 passed.
- `pnpm exec vitest run ui/src/components/Layout.test.tsx
ui/src/pages/ProfileSettings.test.tsx ui/src/pages/IssueDetail.test.tsx
ui/src/pages/Inbox.test.tsx ui/src/pages/Cases.test.tsx
ui/src/hooks/useKeyboardShortcuts.test.tsx ui/src/pages/Agents.test.tsx
ui/src/pages/InstanceGeneralSettings.test.tsx` → 286 passed.
- `pnpm exec vitest run packages/shared/src/settings-visibility.test.ts`
→ 16 passed.
- `pnpm exec vitest run ui/src/hooks/useKeyboardShortcuts.test.tsx` → 7
passed.
- `pnpm exec vitest run server/src/__tests__/feedback-service.test.ts`
(embedded Postgres) → the new retired-key test passes with the fix and
fails without it.
- Manual: sign in with no settings changed, open the inbox, press `j`
and `k` to move the selection, press `?` to open the cheatsheet. Open
Settings → Profile and confirm there is no Keyboard shortcuts section.

## Risks

- The migration drops a column. It uses `DROP COLUMN IF EXISTS`, and the
column has no readers after this change. If you roll back to a build
from before this PR after the migration has run, re-add the column
first: `ALTER TABLE "user" ADD COLUMN "keyboard_shortcuts" boolean
DEFAULT false NOT NULL;`. The older build's ORM selects that column when
it loads users.
- Any external client that still sends `keyboardShortcuts` to `PATCH
/api/instance/settings/general` receives a 400. No in-repo client does.
- Stored `instance_settings.general.keyboardShortcuts` values are
stripped on read and ignored.
- Users who never turned the toggle on now get shortcuts. The handlers
skip text inputs, contenteditable regions, and modal dialogs, so typing
is unaffected.

## Model Used

Claude Fable 5.1 (`claude-fable-5-1`) in Claude Code, with extended
thinking and tool use.

## 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
2026-09-29 21:28:06 -07:00
Devin FoleyandPaperclip 0b12ca9532 fix(server): retain context for unconfirmed adapter stops (#14639)
## Thinking Path

> - Paperclip must keep ownership of work until termination is verified.
> - A Stop request waits for the adapter and its cleanup to settle.
> - After 60 seconds, an unconfirmed Stop raises an error.
> - The error currently lacks run, adapter, and runtime context.
> - This makes it difficult to investigate which stop path is stuck.
> - This change adds bounded diagnostics while preserving termination
checks.

## Linked Issues or Issue Description

**What happened?**

An adapter can remain unsettled after its Stop request. The resulting
error says termination is unverified but does not identify the adapter
or run in error monitoring. The optional Sentry setup does not capture
request context, so the endpoint alone cannot fill the gap.

**Expected behavior**

Keep the Stop unconfirmed and preserve its live execution owner. When
optional Sentry is enabled, attach enough bounded context to investigate
the affected run.

**Steps to reproduce**

1. Register an adapter execution control and abort its controller.
2. Leave its settlement promise pending.
3. Wait for the configured Stop timeout.
4. Observe that Stop still fails, but the event now includes the run
UUID, built-in adapter, native/legacy runtime, timeout duration, and
abort-requested flag.

**Paperclip version or commit**

Master commit `17780751551b3bc1c2521f7694026c34534c46c9`; reproduced
with fake timers and mocked optional error monitoring.

**Deployment mode**

Server execution control, including local and hosted runs. Reporting
remains opt-in.

Searched related Stop PRs. #14523 and #14244 address Hermes cancellation
contracts; this change only adds diagnostics to the shared
unconfirmed-stop timeout.

## What Changed

- Use a typed timeout error with the existing message, name, and timer
stack.
- Pass run/adapter/runtime identity from the cancellation owner.
- Add an event-local, allowlisted Sentry context without changing the
default fingerprint.
- Rebuild the reported exception so arbitrary provider fields cannot be
serialized.
- Test timeout ownership, delayed settlement, privacy boundaries, and
absence of context on unrelated events.
- Document the additional opt-in fields.

## Verification

- `pnpm exec vitest run
server/src/services/adapter-execution-control.test.ts
server/src/__tests__/sentry.test.ts`: 38 passed, five real-SDK checks
skipped because the optional package is not installed.
- `pnpm -r typecheck` passed; server typecheck passed again after the
SDK test addition.
- With audited optional `@sentry/node@10.71.0` installed only in local
test dependencies, `PAPERCLIP_REQUIRE_SENTRY_TEST_SDK=1 pnpm exec vitest
run server/src/__tests__/run-failure-sentry-real-sdk.test.ts
server/src/services/adapter-execution-control.test.ts
server/src/__tests__/sentry.test.ts`: all 45 tests passed. The real SDK
uses an in-memory transport; no Sentry requests are sent.
- The broad local `pnpm test:run` command did not complete in the
available verification window and was stopped; no full local-suite pass
is claimed. `pnpm build` passed. All sharded GitHub CI checks passed on
the final PR head.
- Tests use fake timers and a mocked Sentry package; no provider or
monitoring requests.

## Risks

This is diagnostic coverage, not a claim that the underlying stop delay
is fixed. Unknown adapter/runtime values become `unknown`; malformed run
identifiers become `null`. No stop reason, prompt, output, provider
response, credentials, or arbitrary error properties are sent. Timeout,
cancellation acknowledgement, live-owner retention, and retry behavior
remain unchanged. No schema changes.

## Model Used

OpenAI Codex (GPT-6), with reasoning, repository inspection, and command
execution. The session does not expose a more specific 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 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 the targeted tests locally and they pass; full checks
are in progress
- [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-09-29 16:38:02 -07:00
DottaandPaperclip 1778075155 fix(server): continue unfinished tasks after status replies (#14626)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Native runs report their task outcome through a structured finish
result.
> - A Board comment can permit a passive wait for the next response.
> - That exception accepted reports that also admitted blocking
unfinished work.
> - The task then stayed In Progress without a runner, and recovery
treated the wait as healthy.
> - This pull request rejects that contradiction and uses the existing
bounded continuation path.
> - Real wait conditions and protection against obsolete requests remain
in force.

## Linked Issues or Issue Description

**What happened?**

An agent answered a status inquiry with `yielded` and `response_wake`.
The same result listed blocking remaining work. The server accepted an
indefinite wait without a question, approval, dependency, or pause. No
further run was queued.

**Expected behavior**

Unfinished ordinary tasks must continue or have a recorded reason to
wait. A status reply alone must not suspend the work.

**Steps to reproduce**

1. Add a Board status inquiry to an unfinished assigned task.
2. Submit a successful native result with `yielded`, `response_wake`,
and `remainingWork[].blocksCompletion: true`.
3. Leave the task without any real wait condition.
4. Observe that the old policy preserves In Progress with no
continuation and suppresses recovery.

**Paperclip version or commit**

Reproduced in the native status policy at `da887ea3e`. The branch is
based on current master.

**Deployment mode**

Authenticated server with the native Paperclip Runner.

Related work: Refs #13338 (native response waits and recovery). Refs
#12071 (separate legacy recovery and retry-state work). This change
fixes the native unfinished-response-wait exception.

## What Changed

- Reject contradictory finish reports while the provider can still
correct them.
- Route accepted unfinished response waits through the existing
one-follow-up continuation budget. Repeated incomplete results create a
visible recovery action.
- Preserve questions, approvals, dependencies, pauses, conversation
lifecycles, and superseded Board requests.
- Recheck the current Board source in the decision transaction before
queuing repair.
- Let normal recovery reconsider old committed waits that report
blocking work and still have a current source.
- Add policy and database regression tests. Document the rule.

## Verification

- `pnpm exec vitest run
server/src/services/native-runtime/status-arbiter.test.ts
server/src/__tests__/heartbeat-process-recovery.test.ts
--no-file-parallelism`: 346 tests passed, no skips.
- `pnpm -r typecheck`: passed.
- `pnpm build`: passed.
- `git diff --check origin/master...HEAD`: passed.
- Final head `8f0824d9bb4d631f2347f8afffe5fff6d574cb69`: all CI checks
green (54 passed, 2 intentionally skipped), including all general tests,
serialized server suites, runner tests, eight E2E shards, and the canary
dry run.
- Greptile: 5/5 on the final head, with no unresolved review threads.
- The broad local `pnpm test:run` encountered an unrelated timing
failure in `workspace-runtime.test.ts` (waiting for managed process-tree
listeners). That test passed on an isolated rerun. The duplicate broad
run was stopped; the complete CI suite passed on the final commit.
- The transaction-race regression reproduced an obsolete continuation
before the fix. All 12 source-change cases now pass, covering passive
waits, corrective continuations, and exhausted-repair decisions.

## Risks

- Agents that previously parked unfinished ordinary tasks must now
continue or record an actual wait condition.
- Old contradictory waits become eligible for normal recovery. Existing
ownership, budget, pause, and supersession checks still apply.
- The rule uses the structured blocking-work flag. It does not infer
omitted work from prose.
- No schema, dependency, or UI change.

## Model Used

OpenAI GPT-6 through Codex, with reasoning, repository inspection, code
editing, and test execution. The session does not expose a more specific
deployment identifier 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-09-29 16:51:50 -05:00
DottaandPaperclip b3eb03fcba fix(sentry): preserve run failure stacks and diagnostic context (#14585)
Builds on merged #14575 and targets `master`.

## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Operators use optional Sentry reports to diagnose failed agent runs.
> - The shared reporter currently converts each saved error message into
a new exception.
> - This loses the original stack and cause chain, and omits available
adapter and provider diagnostics.
> - This pull request selects, redacts, and bounds useful diagnostics
before it sends them to Sentry.
> - Operators can locate the failing operation and correlate upstream
failures without copying arbitrary run data.

## Linked Issues or Issue Description

Refs #14573. That change preserves ACP provider failure details in the
run record.
Refs #14575. That merged PR adds recorded exit codes and signals. This
PR covers stacks, causes, and structured diagnostics without duplicating
those fields.

A thrown setup or adapter error currently appears in Sentry with the
reporter's stack. A saved provider failure can contain useful details
that never reach the Sentry event. Both cases use the same shared
reporting path.

## What Changed

- Pass caught setup and execution exceptions, and structured adapter
error metadata, through successful terminal status transitions.
- Snapshot a fixed set of execution, adapter, provider, and exception
fields. Preserve up to four exceptions in the cause chain.
- Remove registered secret values, declared runtime environment
credentials, unknown inherited environment values and encoded credential
forms, and credential patterns before truncation. Mark truncated fields
and bound provider details and stacks.
- Rebuild sanitized Sentry exceptions with the original stacks and
causes. Use an adapter stack preview when available. Omit a fabricated
reporting stack when the source has no stack.
- Keep contexts local to each event. Preserve the optional DSN gate and
existing error-code/adapter fingerprint.
- Document the fields, limits, and omitted data.
- Settle leftover chat fixture outbox rows only after assertions and
worker shutdown, so subsequent tests cannot claim earlier cases’ pending
actions or provider I/O. This fixes the CI shard contamination exposed
during verification; production chat behavior and test timeouts are
unchanged.

## Verification

- `pnpm -r typecheck` passed.
- `pnpm build` passed.
- 86 focused diagnostic, Sentry, and startup tests passed after the
rebase, including the real `@sentry/node@10.71.0` SDK with an in-memory
transport.
- Tests cover cause chains, HTTP status and request IDs, long provider
details, secret redaction, failed secret resolution, cyclic causes, size
limits, and context isolation.
- Five targeted heartbeat integration cases passed, including thrown and
returned errors containing an opaque environment-bound credential. The
earlier full heartbeat integration run also passed its integration
cases.
- The focused suite also passed with an unknown inherited environment
value set to `1`; reporting tests use a controlled environment and
separately verify short-secret redaction.
- Before the fixture cleanup, the full chat shard reproduced the CI
Telegram timeout at `pending recovery before restart` (354 passed, 1
failed). After the cleanup, the same shard passed all 355 tests. No
timeout or production behavior changed.
- Latest-head CI (`0ae9e70df321d66dda025c3a7ba4787e169e0a4f`) passed
typecheck, build, all 12 server shards, all 3 chat shards, workspace and
serialized suites, browser shards, Runner checks, canary validation, the
real Sentry SDK contract, and security checks. Required `ci / verify`
and `ci / e2e` passed.
- The branch has been rebased onto `master` after #14575 merged. All 55
applicable checks passed on this head (2 unrelated Storybook checks
skipped). Greptile re-reviewed the current 11-file diff at 5/5 with no
findings or unresolved review threads.
- Local monolithic full-suite attempts were interrupted to apply fixes;
full-suite success is not claimed from those runs.

## Risks

- Error messages and stacks can contain credentials. The reporter uses
existing redactors and the run's encrypted secret registry, reads only
known fields, and skips capture if registered-secret resolution fails.
- Unknown environment values remain private by default. Unrecognized
short values can mask benign matches; known public settings are
explicitly allowed.
- Diagnostic text is bounded and can be truncated. Truncation is
explicit. Data discarded upstream cannot be recovered.
- These additional fields go to the operator's configured Sentry
endpoint. Arbitrary request/response objects, headers, configuration,
prompts, and stdout/stderr are not copied.

## Model Used

OpenAI GPT-6 through Codex, with tool use and code execution. The exact
serving model ID, context window, and configured reasoning level 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-09-29 12:54:12 -05:00
DottaandPaperclip 2de43fc909 fix(issues): keep agent mentions as context and defer personal app authorization (#14577)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Each task has one assignee. Explicit assignment and review requests
select who should act.
> - An agent mention started another agent on a task it did not own.
Native attachment staging then rejected that run.
> - Allowing that run through startup could also let two agents work on
the same task.
> - Mentions should identify relevant context. They should not start
work or forward comments to other tasks.
> - A personal app installed on a shared agent must also wait until tool
use to resolve the current user's grant.
> - This pull request removes mention dispatch and keeps missing
personal app credentials from blocking startup.

## Linked Issues or Issue Description

**What happened?**

A native agent mentioned on another agent's task failed with
`paperclip_runner_attachment_staging_not_authorized`. The source task
could already be complete. A nearby optional-app warning was a separate
problem: personal app tools were excluded when their shared health state
required attention.

**Expected behavior**

An agent mention is context only. It does not wake the agent, take
ownership, or copy a comment onto another task. Normal feedback still
reaches the assignee. Assignment and explicit review requests still
dispatch work. An unavailable personal app does not block startup or
produce a startup warning. Tool use requests the current user's
authorization and never uses another user's grant.

**Steps to reproduce**

1. Assign a task to agent A. Post a comment that mentions agent B,
including a comment that closes A's task or references B's child task.
2. Confirm the comment retains its agent link and B receives no run or
deferred wake. A can still receive normal feedback.
3. Install an active personal MCP connection on B. Give only Alice a
grant and leave shared health at `error`.
4. Explicitly assign work to B for another user. Confirm it can finish
without using the app.
5. Ask B to use the app. Confirm its tool call shows an inline
connection request for the current user.

Related work: Refs #11144. This change uses the existing execution-time
personal grant resolution.

## What Changed

- Remove mention dispatch from standalone comments and issue updates.
Remove implicit forwarding of parent comments to a mentioned worker's
child task.
- Ignore new requests with the legacy mention wake reason before
creating a run or deferred request. Preserve already accepted queue
entries, which can combine assignments and feedback with a later
mention.
- Remove the native mention admission, staging, and finalization
exceptions from this PR. Native task ownership checks remain intact.
- Keep active, installed personal app tools available despite shared
health errors. Remove optional-app startup warnings. Tool execution
retains the current user's grant and policy checks.
- Update agent instructions and product/API docs. Refresh generated
capability source anchors.

## Verification

- Red: comment-route regressions reproduced extra agent wakes and child
comment forwarding. A separate regression proved that cancelling by the
last coalesced reason could drop an accepted assignment.
- Green: the targeted route, wake queue, heartbeat, workspace,
responsible-user, MCP discovery, and HTTP gateway suites passed. The
final queue and heartbeat rerun passed 104 tests, the restored queue
adapter passed 56, and both comment-route suites passed 135. These
include accepted assignment preservation, rejection of new mention
requests, and normal assignee feedback.
- `pnpm -r typecheck` and `pnpm build` passed locally. The full local
`pnpm test:run` attempt was interrupted for review/CI fixes, so it is
not claimed as a completed local pass. It exposed a cleanup timing race
in the concurrent-mention assertion, now fixed and verified across 10
repetitions. CI also exposed an obsolete test waiting for the removed
mention lookup; it was reproduced and fixed, then both comment suites
passed. Final full-suite verification is through CI.
- Final head `bd9ea4cb05a8f081c54e017760a8999f9ea6ef44`: 54 checks
passed, 2 Storybook checks intentionally skipped; no pending or failing
checks. Full CI includes general and serialized suites, all 8 browser
shards, runner verification, typecheck, build, and canary dry run.
Greptile is 5/5 on this exact commit, with no unresolved findings.
- One unchanged Cursor adapter test hit its 10-second CI timeout. All 5
tests in that file passed locally; one retry of its CI shard passed all
674 tests (3 skipped). The aggregate verification gate then passed. No
code or timeout was changed for that retry.
- Live browser check: inserted a structured mention with the picker on a
human-owned task. The saved link remained visible. Database checks found
zero new runs and zero wake requests.
- Live Codex runner check: explicitly assigned that task with the
unavailable personal app attached. The run succeeded and committed
completion without using the app or creating a connection card.
- Live browser follow-up: asked the assignee to call PostHog and
mentioned another enabled agent as context. Only the assignee ran. It
succeeded and displayed the existing inline connection card. Only
Alice's grant existed; the run belonged to a different user.
- The HTTP regression covers tool discovery with no provider calls or
connection cards, first use returning the current user's authorization
request, and successful retry after that user's grant exists.
- App checks use an isolated local fixture and a fake MCP provider. They
do not use production app credentials.

## Risks

- Intentional behavior change: workflows that used mentions to wake
agents must use assignment, a bounded child task, or an explicit review
request.
- Already accepted queue entries retain their prior rules. An old entry
can combine assignment or feedback with a later mention; its last reason
cannot safely identify mention-only work. New mention requests create no
run or deferred wake.
- Personal apps with a shared health error remain discoverable. Actual
tool use still requires the responsible user's grant and existing policy
gates.
- No database migration or public API schema change.

## Model Used

- OpenAI GPT-6 through Codex, with reasoning, repository tools, code
execution, and browser testing. The exact serving model ID and
context-window size are not exposed in this session.
- Live native-run verification used `gpt-6-astra` through the Codex
provider.

## 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-09-29 12:49:01 -05:00
Devin FoleyandPaperclip e5bf9d49a5 fix(sentry): retain recorded process exit details (#14575)
## Thinking Path

> - Paperclip manages agents and records their task runs.
> - Operators can enable Sentry reports for terminal run failures.
> - A failed adapter can leave only the generic message “Adapter
failed.”
> - The run already records a process exit code and signal, but the
report omits them.
> - This pull request carries those two values through a strict capture
boundary.
> - Operators can distinguish a nonzero exit from signal termination
when the message is generic.

## Linked Issues or Issue Description

**What happened?**
A failed run can store `exitCode: 1` or `signal: "SIGTERM"` while its
Sentry event contains only `adapter_failed` and “Adapter failed.” The
existing reporter drops both recorded fields. This occurs on the current
master reporting path.

**Expected behavior**
The opt-in report preserves bounded process exit evidence without
exporting adapter output or changing run behavior.

**Steps to reproduce**
Enable the backend Sentry DSN and report a failed run whose message is
“Adapter failed” and whose stored signal is `SIGTERM`. Before this
change, the event has no signal field. After this change,
`run_failure.signal` is `SIGTERM` and the existing fingerprint stays the
same.

Related: #12105 and #8222 describe missing adapter/HTTP failure details.
#13152 changes terminal-result cleanup classification, and #12886 adds
process-failure classification and runtime URL checks. None forwards
these stored fields through the Sentry reporter. This change does not
resolve those broader issues.

## What Changed

- Forward the stored exit code and signal from the terminal run
reporter.
- Accept only signed 32-bit integer exit codes; use `null` for missing
or malformed values.
- Accept only the reporting host's Node signal constants; use `null` for
missing values and `unknown` for unrecognized values.
- Keep the added fields in event-local context, outside tags and
fingerprints.
- Cover database-backed reporting, malformed input, privacy, and
isolation through the real Sentry SDK.
- Document the fields and their limits.
- Give the dedicated Sentry job the normal PR dependency-resolution
fallback, with lifecycle scripts disabled on every install and the
required real-SDK test retained.

## Verification

- Before the change: 16 report-shape/exit-field assertions failed in the
focused capture suite.
- After the change: 91 focused Sentry, DSN, and database-backed
reporting tests passed. The real SDK uses an in-memory transport.
- Final real-SDK test also passed with malformed metadata; it verifies
that arbitrary signal text is absent from captured events and unrelated
errors inherit no run context.
- `pnpm -r typecheck`: passed.
- `pnpm build`: passed.
- `pnpm test:run`: exited nonzero after 718 general-server files: 14,085
tests passed, 14 failed, 86 skipped. Thirteen skill-service/cache
failures reproduce on the unchanged base commit on this macOS host. One
comment-wake test timed out; the complete 29-test suite passes on the
unchanged base and in final-head Linux CI. Local isolated rechecks
skipped because embedded PostgreSQL could not start; these are not
counted as passes. The remaining local workspace/serialized lanes did
not run after the failing first lane; all CI lanes passed.
- Initial Sentry CI failed before tests with
`ERR_PNPM_LOCKFILE_CONFIG_MISMATCH`. Its install step lacked the normal
PR fallback. The repaired real-SDK job passed. Security review then
requested disabling lifecycle scripts for resolved dependencies; every
install now uses `--ignore-scripts`. A fresh isolated checkout passed
the exact script-disabled fallback and real-SDK contract. Final-head
real-SDK CI and the security scan passed.

- GitHub CI: all 54 checks passed on
`37e0a836e50660f7753d367bcf5a4959eaf89b90`, including required `ci /
verify` and `ci / e2e`; two unrelated checks skipped.
- Greptile: 5/5 on that commit. No unresolved review comments.
- Merge status: conflict-free; required CODEOWNER approval for the
workflow change is still pending.

## Risks

Low risk: this only adds two validated fields to existing opt-in error
reports. It changes no database schema, run status, retry, fingerprint,
or suppression rule. Process output and adapter result payloads remain
excluded. A recorded signal does not identify its sender or prove an
out-of-memory kill. Missing exit evidence stays unknown; this change
does not establish the cause of a historical generic adapter failure.

## Model Used

OpenAI GPT-6 (Codex), with reasoning, terminal tools, and 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)
- [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
ticket id or instance-derived details
- [x] I have run focused tests locally and they pass; broader validation
is 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-09-29 12:29:17 -05:00
DottaandPaperclip 83076d7e7c feat: return completed handoffs to Agent Chat (#14408)
Return completed Agent Chat handoffs through a durable outbox and scope each generated update to its supplied tasks. Add recovery, browser delivery, result access, and calibrated quality coverage.

Validated with two consecutive ten-case Claude/Codex campaigns, all CI checks, and a 5/5 review.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-09-29 10:25:52 -05:00
DottaandPaperclip 3b4b270650 fix(adapters): preserve ACP terminal failure diagnostics (#14573)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - The shared ACP adapter engine records agent failures for operators.
> - ACP providers can report a failure category, title, and detailed
cause.
> - Our patch kept only the category in the saved error, so an operator
could not diagnose a failure when tracing was off.
> - This pull request preserves redacted provider diagnostics in the run
error, transcript, and structured run result.
> - Operators can now inspect the provider message and any supplied
request ID or stack trace after the run ends.

## Linked Issues or Issue Description

Refs #13889 (the diagnostic gap; this PR does not update the bundled
Claude version).
Refs #14484 (related model-refusal classification; this PR retains
diagnostics for all terminal failure categories).

**What happened?**
An ACP turn failed with only `ACP agent reported a terminal service
failure.` The provider's title and details were available in memory but
absent from the saved error and transcript.

**Expected behavior**
The run retains useful provider diagnostics even when raw tracing is
disabled. Credentials remain redacted. A size limit must report
truncation instead of silently removing the cause.

**Steps to reproduce**
1. Run an ACP agent that returns an error-severity typed session
failure.
2. Include an HTTP error, request ID, and stack text in its title and
details.
3. Inspect the failed run with tracing disabled. Before this change,
only the category survives.

## What Changed

- Both pinned ACPX patches pass complete error text to the in-memory
callback, so redaction happens before truncation.
- The shared engine retains the sanitized category, title, and details
in `resultJson.terminalSessionFailure` and includes the text in the run
error and error transcript.
- Diagnostics redact configured environment values even under arbitrary
names, unknown launch-environment values, connection URL passwords, run
credentials, and common credential syntax. Known boolean settings remain
readable, while credential values are redacted even when embedded in
other text. Diagnostics remove control characters and invalid Unicode.
- Title and detail limits keep escaped transcript JSON below the
server's chunk limit. Truncated fields include an omission count. The
safe run-result projection preserves a byte-bounded diagnostic preview
when the result exceeds its byte budget, with an explicit pointer to the
full adapter-bounded run error and transcript.
- The existing UI and CLI display the error. Diagnostics do not become
assistant output. Issue continuation summaries and session-compaction
prompts receive only the generic category, preventing provider text from
becoming handoff instructions. Existing quota classification, warnings,
timeout precedence, and control-channel failure precedence remain in
place.
- Regression tests cover real ACP child processes with both pinned
versions in one-shot and persistent modes, credential redaction, request
IDs after the old 4 KiB cutoff, transcript parsing, storage bounds, and
database retrieval of oversized multibyte diagnostics.

## Verification

- Full CI on `20ad4f5f1f66c46d2c260e6ad0339cbea607b4cf`: **54 passed, 2
intentionally skipped, no pending or failing checks**. Includes
typechecking, build, all Vitest shards, Runner checks, browser E2E, and
the canary packaging/public-install dry run.
- Greptile: **5/5** on this commit. Superagent security scan passes. All
review threads are resolved.
- Local verification passed: shared ACP engine suite (395 tests); real
Claude ACP child-process and diagnostic regressions across both pinned
runtimes and both execution modes; run retrieval and model-handoff
regressions (59 tests); ACPX patch packaging (16 tests); full typecheck
and build. Affected package typechecks and focused tests were rerun
after review fixes.
- The broad local `pnpm test:run` was stopped after review edits made
its cached imports stale. Fresh targeted runs pass, including both
affected server suites. Cold-build import failures were also rerun after
dependency builds: chat integration (1,063 tests) and tool access (351
tests) pass. The final commit's complete CI matrix is green.

## Risks

- Provider diagnostic text is untrusted. This change retains more of it
in company-scoped run records. Redaction and size bounds apply before
persistence.
- Diagnostics are limited to fields the provider supplies. Old runs
cannot recover discarded error text.
- No schema migration, recovery-policy change, or new Telemetry or
OpenTelemetry export.

## Model Used

- OpenAI GPT-6 through Codex, with reasoning, repository inspection,
code editing, and test execution. 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-09-29 10:18:30 -05:00
da887ea3e9 fix(runner): honor Codex effort selected in composer (#14568)
## Thinking Path

> - Paperclip manages AI agents that work on assigned tasks.
> - The task composer lets a person choose an assignee, model, and
effort for the next run.
> - A Paperclip Runner agent can use Codex as its provider.
> - The composer hid Codex effort for that agent because it checked only
the older Codex adapter.
> - The native Runner input also did not carry an effort choice to
Codex.
> - This pull request carries the chosen effort from the composer to
each Codex turn.
> - People can now select a supported effort and get the effort they
selected.

## Linked Issues or Issue Description

Refs #14322

**What happened?**

The composer showed a model but no effort slider when the assignee used
Paperclip Runner with the Codex provider. A task-level model override
also did not reach the native Runner input.

**Expected behavior**

The composer shows effort choices for a known Codex model. The next
native Codex turn uses the selected model and effort.

**Steps to reproduce**

1. Open a task composer.
2. Select an agent that uses Paperclip Runner with the Codex provider.
3. Select a known Codex model such as `gpt-6-astra`.
4. Open the assignee and model picker. The effort slider is missing
before this change.

## What Changed

- Show known Codex effort levels for Paperclip Runner Codex assignees.
- Save the task effort override in the native run input and send it to
Codex on each turn.
- Apply the task's merged model and effort overrides when the native run
starts.
- Apply a task model override for OpenCode Runner without changing the
agent's provider.
- Add Runner effort tests and desktop and mobile Storybook cases.

## Verification

- `pnpm -r typecheck` passed.
- `pnpm build` passed.
- `pnpm build-storybook` passed.
- `pnpm check:token-gates` passed.
- Focused UI, server, Runner contract, and Codex driver tests passed.
- The full CI test matrix, build, typecheck, and canary dry run passed
on the latest head.

## Risks

- Native Runner inputs add an optional Codex effort field to the current
v5 input. Older inputs keep their previous behavior.
- A known model rejects an effort that its catalog does not support.
Unknown models do not show a slider.

> This fixes an existing composer bug. I checked `ROADMAP.md`; it does
not describe this bug as planned work.

## Model Used

OpenAI Codex, GPT-6. The exact deployment ID and context window are not
exposed in this session. The model used reasoning, code execution, and
repository 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>
Co-authored-by: OpenAI GPT-6 Astra <noreply@openai.com>
2026-09-29 09:41:05 -05:00
DottaandPaperclip 7636966452 fix(inbox): keep other users’ failed runs out of Mine (#14572)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - The Mine inbox shows work that needs the current user.
> - Failed-run rows used the latest run for every agent in the company.
> - A failure from another user therefore appeared in Mine and its
badge.
> - Run list responses also omitted the responsible user needed to
filter these rows.
> - This pull request uses run ownership for personal failure routing.
> - Users see their own failures and can still inspect company failures
in All.

## Linked Issues or Issue Description

**What happened?**

An agent run started for one user failed. Its row and failure badge
appeared in another user's Mine inbox.

**Expected behavior**

Mine and its badge include failed runs for the current responsible user.
Other users' failures remain available in All and run details.

**Steps to reproduce**

1. Use a company with two human users.
2. Create a failed or timed-out run attributed to the first user.
3. Open Mine as the second user. Before this fix, the failed run appears
there and increases the badge.

**Paperclip version or commit**

Reproduced in regression tests on master at `24beb0057`.

**Deployment mode**

Authenticated deployment with multiple users. Tests also cover the local
single-user board.

Related prior work: #933 addressed inbox dismissal and badge
consistency. No duplicate ownership fix was found.

## What Changed

- Return `responsibleUserId` in normal and summary run lists.
- Share one ownership rule across both inbox versions and client/server
badges.
- Select the latest run per agent before applying the ownership filter.
This prevents old failures from resurfacing on shared agents.
- Keep unattributed historical failures in the local board's Mine view.
Hide them from authenticated users with no matching owner.
- Keep company health alerts outside the personal badge, consistent with
the client.
- Document the routing contract and add page, badge, and database
regression coverage.

## Verification

- Red: the new badge cases failed with three company failures instead of
one personal failure; eight Mine page cases failed across both inbox
versions.
- Green: 113 focused tests pass in `ui/src/lib/inbox.test.ts`,
`ui/src/pages/Inbox.test.tsx`,
`server/src/__tests__/heartbeat-list.test.ts`, and
`server/src/__tests__/inbox-dismissals.test.ts`.
- `pnpm check:token-gates` passes.
- Agent calls on behalf of a user have two additional red-to-green API
regressions.
- Full `pnpm -r typecheck` and `pnpm build` pass. Server typecheck also
passes after the agent-call fix.
- All CI test shards and browser tests pass on `243bfa681`. The
duplicate local `pnpm test:run` was stopped after the CI test lanes
completed; it did not finish locally.

## Risks

- Authenticated users no longer receive unattributed legacy failures in
Mine. Those failures remain visible in All.
- The server badge no longer counts company health alerts, matching the
existing client badge.
- No migration, run state, retry behavior, or company access rules
change.

## Model Used

- OpenAI GPT-6 through Codex, with reasoning, terminal execution, and
browser tools. The exact deployment 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-09-29 09:40:21 -05:00
DottaandPaperclip 24beb00575 feat(runner): add rich ACP transport and durable interaction foundation (#14430)
Add shared rich ACP transport, durable questions and permissions, verified provider packaging, and bounded activity and plan presentation. Keep Cursor, Copilot, and Pi pending their separate provider qualification.

Persist interaction settlement before publication, fence failed writes until fresh recovery, and preserve owned-process cleanup. Incorporate reviewed mainline integration with extended harness coverage.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-09-29 08:56:21 -05:00
DottaandPaperclip c9b93d7e8c fix: preserve terminal task owners during release (#14561)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Tasks record an assigned owner and separate checkout and execution
locks.
> - A completed task must retain its owner after execution ends.
> - The release endpoint currently clears that owner when it clears the
locks.
> - This pull request preserves the assignee of Done and Cancelled tasks
during release.
> - Unfinished tasks keep the existing relinquishment behavior.
> - The benefit is stable task attribution without retaining execution
locks.

## Linked Issues or Issue Description

**What happened?**

An agent completed an assigned task, then called the release endpoint.
The task stayed Done, but its assignee became null. The same defect
affects Cancelled tasks. It caused the legacy Claude clarification/reuse
and multiple-repository handoff E2E assertions to fail.

**Expected behavior**

Release must clear execution locks on terminal tasks and preserve their
assignee, final status, and disposition timestamps. Release of
unfinished tasks must still clear the agent assignee. Only In Progress
work returns to Todo.

**Steps to reproduce**

1. Create an assigned task with checkout and execution locks.
2. Complete or cancel the task.
3. Call `POST /api/issues/:id/release` as the assigned agent.
4. Read the saved task. Before this fix, its assignee is null.

**Paperclip version or commit**

Reproduced on master commit `d172197117a14b80a1eb2d2835a0e7cce2679656`.

**Deployment mode**

Local tests against real PostgreSQL through the production issue routes
and services. This is a core lifecycle defect, independent of the agent
adapter.

Refs: #11689, #6899, #7769. These are related open release proposals.
This is an independent fix limited to terminal task ownership. It does
not include timer scheduling changes.

## What Changed

- Preserve the current assignee when releasing Done or Cancelled tasks.
- Keep all execution-lock cleanup and existing unfinished-task behavior.
- Cover all seven task statuses through the release API and read back
saved state.
- Check disposition timestamps, activity attribution, and repeated board
cleanup.
- Update the API contract, agent reference, and CLI help.

## Verification

- Red commit `ddaabb754`: the two terminal-owner regressions failed with
`assigneeAgentId: null`; 12 other route tests passed.
- Green: all 14 route tests pass, plus the existing successor-checkout
race test (15 selected tests total).
- Command: `pnpm --filter @paperclipai/server exec vitest run
src/__tests__/issue-stale-execution-lock-routes.test.ts
src/__tests__/issues-service.test.ts -t 'stale issue execution lock
routes|does not let stale release clobber a successor checkout lock'`.
- The local host has exhausted its SysV semaphore pool. The red/green
runs used the existing test-provider hook to start disposable Docker
PostgreSQL 17 instances. Routes, services, migrations, and assertions
were unchanged. No database tests in the selected set were skipped. The
other 134 tests were excluded by the name filter.
- Capability contract and inventory drift checks pass.
- `pnpm build` and `pnpm -r typecheck` pass.
- The local `pnpm test:run` was interrupted after environment failures
while the complete sharded CI suite ran in parallel: native PostgreSQL
bootstrap fails under the host semaphore limit, and the large Git
fixture hits macOS `ENAMETOOLONG`. A focused rerun confirmed these
happen before the relevant assertions. The interrupted local run is not
counted as a full pass.
- Greptile completed on `1caeeb827e9cb658ddb71f16c2421ec20f80634e` with
**5/5**, a successful check, and no review threads.
- All CI gates pass on the current head: typecheck, build, general and
serialized tests, Runner checks, browser E2E, release packaging, and
security checks. Server shard 11 passed on one targeted retry; the first
attempt had 836 passing tests but an unhandled workspace-runtime startup
rejection caused by an existing timing window. All other successful jobs
were reused.
- No paid provider evaluations were run.

## Risks

- A caller that used release to erase ownership from terminal work will
now retain that owner. An explicit assignment update or the board
force-release option with `clearAssignee=true` can still clear it.
- No schema or migration changes. The transaction, company access,
assignee/run checks, and activity log remain in place.

## Model Used

- OpenAI GPT-6 through Codex, with tool use, code execution, and test
debugging. The session does not expose a more specific backend model
version or context-window size.
- OpenAI `gpt-6-luna` assisted with read-only test discovery and review.

## 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-09-29 08:47:33 -05:00
DottaandFry 3ca196b0a6 feat(agents): persist agent files across tasks without revision history (#14420)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - An agent needs personal files across tasks and sessions.
> - AGENTS.md is one file in that directory. Supporting files need the
same persistence.
> - The Instructions Editor and agent runs must share one current
directory.
> - Concurrent runs should apply only the files they change. The last
sync of the same file wins.
> - This pull request uses existing file transport and removes temporary
copies after sync.
> - Old instruction-only sessions keep their restore contract. New saves
do not create revision history.

## Linked Issues or Issue Description

Refs #14325. This replaces its revision-oriented design with persistent
agent files. Keep #14325 unmerged.

Transport prerequisite #14416 merged first at
`d172197117a14b80a1eb2d2835a0e7cce2679656`. This PR now targets master
and remains below 100 changed files.

Related work: #4513 and #8798 cover instruction tooling. This change
handles run synchronization, cross-task personal files, browser editing,
and old-session restoration.

## What Changed

- Keep one current directory per company and agent. Point AGENT_HOME at
a temporary working copy for each active run. Keep task files and
provider HOME separate.
- Restore text, binary files, and nested folders through workspace
transport. Exclude remote agent files from task Git snapshots with a
self-ignoring file inside the reserved runtime directory; never write
through repository-controlled Git metadata.
- Collect after the provider and child processes have stopped. Keep
resumable conversation state.
- Apply changed and deleted files under the agent lock. The last sync
wins for the same file. Unrelated concurrent changes survive.
- Remove temporary copies after successful sync, rejected sync, and
staging failure. Register ownership before copying so restart recovery
can remove interrupted preparation. Retry transient synchronization up
to three times. Preserve the original remote lease reference until
deletion succeeds; restart cleanup never acquires a replacement sandbox.
Do not create captured directories or a conflict-review queue for new
runs.
- Keep browser editing, stale-draft protection, and streaming binary
downloads. Keep the instruction entry and text editor limited to 1 MiB.
- Keep historical agent-folder sync failures on their affected runs
instead of repeating them above current saved instructions. Preserve
legacy candidate review and current browser-save errors. Avoid duplicate
quota warnings while retaining separate sync failures when they describe
a different problem.
- Require target-scoped caller grants for peer instruction access, while
preserving self edits, responsible-user checks, and protected-change
consent.
- Treat full storage as a nonblocking run warning, never an agent pause
or run-admission failure. Restore already-over-quota saved folders so
ordinary agent cleanup can recover; warn on each run until cleanup. The
run detail view shows the warning.
- Allow 256 MiB per file, 2 GiB per directory, and 100,000 entries. Hash
large files as streams. Check editor-save quotas with metadata instead
of hashing unrelated files.
- Preserve old native inputs, instruction-only copies, paths, digests,
and pending legacy candidates. Adopt old revision heads once. New writes
do not append history rows.
- Add idempotent migration 0287 and verify upgrades from the preview
tables and receipts.
- Add nine interactive stories under **Agents / Persistent files**,
including automatic incoming edits, stale browser drafts, and
storage-limit diagnostics.

## Verification

- Merge candidate: `4f5390107ec6ffd80a76d1d2e85530e66f21d079`, after
merging current master and the landed transport prerequisite.
Integration required no manual conflict resolution; the feature remains
99 changed files. Full workspace typecheck, production build, token
gates, and 715 focused tests passed on this merge candidate. Fresh
Greptile review is 5/5 with no unresolved findings. All 55 checks
passed, with four conditional skips, including the build, typecheck,
browser E2E, and canary dry run. A single retry recovered four jobs
interrupted by runner shutdowns; no source changes were required.
- Historical-warning UI fix: all 6,834 UI tests across 640 files passed,
including regression coverage for three old failures, legacy preserved
edits, and warnings scoped to the affected run. Full workspace
typecheck, production build, Storybook build, and token gates passed.
Browser-verified Storybook playtests passed for Historical Failures
After Successful Save, Storage Limit, and Full Storage Run Warning.
- Review follow-ups at `4e20c9fb2`: all 18 focused tests passed,
including external Git directories, linked worktrees, symlinks,
hardlinks, and distinct I/O failures alongside storage warnings. Server
and UI typechecks, token gates, and the production build passed.
- Storage warning regressions at `0724f3012`: all 33 directory tests and
all five heartbeat-list tests passed, with no skips in their successful
runs. They cover repeated runs while full, an already-over-quota saved
folder, cleanup, warnings retained after unrelated save failures, and
bounded warnings in large result JSON. Server typecheck passed after the
final warning fixes.
- Full workspace typecheck, production build, and token gates passed
during this follow-up. Product E2E harness: 631 tests passed across 52
files; harness typecheck passed. Earlier native session/context and
directory/legacy collection suites passed 537 tests; Runner
unit/transport suites passed 329 tests.
- **Real E2E at `0724f3012` (before this follow-up):** legacy local
Codex and native Daytona Codex each passed six tasks, one server
restart, seven independent assertions, and cleanup verification. Both
prove browser-to-agent edits, agent-to-browser edits, nested/binary
restoration, per-file last-sync-wins, a successful run after an
oversized save rejection, and cleanup clearing the warning.
- Native local Codex also passed the six-task quota flow before the
final warning-retention fixes. That pass began at `918d1ed02` while the
bounded-result warning fix was being edited, so it is not claimed as
exact-final-head evidence. Its final-head rerun failed during embedded
PostgreSQL bootstrap before any provider run: the macOS host had 87,365
of 87,381 SysV semaphores occupied. No unrelated services or kernel
limits were changed.
- The final-source report intentionally records **2/3 cells passed**,
preserving the blocked native-local attempt:
`tests/runner-e2e/results/agent-files-quota-final-20260928-report/`.
Earlier failed attempts and provenance notes remain under
`tests/runner-e2e/results/agent-files-quota-final-20260928-input/` and
the original campaign directories.
- Daytona used immutable image
`ghcr.io/paperclipai/paperclip-daytona-runner@sha256:5643f0d801417cae3581833a1a3bc6715b325e028602738d2652c44cac5dc6bf`
and its exact Linux runner binary. Controller source is `0724f3012`;
image source is recorded separately.
- Legacy-session compatibility and all three ACP Stop/resume browser
regressions passed on the prior validated feature head
`169fab46d5af21caa2269b4c1b29b69c933a6951`. They assert the same
provider session is retained and interrupted writes are not replayed.
Migration upgrade tests also passed earlier.
- Nine interactive stories are under **Agents / Persistent files**,
including **Full Storage Run Warning**. Its playtest and visual browser
inspection passed; the warning states that runs continue and the editor
remains available.
- Prior-head checks on `4e20c9fb2`: 55 passed, two conditional jobs
skipped, no failures or pending checks. All eight browser E2E shards and
their aggregate passed. Fresh Greptile review is 5/5 with no findings;
all review threads are resolved, the security scan passed, and GitHub
reports no merge conflicts.
- The broad local follow-up test run was interrupted after host
semaphore exhaustion affected isolated PostgreSQL instances. It also
encountered the existing macOS long-path fixture failure and two timeout
failures. This is not a claim that the full local suite passed. Logs are
retained; focused storage/warning tests passed.

## Risks

- A later sync can overwrite an earlier edit to the same file, including
a saved browser edit. There is no text merge or retained version. This
is the intended last-sync-wins policy.
- A save that exceeds a storage limit is rejected and its temporary copy
is discarded. The run itself continues normally, and later runs restore
the last saved files with a warning until cleanup. Transient sync
failures get bounded retries. An I/O failure partway through a sync can
leave some files updated; a failed receipt does not claim whole-folder
success.
- Larger folders increase copy time, network traffic, and temporary disk
usage. Active runs still need working copies. Terminal runs do not
accumulate archives. Operators must provision disk for agents and
configured concurrency; these limits are not company-wide quotas.
- A restored old native session remains instruction-only until a fresh
session starts. Its original conflict fence and existing pending
candidates remain compatible.
- Provider processes close at the collection boundary. Conversation
resume remains available, but warm process reuse is lost.
- Backups must include the instance filesystem and database. External
bundles keep their existing behavior until explicitly moved to managed
storage.

## Model Used

OpenAI Codex, GPT-6 family. The session does not expose a more specific
model ID or context-window size. Reasoning, code execution, and browser
tools assisted this change. Real provider E2E uses `gpt-5.6-sol`.

## 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: Fry (Paperclip) <noreply@paperclip.ing>
2026-09-29 08:25:56 -05:00
Devin FoleyandPaperclip 53aad90b9e fix: retry sandbox ACP input delivery after gateway failures (#14485)
## Thinking Path

> - Paperclip coordinates agent work through execution adapters.
> - Sandbox ACP sessions send ordered input through a remote file queue.
> - A temporary provider 502 currently closes the session during an
input upload.
> - A lost response can occur after the sandbox has consumed the
message, so a blind retry can duplicate input.
> - This pull request retries gateway failures with the same sequence
and drops consumed sequences at the receiver.
> - The session can continue through a brief provider failure without
repeating a tool call.

## Linked Issues or Issue Description

**What happened?**

A sandbox ACP run can fail with `ACP agent disconnected during request
(connection_close, exit=null, signal=null)` when a provider input upload
returns HTTP 502. The bridge destroys its local socket on the first
failure and can discard the diagnostic before the proxy reads it.

**Expected behavior**

A temporary gateway failure should get a bounded retry. A lost response
after successful delivery must not duplicate input or reorder later
messages. Permanent failures must still close the session.

**Steps to reproduce**

1. Run the real sandbox process bridge with an echo child and a local
test runner.
2. Inject a provider 502 before preparation, after a chunk upload, or
after final publication and consumption.
3. Send the next input message. Before this change, the connection
closes instead of delivering it.

Searched open and closed PRs for `ACP disconnect`, `bridge retry`, and
`502 sandbox`. Related work: #13287 covers shutdown after bridge loss;
#13793 covers large launch envelopes. This change covers ordered input
delivery within a running legacy ACP session.

## What Changed

- Retry input uploads up to three times for recognized Daytona and
Cloudflare HTTP 502, 503, and 504 diagnostics, with 250 ms and 500 ms
delays.
- Give each upload separate temporary paths and discard already-consumed
input sequences, including late publication from an earlier attempt.
Clean failed attempts in the background without removing a published
message or another attempt’s files. Cleanup cannot delay retries or
shutdown.
- Keep later input behind the retry. Stop queued input on permanent
failure and flush a fixed diagnostic before closing the socket. Neither
failure-diagnostic persistence nor shutdown-warning persistence can
block teardown.
- Add real-process regression tests for lost responses, late
publication, retry exhaustion, immediate permanent failure, and
diagnostic redaction.
- Give accepted run-log file appends up to three seconds to drain before
finalization computes the size, hash, and durable copy. Close the run
handle to later appends. This waits only for file writes, independently
of later DB progress or live-event persistence. If writes remain
stalled, return null size/hash metadata and skip the final durable copy
so the run can settle. Late writes cannot restart mirroring.
- Preserve legacy comment attribution when final log size is unknown by
reading existing entries within the unchanged 2 MB scan limit. Storage
errors or a three-second read deadline return the evidence already read
instead of failing the comment listing; pagination stops at the
deadline. The deadline requests cancellation of the underlying local
stream or S3 HEAD, GET, and response stream. A separate response timeout
returns partial evidence even when filesystem I/O delays cancellation;
late reads cannot append evidence or start another page. Each listing
retains its existing batches of eight reads, without a shared admission
cap that skips readable logs under contention.
- Document the retry and log-finalization boundaries in the development
guide.

## Verification

- Final commit `347daa564b`: [Linux
CI](https://github.com/paperclipai/paperclip/actions/runs/36506995168/attempts/2)
passed. Greptile Apex review 13 scored this commit 5/5 with no new
findings; all 12 review threads are resolved.
- The final CI run initially hit a Cursor test timeout and four Discord
credential-lock contention failures. All five cases passed in isolation.
The two failed shards and their aggregate gate passed on retry without a
code change. Those intermittent failures are not claimed fixed by this
PR.
- `pnpm --filter @paperclipai/adapter-utils typecheck` passed.
- `pnpm exec vitest run
packages/adapter-utils/src/execution-target-stdin-race.test.ts
packages/adapter-utils/src/execution-target-sandbox.test.ts
packages/adapter-utils/src/sandbox-callback-bridge.test.ts`: 262 tests
passed on the final implementation, including 21 new regressions. The
original three fault-injection cases failed before the fix.
- The regressions cover failed and indefinitely stalled cleanup,
Cloudflare gateway responses and retry exhaustion, permanent errors that
must not retry, and teardown while failure logging remains indefinitely
stalled. Seven Apex regression cases failed before the review fixes.
Adapter-utils typecheck and build passed again after the final review
change.
- `pnpm exec vitest run server/src/services/run-log-store.test.ts
server/src/services/run-log-store-cancellation.test.ts`: all 25 tests
passed, including four new regressions that failed before the
finalization fix. They cover delayed and failed appends, late-write
admission, agreement between the local bytes/summary/durable copy, and a
stalled append that exhausts the three-second budget. The timeout case
verifies unknown metadata, no final upload, and no mirror restart after
late completion. New cancellation tests use the real AWS SDK against a
local HTTP server. They verify that stalled HEAD, GET, and response-body
connections close on abort and that a subsequent read succeeds. Local
range and already-aborted read cases also pass.
- `pnpm exec vitest run server/src/__tests__/issues-service.test.ts -t
'readIssueCommentRunLogText|deriveIssueCommentRunLogAttribution'`: 14
targeted tests passed. The null-size reader case, both storage-error
cases, the stalled-read case, and the cancellation/concurrent-listing
cases failed before their fixes. The new regressions verify that
timed-out reads are cancelled, subsequent listings recover, and two
concurrent listings both retain their attribution markers. A read that
ignores cancellation still returns partial evidence at three seconds and
cannot resume pagination when it finishes; this regression failed before
the response-timeout fix.
- `pnpm --filter @paperclipai/server typecheck` and `pnpm --filter
@paperclipai/server build` passed after the response-timeout change.
- Full `pnpm -r typecheck` and `pnpm build` passed earlier in this PR;
the affected packages were rechecked after review fixes.
- Full local `pnpm test:run` failed in the general-server group: 511
files passed, 40 failed, and 158 were skipped. Failures include embedded
PostgreSQL initialization, read-only cache directory renames, a macOS
long-path fixture, and a workspace exposure assertion. The PostgreSQL,
cache-permission, and long-path failures also reproduce with both
changed implementation files restored to baseline commit `24c58e479a`.
The exposure suite passes in isolation both on baseline and the fixed
branch (28 passed, 3 skipped). CI runs the full suite on Linux. Later
local test groups were not reached.
- An earlier CI run hit the Telegram retry-timing failure fixed upstream
in #14501. The branch includes that master fix. The selected recovery
test passed against a fresh, migrated PostgreSQL 16 database. The
embedded PostgreSQL runner is unavailable on this Mac; the isolated
database was stopped and removed afterward.
- No live agent turn was replayed. The tests use local child processes
and injected provider failures.

## Risks

Retries are restricted to recognized Daytona SDK and Cloudflare bridge
gateway-error messages, which survive plugin RPC serialization. Other
errors fail immediately. Temporary upload paths are now unique for all
command-managed queue writes. Receiver sequence checks prevent duplicate
input; retries do not restart an agent turn. Cleanup and failure logging
are nonblocking and best effort; session teardown remains the final
cleanup boundary. Log finalization now drains accepted local file writes
for at most three seconds and ignores later appends on the closed run
handle. A timeout leaves final size/hash unknown and skips the final
durable upload; an existing partial mirror may remain available, but it
is not claimed as a verified final snapshot. It does not wait for later
DB progress or live-event persistence. Optional attribution keeps
partial evidence when a read fails or times out. Cancellation closes S3
requests and response streams. Local filesystem I/O may finish after the
caller deadline, but a late read cannot change the returned evidence or
continue pagination. Later listings can retry after storage recovers.
There is no schema, authentication, or permission change. Revert this
commit to restore the previous behavior.

## Model Used

OpenAI GPT-6 through Codex, with reasoning, repository inspection, code
editing, 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 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 tests locally; targeted tests pass and full-suite
limitations 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-09-28 19:15:33 -07:00
Devin FoleyandPaperclip ea371b9684 fix: retain project defaults in partial workspace overrides (#14502)
## Thinking Path

> - Paperclip manages AI agents and their work.
> - Project workspace policies define how isolated worktrees are set up.
> - Tasks can override a branch without providing every setup field.
> - The resolver currently replaces the entire project strategy with
that partial override.
> - Losing an explicit setup command can run the repository fallback
script and block the task.
> - This pull request keeps enabled project defaults when the task uses
the same strategy type.

## Linked Issues or Issue Description

**What happened?**
A project uses `git_worktree` with `provisionCommand: "true"`. A task
overrides only `baseRef`. The resolver drops the command. Worktree
creation then invokes `scripts/provision-worktree.sh`, which can fail
because its required setup is absent.

**Expected behavior**
A branch override keeps the project's provision, runtime provision, and
teardown commands unless the task explicitly overrides them. A different
strategy type must not inherit those commands.

**Steps to reproduce**
Configure the project with an enabled `git_worktree` strategy and
`provisionCommand: "true"`. Give the task an isolated workspace with a
`git_worktree` strategy and a different `baseRef`. Add a failing
repository fallback provisioner. Before this change, worktree creation
invokes that script. After this change, it uses the project's explicit
command and succeeds.

Related: #4968 concerns agent strategy and working-directory fallback.
#13903 concerns gated API fields and reusable-workspace updates. #11091
concerns provision hooks on workspace reuse. None fixes partial task
overrides discarding project defaults.

## What Changed

- Merge a partial task strategy over the enabled project's strategy only
when their types match.
- Preserve explicit null values when parsing nullable strategy fields,
so they can clear project values.
- Keep explicit empty-string overrides and agent fallback behavior.
- Exclude disabled project strategies and avoid an inherited branch
template when a task pins an existing branch.
- Add policy regression coverage and a real Git worktree test with a
failing fallback script.
- Document inheritance, explicit clearing, and no-op provisioning in the
development guide.

## Verification

- Policy regression: eight failures before the fix; all 41 policy tests
pass after it.
- Real worktree regression: passes and creates a worktree using the
task's base branch without invoking the failing fallback provisioner.
- `pnpm -r typecheck`: passed.
- `pnpm build`: passed.
- `pnpm test:run`: general-server phase completed with 13,873 passed, 86
skipped, and 14 failures in unchanged macOS skills-cache and Git
long-path tests. The same failures reproduce on unmodified base code.
The command stops at that phase, so no full local pass is claimed.
- CI initially failed the existing Telegram subscription recovery test
on a 15-second timeout. The separate fix and investigation are in
#14501. A serialized job also lost its runner; GitHub reported lost
communication, and that job was rerun without source changes. All 52
final-commit checks pass, with two intentional skips. Greptile is 5/5,
with no unresolved comments or merge conflicts. The chat shard passed on
one unchanged rerun. The timeout cause remains unproven; #14501 adds
phase diagnostics for a recurrence.

## Risks

Tasks that specify a partial strategy now retain the project's omitted
fields, including setup and teardown hooks. This is the intended
behavior change. Inheritance requires an enabled project policy and
matching strategy types. Explicit task values still win. Null and empty
commands restore existing runtime defaults; they do not guarantee that
no script runs. Use `"true"` for an explicit no-op provision command. No
migration, live configuration change, or task replay is included.

## Model Used

OpenAI GPT-6 (Codex), with reasoning, terminal tools, and 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)
- [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 focused tests locally and they pass; full-suite status
is 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-09-28 18:09:20 -07:00
Devin FoleyandPaperclip 90119181e7 test: control Telegram subscription retry timing (#14501)
## Thinking Path

> - Paperclip manages AI agents and their work.
> - Telegram delivery recovers subscription changes after a restart.
> - The recovery test leaves a failed action on the real one-second
retry timer.
> - A slow runner can cross that deadline before the test checks that no
retry occurred.
> - This pull request holds the fixture deadline until the explicit
restart transition.
> - The test still checks that recovery uses fresh provider options.

## Linked Issues or Issue Description

**What happened?**
The Telegram subscription recovery test expected one `setWebhook`
request but saw two. A 1.5-second delay after the first failed request
reproduces the failure.

**Expected behavior**
The test controls when the failed request becomes eligible for retry.
Host speed does not change its result.

**Steps to reproduce**
Run the test named `retries an unknown subscription mutation after
restart` with a 1.5-second delay after the first failed-action
assertion. The old fixture retries too early. The updated fixture passes
with the same delay.

Related: #13952 fixes a separate Telegram fixture cleanup problem. This
change addresses retry timing.

## What Changed

- Set the stored retry deadline to 2099 before the pre-restart
assertions.
- Keep the existing explicit epoch deadline after restart and all
provider request assertions.
- Report the current test phase only when this test fails, to diagnose
an observed intermittent CI timeout.
- Leave production retry code unchanged. Temporary delay and per-step
console tracing are not included.

## Verification

- Delayed regression: failed before the change with two requests instead
of one; passed after the change.
- Focused Telegram durable private draft Stop group: 34 tests passed.
- `pnpm -r typecheck`: passed.
- `pnpm build`: passed.
- Full local chat shard: 355 tests passed twice.
- `pnpm test:run`: general-server phase completed with 13,861 passed, 86
skipped, and 14 failures in unchanged macOS skills-cache and Git
long-path tests. The same failures reproduce on unmodified base code.
The command stops at that phase, so no full local pass is claimed.
- CI exposed a separate 15-second timeout. A diagnostic run passed all
355 shard tests, with the affected test completing in under one second.
Its cause remains unproven. Normal step logging is removed; a
failure-only phase report remains for a recurrence. The final commit
also passes the 355-test chat shard, and Greptile rates it 5/5. All 52
final-commit checks pass, with two intentional skips. There are no
unresolved review comments or merge conflicts.

## Risks

Low risk. This changes only the fixture deadline. It does not disable a
test, extend a timeout, or change production retry behavior. Existing
assertions still verify the failed action, the pending state, restart
recovery, and fresh provider options. The intermittent CI timeout is not
claimed fixed; phase diagnostics narrow the next occurrence without
changing the timeout. No documentation change is needed for a test
fixture correction.

## Model Used

OpenAI GPT-6 (Codex), with reasoning, terminal tools, and 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)
- [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 focused tests locally and they pass; full-suite status
is recorded above
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes, or
explained why none is needed
- [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-09-28 18:08:57 -07:00
Devin FoleyandPaperclip ad1f7e98ea fix: retain diagnostic reasons for native runner failures (#14481)
Retain bounded reasons for runner identity, harness recovery, and provider-pack read failures. Preserve existing ownership and cleanup proofs and compatibility with receipt-gated chat recovery.

Verified with executor, recovery, diagnostic privacy, typecheck, build, and full CI checks.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-09-28 16:16:19 -07:00
Devin FoleyandPaperclip 4f6cf5b3ff fix: prevent run identity locks from blocking audit checks (#14478)
Use NO KEY UPDATE for identity locks so audit foreign-key checks can proceed while identity writers remain serialized. Preserve task-before-run ordering, company scoping, and foreign keys.

Verified with PostgreSQL concurrency regressions, focused tests, typecheck, build, and full CI.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-09-28 16:16:05 -07:00
0be2afcca6 feat(ui): improve task composer controls and pending input (#14322)
## Thinking Path

> - Paperclip lets operators assign tasks to AI agents and review their
work.
> - The task composer controls the next message and its assigned agent.
> - Operators needed a way to choose that agent's model and effort
without leaving the composer.
> - The old mode selector, upload button, and input cards made the
mobile composer crowded and hid normal messaging during a pending
decision.
> - Harnesses publish different model and effort capabilities, so the
picker must follow the selected agent.
> - This pull request adds one responsive composer flow, keeps pending
cards visible above it, and protects Codex ACP authentication in the
local test path.
> - Operators can choose run settings, send a message, and answer a
pending card as separate actions.

## Linked Issues or Issue Description

**Subsystem affected**

Task composer UI, issue thread interactions, Codex ACP credential
handling, and Storybook.

**Problem or motivation**

The composer did not expose model or effort for the selected agent.
Mobile actions wrapped poorly. Pending questions and confirmations
replaced the composer. A local Codex ACP test could also reuse host
authentication after the managed key was removed.

**Proposed solution**

Put assignee search, model search, exact model IDs, effort, and fast
mode in one picker. Use a mobile dialog. Replace the direct-upload plus
action and separate mode selector with an Add menu and removable Plan or
Ask chips. Place pending interaction cards above the usable composer.
Keep these cards pending after an ordinary message unless their creator
asks for comment superseding. Replace managed ACP auth files atomically
and isolate the test key from host credentials.

**Roadmap alignment**

ROADMAP.md does not list an overlapping composer milestone. This change
improves the existing task and review flows.

## What Changed

- Added the combined assignee, model, and effort picker to both task
composers. Search matches agent name, role, and harness. The server uses
a curated Codex list by default and honors instance-declared models.
Manual IDs remain available.
- Added an effort slider for known model capabilities, a conditional
Codex fast control, and reset. The picker opens in a modal on mobile.
- Added the Add menu for files, supported goals, Plan mode, and Ask
mode. Plan and Ask are exclusive removable chips. Keyboard mode cycling
remains available.
- Adjusted mobile spacing, avatars, wrapping, and Send placement.
Removed the composer divider.
- Moved pending question, confirmation, review, and related cards above
the composer. Ordinary comments now leave question and confirmation
cards pending by default. The onboarding prompt retains explicit comment
superseding.
- Updated the Storybook composer group with responsive states and the
production picker. Added UI, service, route, and browser regression
coverage.
- Isolated Codex ACP API-key authentication, skipped subscription auth
merge and shared-home copy-back for remote API-key runs, and replaced
the managed auth file atomically.

## Verification

- `pnpm -r typecheck` — passed on the final local head.
- `pnpm check:token-gates` — passed on the final local head.
- `pnpm exec vitest run server/src/__tests__/adapter-models.test.ts
ui/src/components/task-chat/ComposerRunSettingsPicker.test.tsx` — 31
tests passed, including role and harness search, declared Codex models,
and filtering general OpenAI models.
- `pnpm exec vitest run
server/src/__tests__/issue-thread-interactions-service.test.ts` — 74
tests passed.
- `pnpm exec vitest run
packages/adapters/codex-local/src/server/acp.test.ts` — 42 tests passed,
including remote API-key copy-back isolation.
- `pnpm test:run` — attempted locally; the embedded PostgreSQL test
database could not initialize on macOS. The isolated
`heartbeat-run-event-sequencing` suite reproduced that environment
failure. GitHub CI runs the full test matrix for this head.
- `pnpm build` — passed on the final head. `pnpm build-storybook` passed
after the last UI change; only server code, tests, and docs changed
afterward.
- Live local test drive — Codex ACP ran a task with a managed API key.
The test agent was restored to its default ACP configuration afterward.
- Review the interactive stories under the top-level Composer group with
`pnpm storybook`. Check a narrow desktop width and mobile Plan, Ask,
picker, and pending-question states.

## Risks

- A pending card stays open when an ordinary comment changes the
discussion. Its creator can set `supersedeOnUserComment: true` when a
new comment should replace it.
- Model and effort overrides persist on the task until reset or changed.
An unlisted manual model ID may fail when the provider runs it.
- Some harness catalogs do not report effort support. The picker hides
effort for those models.
- No database migration is required.

> 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-6 via Codex. This runtime does not expose the exact model ID
or context window to the task. The model used 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
- [ ] 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>
Co-authored-by: OpenAI Codex <codex@openai.com>
2026-09-28 23:02:39 +00:00
DottaandPaperclip 18e8c121d9 fix(runner): include Grok support in public installs with sandbox prerequisites (#14024)
## Thinking Path

> - Paperclip manages agents through a shared native runner.
> - Built-in harness support should ship with Paperclip's public
distribution.
> - Grok already speaks ACP; it does not require a new public bridge
package.
> - Sandbox provisioning owns the native executable and its pinned
version.
> - The runner must verify that prerequisite without downloading it
during npm installation.
> - This change separates built-in launcher identity from external
runtime identity.
> - Clean npm installation and live staging checks verify the
distribution boundary.

## Linked Issues or Issue Description

Refs #13882, #13973, #13977, #13979.

This follow-up now targets master after #13882 was squash-merged. It
replaces the private `@paperclipai/grok-acp` workspace package with
runner-owned assets. Current master is included so the branch also
contains the merged scheduler, complete-event capture, and durable
cleanup fixes.

## What Changed

- Ship Grok launcher and qualification metadata inside the runner's
compiled output and the public server's vendored runner tree.
- Remove the separate Grok npm package and all package-manager install
hooks for this runtime.
- Require the checksum-verified Grok Build 1.0.13 binary at
`/opt/paperclip/providers/grok/1.0.13/grok` in the selected execution
environment. Provision it explicitly in the Daytona image and CI setup.
- Keep native binaries outside the provider pack. Bind the built-in
launcher into the pack manifest.
- Preserve executable leases, descriptor-backed startup, credential
fences, permissions, and exact ACP model admission.
- Use `builtin:grok-acp` and `native:grok` as profile identities.
Historical package-profile sessions fail closed on resume rather than
being silently reinterpreted.
- Resolve built-in assets from the authenticated sidecar location,
including public server npm layouts. Keep the controller path out of
provider environments.
- Add clean npm tarball installation verification to the existing
trusted canary CI job and the admitted manual EC2 verification path. It
stages a unified release version and runs npm lifecycle scripts, then
verifies missing-prerequisite rejection and admission after separate
provisioning without credentials or inference.
- Include the controller-owned provider pack in stamped Cloud images.
Unstamped local images omit the pack and remain usable; remote ACPX
requires full source provenance.
- Correct CLI approval-page metadata for an already authenticated Cloud
board user; approval authorization remains unchanged.
- Honor explicit native-runner enablement in the Cloud agent picker and
direct setup page, keeping the flag disabled by default.
- Allow selecting the execution environment before connecting
credentials. Include Grok in the existing authenticated hello-probe
flow, targeting its pinned native prerequisite for runner setup.
- Recover an existing subscription sign-in conflict through an explicit
cancel-and-retry action, serialized after cancellation succeeds.
- Preserve the selected ACPX harness before normalizing config fields,
so new Grok agents use the Grok default model.
- Keep the credential-free Cloud provider pack root-owned and readable
after runtime UID remapping; verify manifest and referenced asset access
under an unrelated unprivileged UID during image builds.
- Archive prior failover backups alongside explicitly replaced harness
state, preserving evidence while preventing stale backups from blocking
a fresh replacement.
- Update Daytona image content inputs and contract tests for the
built-in assets and explicit provisioner.
- Document and regression-test the shared `approve-all` default for Grok
setup, saved configuration, and native execution. Explicitly saved
restrictions remain unchanged.

## Verification

Current merge-repair head `df09eb3e1a619430ad8419a0ee9aedd486689b05`
incorporates master `f1a394bd30cb56fb9e479f98b9f50176fe921858` after the
base PR was squash-merged. All 12 conflicts came from incoming files
identical to the tested pre-squash base. The final tree exactly matches
a three-way merge using that original base, preserving built-in Grok
distribution and removal of the obsolete private package. All 252
focused runner/UI tests, six npm-isolation tests, and token gates pass.
Fresh exact-head Greptile review is 5/5 with no outstanding findings;
security scans and EC2 native compilation pass. All current-head CI is
green: 56 successful checks/statuses and four intentional skips ([run
36468768035](https://github.com/paperclipai/paperclip/actions/runs/36468768035)).
The repository owner explicitly authorized bypassing code-owner approval
after all checks passed; no CI checks or repository protection settings
are bypassed or changed. The only remaining PR was removed from the
completed stack metadata to permit native auto-merge.

Earlier integration head `78cb306ecc41b5c96577c26c1d89153b0ef865a1`
includes master `3447609d2247e75e55d91493dda91a608364f672` (2026-09-28).
Two master advances during verification overlapped the eval catalog; the
final merge preserves Grok qualification, completion updates, and
bounded API-response reading in all 348 cells. All 77 focused
catalog/eval/workflow tests pass. Both native stack layers (#14397) are
mergeable, and both exact-head Greptile reviews are 5/5 with successful
security scans and no unresolved review threads. All current-head CI is
green: 56 successful checks/statuses and four intentional skips ([CI
attempts](https://github.com/paperclipai/paperclip/actions/runs/36447124691)).
The initial attempt lost two EC2 runners to shutdown signals and stalled
a third shard during dependency preparation; all three passed the
same-commit failed-job-only retry. Trunk code-owner requirements remain
enforced. The review summary’s non-blocking saved-asset offset
classification note concerns code already merged in #14301; those
runtime files are identical to master and outside this stack’s diff.
Historical live evidence below retains its original source revisions.
[Final public npm
verification](https://github.com/paperclipai/paperclip/actions/runs/36445542764)
passed on `76ea70cd4d13786a042af9df82f0fd7a8c85ae30`: 17 public
packages, an executed offline lifecycle sentinel, unchanged consumer
lock, built-in launcher, missing-prerequisite rejection, and verified
separately provisioned binary/command lease. Provisioning and cleanup
require no host privilege elevation; only the positive probe mounts the
temporary native binary read-only. The verifier is unchanged by the
final master merge. All six isolation tests and an offline npm smoke
test pass. The prior head had 56 green CI checks and a 5/5 review after
two unchanged tests timed out and passed a failed-job-only retry ([CI
attempts](https://github.com/paperclipai/paperclip/actions/runs/36444597313)).
All 56 recovery-display/lineage tests pass; re-review cleared the
already-covered missed-retry concern. Earlier EC2 failures remain
retained: [npm lockfile
rejection](https://github.com/paperclipai/paperclip/actions/runs/36436311203),
[missing compiler in the slim
image](https://github.com/paperclipai/paperclip/actions/runs/36440210984),
and the aggregate 15-minute test timeouts in those broad runs. Both
broad attempts passed typecheck, token gates, Product E2E type/unit
checks and build. The focused EC2 lane preserves the existing
trusted-actor and immutable-source gates.


Earlier documentation/test checkpoint
`ff244c4fd78a7ede5a3e00efe09f475f133ef33e` leaves runtime behavior
unchanged. 154 focused tests pass across configuration building, native
provider resolution, permission policy, credentials, UI configuration,
and new-agent setup (including both Grok auth modes); token gates pass.
All fresh CI is green for this head: 56 successful checks/statuses and
two intentional skips ([run
36367065119](https://github.com/paperclipai/paperclip/actions/runs/36367065119)).
Greptile is 5/5 with no new findings. Grok already inherits the shared
`approve-all` default, so unattended setup requires no manual permission
change.

Runtime head `bb5a9307991f1ac567b781970ef11b39d518e19b` fixes a final
staging continuation failure before provider startup: explicit
replacement archived the old harness but left its failover backups
active, which caused `runner_harness_state_mismatch`. The regression
fails before the fix and passes after it; all eight adjacent
recovery-safety cases also pass. Old backups remain inspectable inside
the continuity archive. All fresh CI is green at this head ([run
36360839248](https://github.com/paperclipai/paperclip/actions/runs/36360839248)),
with a 5/5 review. One unrelated Cursor test timed out in the initial
server shard; the same-commit failed-job rerun passed, and both attempts
are retained. Staging deployment is confirmed healthy on this revision.
The controller image is
`ghcr.io/paperclipai/paperclip@sha256:6ad91c487910ccd2596ff7aed0a3a3ea5233d12b51b83cd6e1402237749b9673`.
The final browser-created staging task passed on this exact revision
with API authentication: context read → structured human question →
controller restart → answer submission → same native provider session
resumed → document saved → task Done. The two turns took approximately
119s and 77s. The actual write receipt was applied, and the saved
document has exactly one revision containing the selected answer and
requested marker. Usage and cost were not reported. [Controller image
build](https://github.com/paperclipai/paperclip/actions/runs/36360889243).

- Previous integration head `a44f7dbb6b6f77cd9ed893756ca453307f281e5f`:
all CI green (53 successful checks/statuses, two intentional skips),
including repository typecheck/build/tests, native Runner tests, browser
shards, and canary installation checks. [CI run
36358672529](https://github.com/paperclipai/paperclip/actions/runs/36358672529).
Greptile is 5/5 with no unresolved findings.
- Focused checks cover Grok credentials, executable admission, launcher
assets, provider-pack paths/permissions, workflow contracts, setup
defaults, CLI authorization, and subscription conflict recovery. All 39
protocol definitions validate. Final integration checks pass 124
catalog/evidence/cache tests and nine project-form tests; token gates
pass. Some local dependency checks could not load the stale installed
dependency tree; the corresponding fresh EC2 checks pass.
- Clean public npm installation passed on EC2 at
`8b172ebcf8e02e30662d830c00f3961e3bd459ec` ([run
36164964900](https://github.com/paperclipai/paperclip/actions/runs/36164964900)):
17 unified-version packages, lifecycle scripts enabled, built-in
launcher present, no separate Grok package or npm-downloaded binary,
missing prerequisite rejected, separately provisioned native executable
and command lease verified. No credentials or inference were used.
Subsequent changes preserve this npm asset layout.
- The immutable Daytona prerequisite image is
`ghcr.io/paperclipai/paperclip-daytona-runner@sha256:98957d5be0ac774d086b6402b5849e8e6356fec70fb8c09fca6eb4ed6de918e0`,
built from `5a2db471f3ddabe77f9f80e76ed27f996cb97fba`. The previous
Cloud controller image was
`ghcr.io/paperclipai/paperclip@sha256:fd914e1ab1e45f741e8e078ff452d16f082d7ac05f9b4b3506d3a3c64150d204`,
built from `a44f7dbb6b6f77cd9ed893756ca453307f281e5f`; it is superseded
by the latest image above. Its EC2 build verified provider-pack access
under an unrelated unprivileged UID.
- Browser staging at `40f898bc4cba73c1dff4e6344a3983ba0fb247ef` passed
full Grok onboarding with the correct `grok-4.7` model, saved credential
delivery, and pinned Daytona execution. A browser-created task read
context and asked the structured human question. After a controller
restart, answering the persisted question resumed the same native
provider session, saved the requested document, and completed the task.
Actual tool outcomes and durable state agree: one question and one
document revision. The two successful turns took 42.7s and 63.1s; usage
and cost were not reported.
- Restricted policy returned the expected `approval_required` outcome.
Functional staging tests explicitly selected `approve-all`; controller
authorization and governed approvals remain enforced. Temporary board
CLI access was revoked and verified rejected (HTTP 401), and the
disposable onboarding agent was paused.

Failures remain retained: the pre-fix continuation failure (its task
remains blocked; the passing final task is fresh), the original Cloud
provider-pack permission failure, the expected restricted-policy denial,
the superseded npm staging failure, and an earlier monolithic CI
infrastructure timeout. Browser CI exposed a project alias/form race;
the final stack uses master's stronger draft-preservation fix and all
browser shards pass. Historical full subscription/API protocol and
Product rosters retain their original source revisions and do not
qualify this packaging revision. No local Docker or Rust build was used.

## Risks

The branch includes master’s draft-preservation fix for project URL
aliases. It keeps the same project’s edit form mounted and clears prior
data when the project or company changes.

Custom sandboxes and local execution hosts must provision the pinned
binary before Grok starts. Missing, changed, unsupported-platform, and
symlinked executables fail admission. The new builtin profile cannot
resume sessions created with the former private-package profile.
Existing Claude/Codex npm bridge profiles retain their package pins.
Grok restricted modes preserve the selected policy but cannot
automatically admit Paperclip calls: ACP permission metadata does not
independently bind tool authority, so those calls stop with
`approval_required`. New Grok configurations default to `approve-all`,
including API configurations that omit the mode. Existing explicitly
restricted configurations remain restricted; controller authorization
and governed approvals remain enforced.

## Model Used

OpenAI GPT-6 through Codex, with tool use and code execution. The exact
serving 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-09-28 14:54:44 -05:00
DottaandPaperclip 992f720262 fix: make runner task context ownership explicit (#13753)
<!-- Write all pull request text in Simplified Technical English
(ASD-STE100). -->

## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Task descriptions, comments, continuation data, skills, and
execution rules enter several agent adapters.
> - The same source can be rendered by more than one automatic input
carrier.
> - Failed resumes can also rebuild input from stale or compact context.
> - This pull request gives each Paperclip-owned source one delivery
owner and preserves the required transport boundaries.
> - It adds deterministic adapter, interaction, runner, and browser
tests for these boundaries.
> - The benefit is more predictable context delivery with explicit
evidence for later live qualification.

## Linked Issues or Issue Description

Related: #13144 removes a duplicate environment payload and bounds wake
lists. Related: #11360 addresses Hermes resume behavior. This pull
request preserves compatible active-session formats while repairing
context ownership and stale question creation.

**What happened?**

Task descriptions and comments could enter more than one automatic
context block. Native transports could wrap a complete model input in a
second task envelope. Some legacy and gateway adapters could omit the
owned assignment on ordinary tasks or rebuild a failed resume with stale
compact context. A continuation could also request a question after
newer human comments had arrived.

**Expected behavior**

Each task or comment source has one automatic model-facing owner.
Distinct comment IDs and repeated wording remain distinct. Fresh
fallback attempts rebuild the required full context. A question request
is rejected when newer queued human direction makes it stale. Harness
access policy remains owned by execution configuration.

**Steps to reproduce**

1. Build a task with a description and current comments.
2. Capture the actual adapter or runner input.
3. Compare source ownership and task-envelope nesting.
4. Queue a human comment before a continuation requests a question.
5. Trigger a failed resume and inspect the fresh retry input.
6. Run the focused adapter, interaction, runner, and browser checks.

## What Changed

- Add shared prompt-section selection at the provider-attempt boundary.
- Deliver owned assignment context through native, legacy CLI, ACP,
gateway, cloud, Pi, Kimi, Grok, Gemini, OpenCode, Cursor, OpenClaw, and
Hermes paths.
- Rebuild full or compact context after resume recovery changes the
attempt. Add native and Claude ACP tests of actual recovery requests.
- Preserve custom templates, loaded instruction files, execution
policies, and older active-session formats.
- Record continuation source metadata and reject stale question creation
under the issue-row lock.
- Add explicit Product E2E context-integrity profiles, prerequisite
gates, credential-isolation checks, and report fixtures.
- Bypass service-worker forwarding for same-origin Vite development
modules. A real Chromium test fails with resource exhaustion before the
repair and passes after it. Production asset caching keeps its existing
policy.
- Add browser diagnostics and service-worker module-loading regressions.
- Add an explicit zero-retry eval option. The default retry behavior
remains unchanged. Each campaign records its effective policy.
- Remove the model-facing working-directory sentence from four prompt
builders. Existing workspace, sandbox, permission, and custom-template
configuration remains unchanged.
- Align the everyday workflow assertion with the current 47-entry
catalog.

Compared with current upstream master, the branch carries the
context-ownership implementation and its tests, the explicit
context-integrity catalog and evidence harness, and the focused browser
regression checks.

## Verification

**Merge assessment:** focused regression evidence supports merge. This
is not full completion of the original broad qualification matrix. The
maintainer has authorized merge after fresh verification of the master
integration.

- Current head: `bbd52f82114eabf09bc7b1a7e97d54a5b43bbc00`. This
integrates current master `2f585ef26a1814fa209715242d1ca791b63e4c4e`.
All 14 conflicts are resolved. Cancellation checks, workspace
finalization, native Grok support, and both sets of tests are retained.
- Current-head Greptile: **5/5**, with no blocking findings. The review
names this exact commit. All **59 reported checks are terminal: 55
successful, 4 skipped, zero pending or failing**. This includes the full
root general and serialized suites, separate runner checks, typecheck,
build, canary, browser E2E, Docker, and security checks. The successful
legacy security status is included in that total.
- After integration: workspace typecheck and full build passed. Separate
runner checks passed: **2,160 TypeScript tests (10 skipped), 582 Rust
tests, and 39 preparation checks**. Other passing checks include 621
Product E2E harness units, 376 focused shared/adapter tests, 160
real-database/API tests, 86 Hermes tests, 18 browser-support checks, and
Product E2E typechecking. The complete root suite passed in CI. The
duplicate local monolithic root run was stopped after that CI result; it
is not counted as a completed local pass.
- New native recovery coverage retains full assignment, completion
contract, and explicit skill selection after safe replacement, for old
and prepared input formats. Full native session test file: **136/136
passed**.
- New Claude ACP coverage captures actual fresh, resumed, and
missing-session fallback requests. It verifies one assignment copy,
comment order, identical text under distinct comment IDs, and full
fallback context. Full file: **33/33 passed**. Both affected TypeScript
checks passed.
- Existing deterministic tests cover source revisions, approval and
trust boundaries, completion validation, custom templates, compatible
sessions, standalone driver wrapping, and maintained adapter transport
requests.
- Provider-free browser support: **17/17 passed** after the master
merge. Service-worker unit tests: **33/33 passed**. The module-overload
regression failed before the repair and passed after it in real
Chromium.

### Fresh live comparisons

The new batch ran exactly four Product E2E attempts. **All four passed
on the first attempt; no retries.** Each has six terminal matchers plus
the existing browser lifecycle and invariant checks.

| Exact case ID | Control | Candidate |
|---|---|---|
| `core-compatibility.runner-codex.local.plan-revise-accept` | Passed |
Passed |
|
`local-session-integrity.runner-acpx-claude.local.structured-question-restart-resume`
| Passed | Passed |

The plan case checks a revised canonical plan and revision-bound
approval before completion. The question case restarts the server before
submitting the answer, then verifies the continuation completes.

Control source is `dfa4e1bda8d50a1a01746603251a9128dbe9d0d6`. Candidate
source is `79fcdb5dece501d28064ea9da306603881b46f0c`. They use identical
frozen definitions and provider versions: Codex `0.156.0` with
`gpt-5.6-sol`; ACPX `0.13.1` / Claude ACP `0.73.0` with
`claude-sonnet-5`. The September 24 head added master browser recovery
and test-only changes. The September 28 head also integrates newer
master changes, including cancellation, workspace finalization, and
native Grok. These are frozen-source live results, not exact-head live
runs.

The candidate received one description copy where the control initially
received three. The submitted initial plan envelopes were 7,969 versus
19,097 characters. Question envelopes were 7,592 versus 18,919. These
are structural measurements, not whole-provider token or dollar savings.

### Earlier evidence and failed attempts

- The preceding fresh batch has four effective passing pairs: OpenCode
comment continuation and assigned skill, native Codex comment
continuation, and native Claude comment continuation. It retains **11
attempts: eight passed and three failed**.
- Original failures remain recorded: missing local PostgreSQL library
links before task creation; host-sleep cleanup after task/page checks
passed; and a Claude **control** session-open rejection before a model
turn. Setup was repaired identically on both worktrees. The permitted
unchanged infrastructure retries passed. The underlying Claude provider
startup error was not retained and remains unknown.
- Older R2 retains **17 passes and one failure** across 18 attempts,
including eight both-pass native/legacy Codex/Claude pairs. Its OpenCode
blank-page failure led to the service-worker repair. R2 is historical
evidence: master changed the native fixed prompt and removed duplicate
wake environment data afterward.
- The September 24 CI run initially failed one unrelated preview
readiness test (`ECONNREFUSED` on its local fixture). Its test and
production code match master. Isolated local verification passed **28
tests, 3 skipped**. One unchanged CI retry passed the full shard: **831
passed, 1 skipped**, including all **31 preview-exposure tests**. The
aggregate CI gate passed afterward. The precise startup cause remains
unknown; a port race is a hypothesis, not a proved cause.

### Limits

The original wider profile/workflow matrix, repeated trials, and remote
Daytona qualification are incomplete. These results support a focused
merge recommendation, not statistical equivalence or universal harness
qualification. Some usage receipts are missing in both variants, so no
token or dollar savings are claimed. The $500 ceiling was preserved
using conservative allowances; failed attempts and unknown charges
remain in the ledger.

Reproduce the focused additions with `pnpm exec vitest run
packages/adapters/claude-local/src/server/acp.test.ts` and `pnpm
--filter @paperclipai/paperclip-runner exec vitest run
src/native-session-runtime.test.ts`. Full checks use `pnpm -r
typecheck`, `pnpm test:run`, `pnpm build`, and the separate runner
checks. Paid evals require the frozen definitions, profiles, and
credentials; do not use `--all` as a substitute for the selected cases.

## Risks

- Context placement changes can affect model behavior. Deterministic
checks cover the selected paths, but live qualification remains
incomplete.
- The stale-question guard can reject a request when queued human
comments arrived during the run. This is intended.
- New stored inputs and model envelopes retain compatibility readers for
older active sessions.
- Custom templates may intentionally repeat content.
- Removing a model-facing working-directory sentence does not change
filesystem, command, sandbox, or permission configuration.
- The worker bypass applies only to same-origin development module
paths. Cache-policy tests preserve private-response handling and
production asset caching. Mounted HTTP fixture changes remain test-only.
- This PR does not claim measured token savings or statistical
equivalence across every harness.

## Model Used

OpenAI Codex, exact model gpt-6-astra, with repository tools and code
execution. Bounded supporting work used gpt-5.6-luna and gpt-6-luna. The
serving context-window size is not exposed in this task.

## 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 using the required issue fields
- [x] I have not referenced internal/instance-local Paperclip issues or
links
- [x] My branch name describes the change and contains no internal
ticket id
- [x] I have run the focused local checks and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect these changes
- [x] I have considered and documented risks above
- [x] All current-head Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
for the current head
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-09-28 14:49:14 -05:00