Commit Graph

1375 Commits

Author SHA1 Message Date
Dotta c9e3bb7ca4
fix: preserve queued work after native Stop and honor steering support (#13354)
## Thinking Path

> - Paperclip lets people manage AI agents and their tasks.
> - The runner owns execution, while the task keeps user instructions
and status.
> - Stop must stop the current response without losing instructions that
the user already sent.
> - The queue stored its original reason inside saved context. Recovery
checked the outer deferred reason and left the message waiting.
> - Claude also exposed Steer through a shared method even though its
driver did not support it. A rejected request could remove its own error
row.
> - This pull request keeps queued work until execution has stopped,
uses the driver's real capability, and preserves completion event order.
> - Users can continue work without repairing task state or repeating
messages.

## Linked Issues or Issue Description

Refs #13338. Related recovery work: #13353.

**What happened?**

A message sent during a native run stayed queued after Stop. Claude
exposed an unsupported Steer action. A steering failure could hide the
queued row and its error. A terminal event could also precede the final
provider result, and subtree Stop omitted the board actor.

**Expected behavior**

Stop ends the current execution. Once Paperclip proves that execution
has stopped, it delivers the saved instruction once through normal
admission. Pause and recovery holds still prevent dispatch. Unsupported
controls stay disabled, and a rejected action leaves an actionable error
visible. Final results precede terminal events.

**Steps to reproduce**

1. Start a Claude or Codex task that writes a file and then waits.
2. Send a follow-up instruction while it runs.
3. Press Stop. Check that the queued instruction runs once and preserves
the file.
4. Check Claude's Steer control and simulate a server rejection on the
only queued message.

## What Changed

- Recover saved native comments after acknowledged Stop using their
original wake reason.
- Require durable remote termination receipts or verified local process
termination before dispatch.
- Preserve actor identity, queued-message deduplication, Pause, and
recovery gates.
- Derive steering support from the driver descriptor and reject
unsupported calls.
- Keep the queue mounted until a steering request succeeds so its error
remains visible.
- Emit provider results before terminal events and pass the board actor
into subtree Stop.
- Document Stop and steering behavior.

## Verification

- Final-head continuation suite: 104 passed, after failing regressions
for saved wake reasons, cleanup proof, and deduplication of every queued
message. Steering UI: 121 passed. Driver capability: 26 passed. Runner
backend/transport: 205 passed; Rust library: 285 passed.
- Real Claude and Codex browser journeys both preserved the saved file,
delivered the queued instruction once after Stop, and reached Done with
exactly two total runs. The process Stop browser fixture also passed.
- Local full repository typecheck and build passed on `afaa35139`;
server typecheck and the affected 104-test suite passed after the final
queue changes. Token gates passed. Final-head CI verifies the complete
integrated source.
- Local aggregate evidence has explicit limits: the general-server
invocation overlapped the queue fixes and finished with 11,989 passed, 2
failed, and 80 skipped; both failures are covered by the final 104-test
pass. The UI and CLI then passed all 6,184 and 485 tests; the complete
145-file serialized rerun passed all 2470 tests. The shared-package lock
fixture passed unchanged on rerun, but the package phase subsequently
stopped at an embedded-Postgres bootstrap resource failure. No single
pristine green local full aggregate is claimed.
- Greptile reviewed `fa66e2bd5` at [5/5 with no unresolved
findings](https://github.com/paperclipai/paperclip/pull/13354#issuecomment-5650334242).
[Final-head CI completed
successfully](https://github.com/paperclipai/paperclip/actions/runs/34733781888/attempts/2):
33 successful checks, 2 conditional skips, including all server,
package, UI, browser, runner, typecheck, and build gates. The first
attempt hit a preview-readiness/port-collision fixture; its unchanged
local control passed 25 tests with 3 skips, and one supported unchanged
CI retry passed the affected shard and aggregate gates.

## Risks

- Queue recovery must never overlap an old execution. Unknown cleanup
state remains blocked.
- Driver descriptors are now authoritative for steering; a wrong
descriptor disables the action instead of attempting it.
- No schema migration or historical status reconciliation is included.

## Model Used

OpenAI GPT-6 through Codex, with reasoning, code execution, browser
testing, and tool use. The exact hosted model ID and context-window size
are 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 either (a) linked existing issues with `Fixes: #` / `Closes
#` OR (b) described the issue in-PR following the relevant issue
template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-09-12 22:29:54 -05:00
Dotta 6809314a3f
fix: recover sandbox workspace setup and retries (#13353)
## Thinking Path

> - Paperclip manages AI agents and their tasks.
> - Sandbox tasks need a workspace and a provider session before work
can start.
> - A selected Git subfolder is a valid workspace, but it is not a
repository fetch source.
> - A resumed sandbox must keep one resource identity when the provider
fills in its region.
> - Workspace reuse does not prove that a provider session has started.
> - A recorded continuation must not leave an old failure blocking Retry
for a newer attempt.
> - This pull request fixes those setup and recovery boundaries while
preserving ownership checks.

## Linked Issues or Issue Description

**What happened?**

A Daytona task failed before provider startup when its project folder
was inside a parent Git repository. After the folder was repaired, Retry
resumed the same sandbox and verified its workspace sentinel, but
workspace preparation reported that the lease was no longer active. A
later attempt could fail because the resumed workspace had no provider
checkpoint. The old run also kept a recovery projection after the server
recorded its explicit successor, hiding Retry for the new failure.

**Expected behavior**

Sync the selected folder without importing parent files or history. Keep
the existing sandbox identity stable. Allow a new provider session only
with proof that its exact session has never started. Let the current
failed attempt retain Retry once the old recovery has a recorded
successor.

**Steps to reproduce**

1. Select a subfolder of a Git repository as a project workspace and
start a Daytona task.
2. Leave the target region unset. Release its reusable sandbox after
setup fails, then resume and realize the workspace.
3. Retry a provider setup that failed before any session directory or
checkpoint was created.
4. Record an explicit successor for a native failure, fail that
successor during setup, and inspect Retry in the task thread.

**Paperclip version or commit**

Reproduced against `8d1f0c20a` with new failing regressions before each
production fix.

**Deployment mode**

Local controller with a Daytona environment. Automated tests use
deterministic provider fixtures and real filesystem operations.

Related: #13338, #13163, #13264, #13349. The open work-folder stack in
#13264 includes a broader fresh-session authority change. This patch
addresses the independently reproduced startup failure with existing
durable bootstrap proof and atomic directory creation. It does not
include the work-folder migration or credential changes from that stack.

## What Changed

- Classify only the selected Git repository root as a fetch source. Sync
subfolders as directories and preserve their enclosing Git ignore rules
on upload and restore. Recognize the shared scheduler’s completed
non-repository result so ordinary folders still sync; timeout,
cancellation, and output-limit failures remain closed.
- Remove the placement target from Daytona account cache identity. Keep
API endpoint, credential digest, company, environment, driver, and
sandbox ID boundaries.
- Preserve closed-lease admission until a sentinel-verified resume
reopens that same resource.
- Show the already-recorded explicit successor of a resolved recovery.
Keep the old failure evidence and unresolved holds. No historical status
writes occur.
- Permit a resumed workspace to create a new session directory only with
matching durable identity, zero connections and events, untouched
bootstrap commands, no backup, and an absent remote session. Claim the
directory atomically. Existing, partial, or ambiguous state still blocks
startup.

## Verification

- Final head `c43c7403f`: [CI completed
successfully](https://github.com/paperclipai/paperclip/actions/runs/34733846820/attempts/2),
with 32 successful checks and 2 conditional skips. This includes every
server, UI, package, serialized-route, browser, native-runner,
typecheck, and build gate. Greptile reviewed the same head at [5/5 with
no unresolved
findings](https://github.com/paperclipai/paperclip/pull/13353#issuecomment-5650270168).
- New regressions failed before each of the four production fixes.
Git/archive/restore suites: 148 passed. The scheduler-wrapped non-Git
regression also failed before its fix; 135 affected Git/sync/Codex tests
then passed.
- Daytona plugin: 230 passed, 6 opt-in live tests skipped. Native
executor, projection, and TaskChatThread: 494 passed, including
existing/partial state, wrong identity, prior connections or turns,
backups, unavailable proof, and unresolved recovery controls.
- Local full-repository typecheck, build, and token gates passed on the
final head. Local CLI: 485 passed. Complete single-worker package rerun:
3,224 passed, 19 skipped.
- Local verification is an aggregate with recorded retries, not one
pristine green invocation: the general-server run began on `e721a920a`
and finished with 12,002 passed, 3 failed, 70 skipped. Its real Codex
scheduler failure is fixed above; the socket and workspace-runtime
timeout failures passed unchanged in focused reruns. Both Inbox failures
passed unchanged in the full 27-test Inbox file; database/shared-package
failures passed in the single-worker package rerun. The supplemental
local serialized-route rerun remains in progress; all five corresponding
final-head CI lanes passed.
- The first final-head CI attempt hit a Daytona fixture-readiness race
and a signoff-browser heartbeat receipt timeout. One supported unchanged
failed-job rerun passed both and the aggregate gates. Live combined
user-journey verification is tracked in the related follow-up; this PR's
provider tests use deterministic fixtures and real filesystem checks.

## Risks

- A selected subfolder uses directory sync and does not carry parent Git
history. Its ignored files stay local.
- The target region remains a creation setting and part of workspace
reuse policy; it does not split the account identity of an existing
sandbox.
- Incomplete or conflicting provider state still fails closed. This
change does not erase a session, infer completed work, bypass a user
decision, or replay uncertain actions.
- A later remote setup failure can leave a claimed partial session
directory. It remains blocked rather than being overwritten.

## Model Used

OpenAI GPT-6 through Codex, with reasoning, repository tools, and code
execution. The exact hosted model ID and context-window size are 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 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-12 22:19:42 -05:00
Dotta 8d1f0c20af
fix: let responsible users choose either AI subscription or API key (#13351)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - AI Connections select the account used for each run.
> - A responsible-user binding must follow the person whose work the
agent performs.
> - The saved sign-in method currently blocks users with another method
for the same provider.
> - This pull request resolves a personal default by company, user, and
provider.
> - Each user can use a subscription or API key with the same bot and
model.

## Linked Issues or Issue Description

Refs #13247, #13248, #13346, #13347.

**What happened?**
A bot configured with a Claude subscription rejects another responsible
user’s Claude API key. Inline repair also limits that person to the
original sign-in method.

**Expected behavior**
The same bot uses each responsible user’s default Claude account,
whether it is a subscription or API key. Explicit shared account
selections remain fixed.

**Steps to reproduce**
1. User A connects a Claude subscription and creates a bot using the
responsible user’s connection.
2. User C connects a personal Claude API key.
3. User C runs the same bot. Before this fix, credential resolution
fails.

## What Changed

- Add a personal provider-default table. Preserve legacy per-method
preferences and backfill the most recently updated preference, including
unavailable defaults. Repeated migration does not replace a selection. A
database trigger propagates old-server default updates without treating
new accounts as replacement defaults.
- Resolve responsible-user bindings by provider. Retain the method as a
wire compatibility hint for old servers. Explicit selections still
require the exact method and grant.
- Use the selected account’s method for credential isolation, refresh
locking, and run attribution.
- Update onboarding, agent setup, the picker, and inline task repair.
Keep existing authentication components and harness/model settings.
- Add mixed-method runtime, migration, repair, and Storybook coverage.
Include upstream’s duplicate Anthropic option fix through the base
branch.

## Verification

- Focused resolver, migration, connection-intent, onboarding, agent
setup, model, and connector UI suites: 331 tests passed.
- Onboarding and new-agent regression suites passed during the initial
focused run.
- UI typecheck, token gates, and Storybook build passed.
- Live browser checks passed for Claude and Codex API-default execution,
switching both back to subscriptions, and both existing shared-account
bots. Bot configuration remained unchanged.
- One Daytona startup command stalled before Claude launched. The test
run was cancelled, its sandbox stopped, and the same account/task passed
on retry. Startup cancellation remains a separate environment finding;
this PR does not change that command transport.
- Browser review: all eight assertions passed in the new mixed-method
story, including shared selection, return to responsible-user selection,
and unchanged harness/model.
- Repository build and typecheck passed after refreshing upstream
dependencies. Final resolver and historical rollback verification: 38
tests passed. All latest-head CI gates passed, including
server/workspace/serialized suites, browser E2E, build, typecheck, and
runner verification. The extra serial local full-suite run was stopped
after equivalent CI passed; focused local checks completed.

## Risks

- Users with both historical method defaults get their most recently
updated preference as the initial provider default. They can change it
explicitly in Connections.
- A revoked or unavailable default blocks. Connecting an additional
account does not silently replace it.
- Existing legacy authentication is unchanged. Managed responsible-user
bindings intentionally stop pinning a method.
- Live staging: the same Claude and Codex bots completed real API-key
runs after changing only the personal default, then completed
subscription runs after restoring the original defaults. Read-only
database verification confirms unchanged bot configuration and actual
method attribution. Distinct-user concurrency is covered by automated
real-database tests with synthetic credentials, not two live human
logins.

## Model Used

OpenAI GPT-6 (Codex), with reasoning, repository tools, code execution,
and browser interaction. 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-09-12 20:27:26 -05:00
Dotta 422287eecd
fix: preserve runner recovery, warm sessions, and task outcomes (#13338)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - The native runner connects task messages, provider execution, and
task outcomes.
> - First-time user tests exposed gaps in recovery, completion
permissions, message delivery, and Stop behavior.
> - These gaps left usable output hidden, completed work waiting for
bookkeeping, or safe work unable to continue.
> - This pull request fixes the shared lifecycle and receipt paths while
preserving process ownership and action checks.
> - Users can continue work with accurate task state and durable
messages.

## Linked Issues or Issue Description

**What happened?**

A stopped local Codex execution could remain blocked even after its
processes had stopped and its complete transcript proved that no
external action needed replay. Claude under Conservative permissions
could fail to call task completion tools. Recovery could reuse an
assistant item ID and overwrite prior output. A delivered comment could
remain marked uncertain after navigation. Stop could look like Pause or
a new recovery incident. Workspace contention could look like
cancellation. A direct reply reopening Done could enter a clarification
loop.

**Expected behavior**

Recover automatically only with verified termination and complete action
receipts. Preserve answers and messages. Keep task completion available
under Conservative permissions without broad tool access. Show crashes
as Blocked, actual human decisions as In Review, and ordinary workspace
contention as waiting. Stop the current response and allow a new
direction.

**Steps to reproduce**

1. Create ordinary response tasks with local Codex and Claude Code, then
send follow-up messages through the task composer.
2. Interrupt a disposable local Codex runner during text-only work.
Verify automatic continuation and retained output.
3. Stop a response, send a new request, answer a clarification, and
reopen completed work with another message.
4. Navigate or reload while a comment submission is pending. Confirm the
exact persisted request receipt settles it without removing newer draft
text.
5. Run two tasks in a shared Daytona workspace. Confirm waiting does not
appear as failure.

**Paperclip version or commit**

Initial acceptance baseline: `c9021c6721f91e2c74bd9fee9d3fd41c999d17b7`.
Current integration base: `6cef9743c`. Both operator-interruption and
workspace-waiting guards are preserved; native restart and legacy
permission rules remain documented.

**Deployment mode**

An isolated source-built test-drive instance, with real local Codex and
Claude Code providers and disposable Daytona environments.

Related work: #13314, #13316, #13327, #13344, #13239, #13254, #13163.
This PR addresses additional failures from ordinary task journeys,
including controller restart handoff and repeated warm sandbox setup.
Historical task status reconciliation is excluded.

## What Changed

- Persist runner ownership immediately at spawn and resume an explicitly
adopted runner even when the controller crashed before the first driver
checkpoint. Detach the controller safely across graceful restarts,
including session startup. Prevent an old finalizer from suspending or
signaling an adopted runner. Checkpoint idle warm sessions before
shutdown. Preserve the same run and queued follow-up messages.
- Scope saved legacy queue successor checks to the queue owner while
preserving ordinary task locks, operator identity, assignment gates, and
exactly-once delivery.
- Preserve managed Codex credential files when an old session is
detached for restart; normal owned cleanup still copies refreshed auth
back and removes the scoped copy.
- Reuse the bound warm shared sandbox and fully verify an existing
staged provider pack before using it. This avoids repeated uploads when
the pack is already valid.
- Add a narrow local Codex replacement path with stopped-process proof,
a closed transcript inventory, exact completion receipts, and
fresh-session lineage. Preserve no-replay holds when evidence is
incomplete. Recovery may clear only the same run's recorded Blocked
status version; manual re-blocking and dependency changes invalidate
that receipt, while queued comments do not. Later blocks stop scheduled,
queued, and final dispatch; queued/final checks re-read dependencies
even when the task status stays In Progress.
- Permit only task delivery and human-input tools through the isolated
Claude runner's exact task bridge.
- Scope assistant item identity to the provider turn and ignore only
authority-free Codex skill-change notifications during startup.
- Reconcile composer submissions by client request ID across response
loss, navigation, and reload. Retain text typed during delivery.
- Keep acknowledged run-only Stop neutral and show workspace contention
as waiting. Project exhausted native failures as Blocked.
- Restore the guarded task-page retry action for failed legacy runs,
including the server-supported explicit new-attempt path for stopped
conversation adapters. Preserve native/process recovery holds and avoid
promising Retry while a decision or execution gate hides it.
- Refresh delivered artifacts and handle direct user replies that reopen
completed work without a clarification loop.
- Check the embedded PostgreSQL PID, data directory, and actual port
before connecting or migrating.
- Document accepted behavior and add focused regressions at lifecycle,
route, transcript, and UI boundaries.

## Verification

- Final head `fece606ac2` passes the complete GitHub CI matrix: **34
green checks, two expected Storybook skips, no failures or pending
checks**, including `ci / verify`, `ci / e2e`, full runner verification,
typecheck, build, every server/workspace shard, and all browser shards.
[CI
run](https://github.com/paperclipai/paperclip/actions/runs/34727183287).
Greptile is **5/5 with no open findings**. The final two commits only
refine test fixtures; both affected suites pass 24/24 locally and in CI,
with server typecheck green.
- Complete local Vitest coverage uses the canonical groups/shards: all
635 general server suites, all 145 serialized suites, and all workspace
packages. The aggregate began on `0a8001c18` while the final queue fix
arrived: 23,903 passed, five failed, 87 skipped. The five
port/socket/timing failures passed unchanged in follow-ups (60 tests in
the exposure/file suites and 412 tests covering the serialized failures
and unrun tails). The final queue/operator-identity suites separately
passed 52/52. This is aggregate coverage plus explicit reruns, not a
pristine single-command final-head run.
- After integration with current master,
queue/operator-identity/continuation suites passed 162/162 and affected
UI suites passed 140/140. ACP Stop/continuation and legacy
task/Inbox/message browser suites passed 9/9, including both task
recovery Retry and thread Try again, automatic saved-message delivery,
exactly one new run, Done, and retained output after reload. The default
process Stop/Pause/Resume browser case passed (the native-provider case
is opt-in and skipped by default). The complete Board attachment/receipt
browser suite passed 11/11 on a disposable instance, covering both
composers, exact receipts after lost responses, no replay, bound
attachments, and newer drafts after reload.
- Blocking-intent regressions cover pre-existing Blocked, a mismatched
run/cause, an explicit manual re-block, changed dependencies, a queued
comment after failure, and a block arriving between scheduling and
provider dispatch. The negative cases reproduced before the fix. All 478
affected executor/recovery/dispatch tests passed; both database suites
ran separately after availability-probe skips in the first combined
command. The final late-dependency check passed all 143 affected
recovery/dispatch tests (zero skips) after two new negative cases
reproduced the bug.
- Focused runtime regressions cover awaited runner ownership
publication, authenticated adoption before the first checkpoint,
old-finalizer detachment, idle and busy warm-session shutdown, rejected
checkpoint propagation, provider-pack verification, and managed-Codex
credential preservation. Four managed credential detachment cases
reproduced the bug before the fix; normal owned cleanup still succeeds
exactly once.
- Live local Claude: SIGKILL 2.6 seconds into startup recovered the same
run automatically in 53 seconds, then a normal follow-up completed in 24
seconds. SIGTERM 2.5 seconds into startup preserved the same run (54
seconds) and its queued follow-up (21 seconds). Answers remained visible
and the task reached Done.
- Live Claude Daytona: a warm follow-up retained its sandbox and fell
from 121 seconds to 44 seconds. A separate cold turn took 127 seconds;
after controller shutdown and checkpointing, its follow-up completed in
33 seconds with the same sandbox, workspace, native session, and runner.
Both answers remained visible and the task was Done.
- Other live journeys covered task completion and follow-up with local
and Daytona Codex, local Codex crash recovery, Stop then new direction,
clarification response, live artifact refresh, and shared-workspace
waiting.
- Validation limits: the opt-in native composer Stop/Pause→subtree
Resume fixture exposes terminal/result ordering and subtree-cancellation
attribution bugs that can leave a child task blocked; that new finding
is assigned to a separate follow-up and is not claimed fixed here.
Default CI skips this optional native-provider fixture. Managed-Codex
credential handoff and the queue-agent integration use automated
regression evidence. Cold custom provider-pack uploads still add startup
latency.

## Risks

- Automatic replacement remains deliberately narrow: local Codex,
verified stopped identities, unchanged retained state, and a complete
text/completion-only turn. Unknown actions, partial history, or changed
ownership remain blocked.
- Claude completion permission handling changes an upstream package
patch. The exact isolated task bridge must remain pinned; unrelated
tools keep their existing permissions.
- New task failure projection changes user-visible status. No historical
status backfill or database migration is included.
- This is a broad lifecycle fix across server and UI. Live proof covers
graceful local Claude restart during startup and idle Claude Daytona
session recovery across controller shutdown. Live abrupt SIGKILL during
local Claude startup also recovered the same run. Unknown ownership or
missing action evidence still blocks reuse. Cold custom provider-pack
uploads still add startup latency; this change avoids unnecessary repeat
uploads.

## Model Used

OpenAI GPT-6 (Codex), with reasoning, code execution, browser
automation, and tool use. The exact hosted model ID and context window
are 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 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-12 19:41:15 -05:00
Dotta 13bae6fa21
fix: reject unsupported REST tool connections without stdio validation (#13346)
## Thinking Path

> - Paperclip manages AI agents and their connections.
> - Connection checks must use the configured transport.
> - The tool service treated every remaining transport as local stdio.
> - Anthropic's old REST method therefore failed with a templateId
error. A REST connection with a valid stdio template could incorrectly
pass.
> - Anthropic now has a supported AI-account flow. This pull request
removes its obsolete REST setup option and limits stdio checks to stdio
connections.
> - Users can connect an AI account, and existing unsupported
connections receive an accurate error.

## Linked Issues or Issue Description

Related: #13248 added the supported AI-account flow. Searches for
related REST health and templateId bugs found no duplicate fix.

**What happened?**

The Anthropic REST API-key connection showed `Local stdio MCP
connections must use an approved templateId`. Health checks and catalog
discovery both fell through to the local stdio path. A REST connection
with an approved template could report success and expose the template's
catalog without a REST integration.

**Expected behavior**

Only local stdio connections use command templates. Unsupported
transports return an accurate HTTP 422 error. New Anthropic accounts use
the supported runtime authentication flow.

**Steps to reproduce**

1. Check out the test-only commit `924e6e85a` in a separate worktree and
install dependencies.
2. Run `pnpm exec vitest run packages/shared/src/app-definitions.test.ts
server/src/__tests__/tool-access-service.test.ts -t 'unsupported
REST|obsolete Anthropic'`.
3. The tests exercise saved Anthropic REST configuration and an
unsupported REST connection containing an approved stdio template. They
cover health checks and catalog discovery separately.
4. Run the same tests on the fix commit. They pass. The full affected
files also pass.

**Paperclip version or commit**

Reproduced against master `6cef9743c`.

**Deployment mode**

Server transport handling. Reproduced with an isolated embedded
PostgreSQL test database. No provider account or live credentials are
required.

## What Changed

- Restrict stdio health checks and tool discovery to `local_stdio`.
- Return and audit `tool_connection_transport_unsupported` with HTTP 422
for unsupported tool transports.
- Remove Anthropic's obsolete REST method from the generated catalog and
its durable ingestion source. Keep its subscription and API-key AI
methods.
- Cover the reported error, false-success case, rejected obsolete setup,
connection removal, and the UI's AI-account submission path.
- Replace impossible reconnect forms for removed methods with supported
setup, while preserving connection removal.
- Preserve AI-versus-tool intent isolation for legacy requests and
reject new unsupported Anthropic tool requests.
- Document recovery for existing unsupported connections.

## Verification

- Clean-worktree red/green: the same command failed all six regression
cases at `924e6e85a` and passed all six at `4d3de9de0`. The failing run
includes the reported templateId error.
- Green: all 555 tests across the six affected test files passed.
- Recovery UI red/green: three added cases failed before the recovery
fix and passed afterward; all 200 tests across setup, detail, and
advanced controls passed.
- After the recovery UI update, UI typecheck/build and token gates
passed again.
- `pnpm -r typecheck` — passed.
- `pnpm build` — passed.
- `pnpm check:token-gates` — passed.
- Catalog regeneration — passed with the documented
`PAPERCLIP_CONTENT_TEMPLATES` override for the local capture corpus.
- Full CI on `69fb31fd4` — passed all general and serialized test
shards, browser shards, typecheck, build, runner verification, and
canary dry run:
https://github.com/paperclipai/paperclip/actions/runs/34726975425.
- The local serial `pnpm test:run` was stopped after the fixture
correction superseded that run; full-suite verification above comes from
CI. All 555 affected tests passed locally, including all 17
connection-intent tests after the correction.
- Greptile — 5/5, successful check on final commit `69fb31fd4`, no
unresolved findings.
- No live Anthropic validation was performed. The UI regression uses a
fake key and a mocked AI-account response.

## Risks

Existing obsolete REST connections remain in needs-attention state.
Users must add an account through the supported flow and remove the old
connection. Credentials and grants are not transferred automatically.
Removal remains covered. The specialized AgentMail and Composio paths
keep their existing behavior. There are no schema or permission changes.

## Model Used

OpenAI GPT-6 through Codex. The exact serving model ID and
context-window capacity are not exposed in this session. Used reasoning,
code editing, shell tools, and test execution.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [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-12 19:26:58 -05:00
Dotta df984cbc2c
fix: dispatch queued legacy messages with operator identity and task permissions (#13315)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Task conversations save messages that arrive during an active turn.
> - Legacy adapters deliver these messages in a later turn.
> - A run can stop before the saved queue is delivered.
> - The Interrupt button previously required an active run, so it could
not release this queue.
> - This pull request lets a board operator send the saved queue after
the run stops and retries queues missed during finalization.
> - Manual dispatch must use the clicking operator and must not require
permission to create agents.
> - The task can continue without a duplicate message or a second
execution owner.

## Linked Issues or Issue Description

**What happened?**

A legacy task retained a queued message after its run stopped. Interrupt
was disabled because the queue had no active target. Finalization and
deferred message admission can also leave a queue without a successor.

**Expected behavior**

Interrupt sends the saved messages when no runner is active. Messages
that arrive during normal completion are delivered automatically. An
uncertain previous execution still requires proof that its process or
sandbox stopped.

**Steps to reproduce**

1. Queue a user message during a legacy conversation turn.
2. Let the turn stop or simulate a server restart before queue
promotion.
3. Open the task with a deferred queue and no active run.
4. Try Interrupt. Before this change, the button is disabled.

**Paperclip version or commit**

Reproduced against `8f40b4ad4`.

**Deployment mode**

Legacy conversation adapter. The same persisted queue state is covered
with an isolated PostgreSQL fixture.

Related public work: #13275 adds active legacy interruption. #13291
addresses automatic sandbox conversation recovery. This change handles
explicit saved-queue delivery and late queue promotion.

## What Changed

- Accept a null Interrupt target while retaining queue identity,
revision, company, and assignee checks.
- Save the operator's request on the existing queue. Reuse normal
admission after verified stop, including older messages, different
authors, and queues whose original wake came from the system.
- Strip interruption authority from caller-supplied wake payloads. Only
the board queue route can persist that authority.
- Retry durable interruption requests after restart and deferred queues
after legacy cleanup.
- Let an explicit Interrupt retry cleanup for its stopped run, including
old ephemeral leases that recorded success without a provider stop
receipt. Preserve retained resources, other lease owners, and the
automatic retry limit.
- Preserve the server's waiting explanation when normalizing and
combining queue entries.
- Revalidate the consumed board queue receipt at dispatch so a different
message author does not cause setup failure.
- Use the Interrupt user's execution identity for the new run. Preserve
original message authors. Validate the receipt independently at startup
and inherit the resulting identity on retry.
- Persist authenticated board authority for ordinary manual wakes too.
Adopting someone else's queued messages cannot switch a manual run to
that author's permissions. Strip caller-supplied authority markers and
retain private conversation ownership checks.
- Keep the clicking user when a manual wake is merged into an older
deferred receipt. Update its requester and payload in the same
transaction.
- Use the same current-queue/revision API on task details and pipeline
conversations; show Interrupt after a legacy target stops.
- Keep manual wakes out of active runs, including unscoped agent wakes.
They receive their own execution identity; a matching receipt requester
is not sufficient because an exact retry can retain a different
originating identity.
- Authorize both existing-agent wake endpoints with `agent:wake`,
available to active non-viewer company members. Keep `agents:create` for
hiring. Validate the stored task and current assignee before an exact
task retry.
- Reject viewer Interrupt requests before saving intent or stopping
execution. Keep external chat retry authorization and per-action
agent/user permission checks.
- Preserve edits and discards until dispatch. Prevent another queue
promotion when the same agent already has a successor. Keep independent
reviewer recovery available.
- Suppress cancelled/failed run toasts for intentional operator
interruption. Keep ordinary runtime error notices.
- Add UI, route, admission, restart, successor ownership, and toast
regression tests. Document the behavior.
- Reuse the existing socket reservation helper for both
credential-quorum test cases after CI exposed an ambient-port collision.
This changes test preparation only; production credential staging is
still called exactly once.

## Verification

- Failing regression tests reproduced the message-author identity bug
and an operator's `agents:create` rejection before the fixes.
- All 316 focused tests pass across eight route, queue, identity,
authorization, continuation, and responsible-user suites, including the
44-test rerun of queue admission and actual startup after the final
manual-wake restriction. Regressions reproduce cross-user merging both
with and without a task, and same-requester receipt ambiguity. The
cross-company existence guard also passes both tests.
- Startup integration tests reach adapter execution under the clicking
operator and retain that identity through follow-up. Coverage includes
mixed authors, adopted queues, system-origin queues, restarts, forged or
stale receipts, viewers, suspended memberships, changed assignees,
private conversations, and caller-supplied authority markers.
- The earlier queue/cleanup/UI regression suite passed 402 tests. The
final review corrections pass another 180 tests across queue
admission/persistence, real heartbeat startup, UI API, conversation
rendering, and pipeline suites. Regression tests reproduced both review
findings before correction. The final head has a 5/5 review with no
unresolved threads. Full CI passes on `c2002979c`, including every
general and serialized server shard, all browser shards, Paperclip
Runner verification, typecheck, build, canary dry run, and the aggregate
gates.
- Full `pnpm -r typecheck`, `pnpm build`, and UI token gates pass after
the final application changes. CI identified an outdated task-page API
mock after the shared helper extraction; the fixture now exercises the
real helper, and all 131 task-page/API tests pass. The final application
build passes with the additional manual-wake restriction.
- CI exposed a pre-existing port collision in the Codex
credential-quorum fixture. It reproduced locally; both listener cases
now use the existing bounded reservation helper. All 41 credential tests
pass on rerun. One intervening local run hit a separate ambient bind
collision in the two-occupied-port case.
- The full local `pnpm test:run` attempt was stopped after host
contention caused focused-suite timeouts. The affected focused tests
passed on rerun. An expiring trace fixture and a missing
private-conversation state were corrected. The successful full CI run is
the complete-suite verification.
- Hosted Interrupt previously cleared the original queue and produced
exactly one successor with neutral interruption feedback. It exposed the
dispatch authorization defect. Retry on that earlier build was rejected
for missing `agents:create` before creating another run.
- Deployed the final application build (`38257f391`) to the scoped
hosted instance and verified readiness. The latest PR commit changes
only the credential test fixture; application code matches that
deployment. A live Retry by the same operator without `agents:create`
created one successor attributed to that operator, passing the former
dispatch permission gate. Startup then stopped at
`configuration_incomplete` because that operator has not configured
their required personal Claude Code OAuth secret; the post-deployment
run page confirms the operator identity and no provider work started,
and the My secrets UI still shows the token as not set. Provider
execution remains unverified pending that credential. No permission
grants or credentials were changed.

## Risks

Queue admission and finalization can race. The task lock, durable queue
receipt, current comment IDs, and successor guard prevent duplicate
dispatch. Process and lease stop checks, task pauses, approvals,
ownership, and budgets remain in force. The API change only allows null
on legacy Interrupt; native steering still requires an active run. No
schema migration is required. Active non-viewer board members can now
invoke existing agents without agent-creation permission. Agent
self-invocation rules, raw provider-trace admin access, task retry
scope, external chat authorization, and action-specific user/agent
permissions remain enforced.

## Model Used

OpenAI GPT-6 through Codex. The session does not expose an exact backend
model ID 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
#` 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-12 17:11:30 -05:00
Dotta 8d6232e7b0
feat: reuse provider sign-in across AI connection workflows (#13248)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Users connect provider accounts during onboarding and agent setup.
> - They should reuse and manage those accounts through the existing
Connectors interface.
> - A second login wizard would diverge from the established provider
workflows.
> - This pull request composes the existing sign-in components into
Connections and agent configuration.
> - Users can select accounts without changing their agent's harness or
model.

## Linked Issues or Issue Description

**Problem or motivation**
AI credentials are configured separately from Connections. Agents cannot
consistently reuse a responsible user's account or a permitted shared
account.

**Proposed solution**
Manage AI accounts with the existing Connections grants and permissions.
Keep model and harness selection independent from credential selection.
Preserve legacy authentication until validated adoption.

**Alternatives considered**
A separate credential registry would duplicate ownership and access
policy. Automatic fallback would risk using the wrong account.

**Roadmap alignment**
This extends the shipped Apps, multi-user, secrets, and agent-runtime
capabilities. The maintainer requested the feature and reviewed the UI.
Related groundwork: #11899 (connection permissions), #10910 (connection
wizard), #11692 (Claude subscription profiles), and #11854 (Codex
account rotation).

## What Changed

- Add compact AI-account management to the existing Connectors pages.
- Reuse AgentProviderConnection, AdapterLoginPanel, AdapterLoginChrome,
and authentication controllers.
- Add the shared connection picker to agent setup/settings and task
requests.
- Preserve onboarding's sequence and reuse existing accounts.
- Add local-login recovery, retry, cancellation, and React StrictMode
handling.
- Add interactive Storybook scenarios, design-guide examples, and app
acceptance checks.

This is part 2 of the AI Connections change. The runtime foundation in
#13247 is merged. This PR now targets master.

## Verification

- Updated against master `47ded8bf9`, including the landed runtime
foundation and upstream task-search changes.
- Full workspace typecheck, production build, Storybook build, and token
gates passed on the integrated branch. Final local-login changes passed
59 focused tests; new-agent and inbox regression suites passed 63 tests.
- Browser checks verified automatic local Claude account detection,
resumable Codex login commands, retry, focus restoration, and
desktop/phone layouts. Commands create their isolated directory before
invoking the CLI.
- All CI test, browser, build, packaging, and runner jobs passed on
final head `dd17d3211931dd70aaa6ea619d83a7f9966dd18e`. The fresh
Greptile review is 5/5, the security scan passed, and there are no
unresolved review threads. The final CI aggregate gates passed.
- Local general-server coverage passed 11,804 tests; three
port-collision failures passed in an isolated 25-test rerun. All 6,111
UI tests passed. CLI coverage passed 484 tests; its remaining doctor
test requires port 3199, which is occupied by an unrelated report server
on this Mac. The complete CLI suite passed in CI.
- Live browser testing verified Codex API-key reconnect inside a task
card on desktop and phone. Real provider runs resumed and completed with
unchanged connection/grant identity and agent routing.
- Tested opening, cancelling, reopening, and completing connection
creation. A regression confirms Connect another account cannot submit
the new-agent form or copy provider keys into agent settings.
- Added shared inline repair, automatic local sign-in checks, and
responsive connection dialogs. Standalone Daytona installation ignores
workspace configuration and suppresses dependency scripts. Its
standalone build also passed with CI's exact pnpm 9.15.4.
- Destructive live tests are excluded by default. Explicit opt-in, local
deployment checks, and matching disposable fixture identities are
required before any mutation.

## Risks

- Local Codex/Grok creation requires the connection-specific terminal
login command.
- Browser sign-in uses the existing supported-environment controllers.
- This update verifies live local Claude detection and Codex API-key
task repair. New subscription authorization/refresh and
independent-human/native-runner isolation were not reverified in this
update.
- No agent automatically adopts managed Connections.

## Model Used

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

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (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-12 16:51:26 -05:00
Dotta 47ded8bf97
feat: manage AI runtime credentials through Connections (#13247)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Agent runs need credentials for a specific provider and sign-in
method.
> - Connections already owns accounts, grants, and access permissions.
> - AI authentication should use those same boundaries.
> - This pull request adds the storage, API, adoption, and runtime
foundation.
> - Legacy agents keep their authentication until they explicitly adopt
a managed connection.

## Linked Issues or Issue Description

**Problem or motivation**
AI credentials are configured separately from Connections. Agents cannot
consistently reuse a responsible user's account or a permitted shared
account.

**Proposed solution**
Manage AI accounts with the existing Connections grants and permissions.
Keep model and harness selection independent from credential selection.
Preserve legacy authentication until validated adoption.

**Alternatives considered**
A separate credential registry would duplicate ownership and access
policy. Automatic fallback would risk using the wrong account.

**Roadmap alignment**
This extends the shipped Apps, multi-user, secrets, and agent-runtime
capabilities. The maintainer requested the feature and reviewed the UI.
Related groundwork: #11899 (connection permissions), #10910 (connection
wizard), #11692 (Claude subscription profiles), and #11854 (Codex
account rotation).

## What Changed

- Add AI-purpose/runtime-auth contracts and an additive, idempotent
migration.
- Add Claude, OpenAI, OpenRouter, and Grok provider capabilities and
catalog entries.
- Store credentials on grants. Resolve responsible-user defaults or
explicit permitted grants.
- Isolate managed credentials and provider sessions across accounts.
Block missing credentials without ambient fallback.
- Keep imported legacy secrets unchanged during reconnect. Use
independent local Codex/Grok sign-in attempts for rotating credentials.
- Add authorization, migration, concurrent refresh, retry, cancellation,
and legacy-compatibility tests.

This is part 1 of a two-PR stack. The app UI follows in #13248. Merge
the foundation first.

## Verification

- Updated against master `04e364236`, preserving upstream provider login
and connector workflows.
- Full workspace typecheck, production build, Storybook build, and token
gates passed on the integrated branch. Final local-login changes passed
59 focused tests; new-agent and inbox regression suites passed 63 tests.
- Browser checks verified automatic local Claude account detection,
resumable Codex login commands, retry, focus restoration, and
desktop/phone layouts. Commands create their isolated directory before
invoking the CLI.
- All current-head CI checks passed on `2a996560a`, including all
server/workspace tests, browser shards, runner verification, typecheck,
build, and canary dry run. Greptile reviewed that commit at 5/5 with no
unresolved threads. Earlier local full-suite attempts hit the Mac
PostgreSQL shared-memory limit; the complete suites passed in CI.
- Renumbered the additive AI migration to `0276` after upstream
migrations and regenerated its snapshot. Existing legacy agents retain
their configuration.
- Added local login status checks, owner-scoped retry, managed OpenCode
remote homes, credential-aware model discovery, and task
connection-repair delivery.

## Risks

- Managed credential failures intentionally block execution. They do not
restore legacy fallback.
- Preview-era copied Codex/Grok subscriptions require independent
reconnect.
- The integrated branch has live provider acceptance coverage. This
update verifies local Claude detection and Codex API-key task repair; it
does not add a new subscription authorization/refresh or Daytona stress
pass.
- Runtime-auth connections must stay excluded from tool and channel
handling.

## Model Used

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

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (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-12 16:30:10 -05:00
Dotta 4d317274ce
feat(channels): add experimental iMessage Photon (#13299)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Channels connect external conversations to company tasks and agent
execution.
> - Slack, Discord, and AgentMail already provide durable delivery and
access controls.
> - People also need to reach an agent from Apple Messages and send
photos.
> - Photon provides shared Pro DMs, dedicated numbers, and authenticated
event recovery.
> - This pull request connects Photon to the existing channel services.
> - People can message an agent while Paperclip retains task ownership
and approval authority.

## Linked Issues or Issue Description

**Subsystem affected**

Cross-cutting: channel services, shared contracts, database constraints,
Apps, and agent Channels UI.

**Problem or motivation**

Paperclip has no iMessage channel. A person cannot use Apple Messages to
start a task, send a photo, or answer an agent's pending question.

**Proposed solution**

Add experimental **iMessage Photon** with Pro-compatible shared DMs or a
dedicated Photon Cloud number per agent channel. Reuse channel
admission, identity links, task generations, publication, and
interaction continuation. Keep groups disabled for shared allocation.
Dedicated lines support groups that an operator explicitly enables.
Require a fresh linked message and a published agent response before
setup completes.

**Alternatives considered**

Shared allocation has no owned phone number, so it reserves one project
and allows DMs only. Dedicated allocation reserves one stable number.
Local Mac access needs a separate deployment model. The upstream Photon
Chat SDK adapter does not persist the poll mappings and send receipts
required here. This change uses the lower-level SDK without adding
another agent runtime.

**Roadmap alignment**

This extends Connected Apps and agent communication through the existing
channel subsystem. It does not add a parallel tool connection or agent
loop. GitHub searches for Photon and iMessage found no matching provider
implementation.

**Additional context**

This ships behind the existing experimental channel gate. Dedicated-line
release qualification remains incomplete. Real Photon Pro DMs passed
task/reply, native poll, text answers, confirmation rejection, media,
restart, pause, reconnect, revocation, and removal tests. An
operator-supplied iPhone camera HEIC also passed the full round trip.
Dedicated groups remain unqualified. See [the verification
record](doc/connections/IMESSAGE-PHOTON-VERIFICATION.md) and [the
implementation plan](doc/plans/2026-09-11-imessage-photon.md).

## What Changed

- Add the provider catalog entry, shared setup contracts, and a forward
migration. A global partial index reserves the dedicated number or
shared project until its endpoint is archived.
- Add Cloud project inspection, vaulted project credentials,
selected-line token renewal, and a leased receiver. Persist checkpoint
updates under the receiver lease. Shared project replay accepts sparse
increasing sequences only after a complete recovery barrier.
- Connect DMs and enabled groups to existing task generations, sender
authorization, ordered delivery, and publication services. Keep each
iMessage conversation on its task after completion; only explicit `/new`
or `/close` releases the binding. Publish committed inbound comments
live and label their human bubbles “Sent from iMessage” in both
task-chat renderers.
- Persist immutable text/file send identities, upload receipts, poll
IDs, option IDs, per-person drafts, and canonical interaction
continuation proofs.
- Add source-bound file recovery, bounded HEIC/HEIF conversion, JPEG
previews, and related Live Photo companion video retention.
- Add the three-step setup flow and channel management surfaces with
official branding. Preserve the experimental gate and existing
pause/disconnect behavior.
- Add interactive production-component Storybooks for setup, access,
recovery, and ongoing conversations. Add provider, integration, catalog,
and browser regression coverage. Document setup, recovery, supported
boundaries, and qualification gaps.

## Verification

- Live Photon Pro, SDK 2.1.0: linked iPhone messages create a task and
receive native Codex replies in Apple Messages. Unlinked senders cannot
start work.
- Three real follow-ups each reopened the same completed task. Incoming
bubbles appeared on its open page without reload and showed “Sent from
iMessage.” The third follow-up ran after restarting the server on
`4d7222110`; the agent correctly repeated its previous reply from before
the restart.
- Native polls after restart, sequential text drafts, required-field
correction, explicit submission, approval rejection with a required
reason, and native continuation passed against Photon.
- PNG, text documents, synthetic HEIC, and a real iPhone camera HEIC
passed in both directions. The camera photo produced a 3024×4032 JPEG
preview. The native agent described it and returned the received HEIC
byte-for-byte.
- Pause/resume, reconnect, identity revocation, removal, `/status`,
`/new`, `/close`, and stale answers after close passed live. Messages
suppressed by pause did not become work on resume. Removal stopped
intake and removed credential bindings.
- All 304 focused tests passed on `4d7222110`. These cover Photon
unit/integration behavior, both task-chat renderers, live comment
hydration, completed-task continuity after restart, enabled groups,
duplicate delivery, and explicit reset/close. The selected Teams
completion-boundary regression also passed. Full workspace
typecheck/build and token gates passed for the conversation fix; the
final UI changes passed their affected typecheck/build and tests.
- All 26 new Photon Storybook Playwright cases passed in light and dark
themes, including the complete shared-DM setup journey and 390px mobile
follow-ups. UI typecheck and the Storybook build passed. These stories
use simulated Photon responses and do not replace the live evidence
above.
- The full chat-adapters browser suite previously passed all 39 cases.
Migration checks passed, and migration 0275 applied to the isolated live
instance with the earlier Photon migration already applied.
- The local full Vitest run was previously interrupted by the host's
embedded-Postgres shared-memory limit; it is not a full-suite pass. All
30 applicable CI checks passed on preceding head `7a5419cac`, with two
skipped checks and Greptile 5/5. Head `24f8e1aae` adds an explicit
required-story discovery guard to the 26 passing Storybook cases.
Greptile rates this final head 5/5 with no unresolved review threads.
All 30 applicable CI checks passed, with two optional checks skipped.
- A repeated live send key suppressed the duplicate but returned gRPC 6
/ SDK `internalError` without an original receipt. Paperclip keeps
unknown delivery unresolved. This provider behavior is covered by a
regression test.
- See [the verification
record](doc/connections/IMESSAGE-PHOTON-VERIFICATION.md) for package
versions, redacted live evidence, deterministic coverage, and remaining
qualification gaps.

## Risks

- Dedicated group qualification remains unrun; groups are disabled for
the approved Pro scope. Real iPhone camera HEIC passed transport,
preview generation, agent inspection, and return. Keep the channel
experimental; the dedicated-line release matrix remains incomplete.
- Shared recovery and attachment aliases were verified against the live
gateway. Duplicate writes currently return an error without the original
receipt; unresolved sends require operator resolution. The
implementation fails visibly on invalid replay ordering, a reset cursor,
or changed identity.
- The HEIF converter passed on macOS arm64 and in Linux CI. Windows HEIF
binaries have not been executed in this work. Linux musl has no packaged
converter. Unsupported conversion retains the original and reports the
missing preview.
- The migration adds a global reservation across companies for Photon
numbers and shared projects. Paused and revoked endpoints keep that
reservation until removal.
- Integration touches shared channel services. Existing provider browser
coverage passes; broad repository verification is recorded above.
- `pnpm-lock.yaml` is intentionally excluded under repository policy.
The repository bot owns lockfile updates. The additional Superagent
supply-chain scan is neutral/inconclusive because these new dependencies
are not yet in the committed lockfile. Its security scan passed; all
required CI checks pass.

## Model Used

OpenAI Codex, GPT-6 family, with reasoning, repository inspection, code
execution, browser testing, and tool use. The exact served model
identifier and context-window size are not exposed in this session. No
sub-agents were used.

## 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-12 15:23:50 -05:00
Dotta ed50a39c3f
fix: preserve NUL characters in run-event payloads (#13325)
Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-09-12 13:34:45 -05:00
Dotta c9021c6721
fix: require explicit native completion reviews (#13314)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Native runs report their outcome through paperclip_finish.
> - The server previously turned incomplete reports into human approval
requests.
> - Those requests could block a later successful run, even when no
person had requested review.
> - This pull request creates review cards only for explicit attention
requests and withdraws proven old fallback cards.
> - Agents receive useful completion feedback, while explicit approval
gates and task state protections remain in force.

## Linked Issues or Issue Description

Related: #13266 removed reviews caused by policy upgrades. This change
removes the separate completion fallback.

**What happened?**

An agent reported needs_review while waiting for checks without
requesting a human decision. Paperclip created a generic Native
completion review. A later successful report could not complete the task
because that old card remained pending.

**Expected behavior**

Ordinary low-risk work completes after a valid done report, a successful
run, and workspace finalization. Incomplete work stays with the agent.
Explicit approval requests remain visible and must be resolved.

**Steps to reproduce**

1. Complete a native run with needs_review and no attention requests.
2. Continue the task and submit a successful done report.
3. Observe that the old implementation leaves the task in review behind
a generic confirmation card.

## What Changed

- Require explicit attention requests to create native review cards.
Route each request independently and preserve pending or declined
decisions.
- Withdraw only pending system cards with matching old decision,
assessment, effect, contract, and prompt provenance. Preserve history
and explicit or answered requests.
- Reassess an affected current result without overwriting later task
edits, runs, contracts, or workspace failures.
- Return pending approval links and required actions through the
completion tool. Reject contradictory done reports and empty review
requests before accepting a result.
- Allow one corrective continuation for incomplete results, then expose
a recovery action.
- Update status fixtures, database regressions, runner tests, and the
completion contract documentation.

## Verification

- `pnpm -r typecheck` passed after merging current master.
- `pnpm build` passed after merging current master.
- The combined branch passed 89 completion and Agent Chat tests. Other
targeted tests passed: 170 external-chat and reconciliation tests; 50
runner-resume and control-plane tests; 13 arbiter tests; 7 chat delivery
tests; 21 runner completion and runtime-context tests.
- The full local test attempt exposed old review fixtures and a missing
fake-provider binary. The fixtures are fixed and the helper is built.
All affected suites pass in fresh reruns. The timing-sensitive Discord
test also passed on rerun.
- All latest-head CI checks passed, including build, typecheck, general
and serialized tests, runner verification, browser tests, and canary dry
run. Greptile is 5/5 with zero unresolved comments.

## Risks

- Cleanup changes existing pending cards. It requires exact system
provenance and only applies to low-risk agent-claim contracts. It does
not delete history or dismiss explicit requests.
- Status still commits after the turn and workspace finalization.
Completion feedback reports current constraints and does not claim an
early status commit.
- Incomplete reports now request a bounded corrective run instead of an
automatic approval. Repeated failures expose recovery.

## Model Used

OpenAI Codex, GPT-6, with repository inspection, code execution, and
test tools. The exact deployment 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-12 13:00:04 -05:00
Dotta 7e6d512597
fix(onboarding): make chief-of-staff hiring reliable (#13317)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - The first agent helps the board define work and hire other agents.
> - That agent can have the general role while its instructions require
hiring skills.
> - Missing skills and blocked schema discovery make valid requests
fail.
> - Repeated confirmation and invalid waiting guidance can turn these
failures into extra runs.
> - This PR supplies the required skills, opens read-only schema
discovery, and corrects the guidance.
> - The agent can complete an authorized hire while company approval and
duplicate checks still apply.

## Linked Issues or Issue Description

Refs #13068 — the first-task onboarding flow that this change repairs.
Refs #12029 — related drift between the sandbox allowlist and bundled
hiring guidance. This PR adds schema access; it does not replace the
earlier hiring-route fix.

**What happened?**

A general-role onboarding chief received hiring instructions without the
core hiring skills. Sandbox requests to the documented OpenAPI endpoint
failed. The agent then guessed question and hire payloads. The persona
required new confirmation after validation errors and described waiting
states that agents cannot set.

**Expected behavior**

A direct request authorizes the requested hire. The chief asks only for
material missing details, uses valid API payloads, and completes the
task. Formal company approval gates still apply. A saved human-input
card gives the task a valid waiting state.

**Steps to reproduce**

1. Create an onboarding chief with role `general` through the board.
2. Ask it to hire a friendly robot with a supplied name and
responsibilities.
3. Check its assigned skills, schema requests, question cards, hire
requests, and final task state.

**Paperclip version or commit**

Reproduced on the first-task onboarding implementation after #13068. The
live local verification used this branch at `112f44610`.

**Deployment mode**

The original failure used a hosted sandbox with legacy Codex ACP. Live
verification used an isolated local instance and real `codex_local`
execution. Queue and HTTP/2 transport access is covered by automated
tests.

## What Changed

- Give board-created onboarding chiefs the existing core skills
regardless of role. Preserve explicit skill version pins, including
aliases. Keep ordinary general-agent defaults and authorization checks.
- Allow exactly `GET /api/openapi.json` through both sandbox bridge
transports.
- Publish validator-tested question, free-text, hire, and waiting
examples. Regenerate the runner API reference and capability inventory.
- Clarify direct authorization, material ambiguity, and correction of
confirmed pre-creation validation failures. Preserve uncertain-outcome
reconciliation, duplicate protection, and company approval gates.
- Align disposition instructions with agent permissions and the saved
human-input waiting path.

## Verification

- After rebasing onto current `master`: 69 targeted server tests, 110
queue/HTTP2 bridge tests, and 4 capability inventory tests passed. These
cover core skill defaults, version pins, actor restrictions, schema
access, published examples, hire validation, idempotency, and approval
gates. Waiting recovery tests and live question flows also passed before
the rebase.
- `pnpm -r typecheck` and `pnpm build` passed again after the rebase.
Frozen dependency installation and both generated capability checks
passed.
- Ran the full `pnpm test:run` suite. The initial run had 14 failed
server files due to local database resource limits, a missing built test
fixture, and socket failures. All 14 files passed after fixture repair
and isolated retries. UI, CLI, workspace packages, database tests, and
all 145 serialized server files passed.
- Real one-request hiring replay: one hire, one successful run, task
done in 2m16s. No repeated approval or recovery escalation.
- Real two-turn browser conversation: start with an unspecified hire,
then supply a name and friendly robot responsibilities. One
clarification card, one hire, two successful runs, task done in 3m27s of
execution. No failed writes, confirmation cards, or recovery actions.
- Assigned the hired robot a welcome-message task through the browser.
It produced a warm message under 100 words and finished in one
successful 66-second run, with no questions or recovery actions.
- The two-turn flow still asked an optional preferences question and
gave a technical final reply. These are remaining presentation limits.
- Greptile: 5/5 on `b71f83ba2`, with zero unresolved review threads.
Fixed its generator finding and passed 1,655 published-example/runtime
API tests plus server typecheck. All latest-head CI checks are green (32
passed; 2 unrelated Storybook checks skipped). The signoff-policy
browser test initially timed out while waiting for an approver run. Its
shard passed on one rerun without code changes. [CI
run](https://github.com/paperclipai/paperclip/actions/runs/34698211049).

## Risks

- Onboarding chiefs receive more default skills. Ordinary general agents
retain existing defaults, and explicit versions take precedence.
- Prompt guidance can affect model behavior. The live replays are
examples, not a guarantee that every model follows the guidance.
- Retry guidance applies only when validation confirms that nothing was
created. Uncertain outcomes still require checking existing agents.
- No database migration or new public endpoint. Existing company
boundaries, approval gates, and bounded recovery remain in force.

## Model Used

OpenAI Codex, model `gpt-6-astra`, with reasoning, tool use, code
editing, and live browser verification. The exact 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 `#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-12 12:59:42 -05:00
Dotta ab15aff390
feat: add experimental persistent agent chat (#13284)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Conversations must use the same tasks, controls, and execution
history.
> - Users need an ongoing chat with an agent without managing task
properties.
> - Agents should clarify and plan work, then hand execution to assigned
project tasks.
> - This pull request combines the reviewed Agent Chat stack for one
squash merge.
> - The benefit is persistent conversation with normal task governance
and shared UI.

## Linked Issues or Issue Description

**Subsystem affected**

Task lifecycle, agent runtime tools, shared task UI, and browser/paid
runner tests.

**Problem or motivation**

Users need one persistent conversation with each agent. A separate chat
store or renderer would duplicate task behavior and bypass existing
controls.

**Proposed solution**

Use a task-backed chat per company, user, and agent. Reuse the task
composer and transcript. Clarify and plan in chat, then create assigned
project tasks with the relevant plan. Keep Agent Chat behind its own
disabled-by-default experimental setting.

**Roadmap alignment**

This implements the task-backed direction in [CEO
Chat](https://github.com/paperclipai/paperclip/blob/master/ROADMAP.md#-ceo-chat).
Related proposals: #2504 and #9693. Related request: #7981. The
maintainer requested one squash merge of the complete stack.

Consolidates the reviewed runtime
[#13281](https://github.com/paperclipai/paperclip/pull/13281), backend
[#13282](https://github.com/paperclipai/paperclip/pull/13282), and UI
[#13283](https://github.com/paperclipai/paperclip/pull/13283) layers
with this PR's E2E coverage. All four layers passed CI and received
Greptile 5/5 before consolidation. This PR targets master and includes
the complete feature.

## What Changed

- Add personal canonical chat tasks with ordinary company visibility,
immutable identity, idempotent first sends, and an idle waiting state.
- Process `/new` in queue order. Preserve history, release a chat pause,
and fence old provider context and delayed writes.
- Keep chat lifecycle rules across recovery, finalization, assignment,
task lists, and rollups.
- Support research and plan revision in chat. Hand plans to ordinary
assigned project tasks before execution starts. Reject new chat
subtasks.
- Add repository-aware project creation and discovery tools, including
multiple repository IDs and GitHub URLs, authorization, idempotency, and
durable project-created cards.
- Reuse task UI components for chat, with starred/recent agent
navigation and a separate `enableAgentChat` experimental flag.
- Add deterministic browser tests and 24 paid chat cells across four
Codex/Claude profiles, with validated reports and screenshots.
- Integrate current master recovery, controller lease, queued-message,
and task UI changes. Gate chat interruption and deferred promotion on
ownership/feature policy. Guarantee lease renewal and active controls
are stopped even if teardown fails.
- Preserve master's migration 0273 and generate chat migration 0274 with
idempotent replay for development databases.

## Verification

- Prior exact heads of all four PRs passed Linux CI, including build,
typecheck, general/serialized tests, and browser E2E. Each had Greptile
5/5 and no unresolved findings.
- Integrated local verification passed: full repository typecheck and
production build, Storybook build, token gates, 340 focused UI tests,
all 20 deterministic chat browser tests, two migration replay tests, 88
focused chat/queue/native/controller tests, and provider/session
regressions including real lease expiry. These include the three
lifecycle regressions for the final admission/teardown fixes; server
typecheck also passes. Current head
`1268eda16cc2af892055917e7292f068820be135` has Greptile 5/5 with no
unresolved findings and passing security scans. All final-head CI gates
passed: build, full Runner verification, typecheck/release registry,
canary, all general/serialized test shards, and all browser E2E shards
([CI
run](https://github.com/paperclipai/paperclip/actions/runs/34696739927)).
Local PostgreSQL startup contention required serialized retries; skipped
fixtures do not count as passing coverage.
- The earlier paid campaign passed all 24 chat cells and retained 32
screenshots:
[report](https://d1p6rlowie26tp.cloudfront.net/runner-e2e/campaigns/gha-34648511170-1/index.html?report=agent-chat#suite-agent-chat).
It tested `abacbdfd2f660709ec37312cdb758284c8399d04`; it is prior
evidence, not a paid run of this integrated head.
- Manual check: enable Agent Chat in Experimental settings, open an
agent, clarify and revise a plan, then hand off to an assigned project
task. Stop a reply, send `/new`, and verify fresh context with retained
history. Disable the setting and verify agent shortcuts/new chat turns
are blocked.

## Risks

- Queue/session integration can affect retries and delayed writes. Tests
cover ownership, cancellation, reset boundaries, idle recovery, and
ordinary task behavior.
- Migration 0274 adds conversation fields and constraints. Replay is
idempotent and preserves existing development chat history.
- This combines the previously reviewed stack at the maintainer's
request. Agent Chat remains off by default and is separate from
Conference Room.

## Model Used

OpenAI Codex, GPT-6 Astra (`gpt-6-astra`), with reasoning, code
execution, browser tools, and parallel review. The exact context-window
size is not exposed in this session. Codex and Claude also ran as test
subjects in the linked paid campaign.

## 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-12 08:56:04 -05:00
Devin Foley 5cc7784986
test: remove cold executable reads from runner integrity deadlines (#13301)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Native runner protocol tests verify that invalid authenticated input
fails closed.
> - Cloud readiness requires those tests to pass before a source commit
can deploy.
> - Two test fixtures hash the host Node executable twice even though
its process launcher is synthetic.
> - Cold reads of a large Linux executable consume time unrelated to
protocol failure handling.
> - This PR gives both synthetic runner fixtures tiny real artifacts and
keeps their existing deadlines.
> - Real authentication, encrypted frames, and request and notification
failures remain covered.

## Linked Issues or Issue Description

**What happened?**
Cloud readiness repeatedly failed in `DurablePrpControlPlane > promptly
fails the real transport request and notification paths on authenticated
bad semantic input (throwing observer: false)` with `Test timed out in
5000ms`. The image built, but the failed source check prevented
deployment. See runs
[34656885170](https://github.com/paperclipai/paperclip/actions/runs/34656885170)
and
[34657111560](https://github.com/paperclipai/paperclip/actions/runs/34657111560).

The first case took 5.6–11.4 seconds; the following case took about 0.4
seconds. The original test reads and hashes `process.execPath` once
itself and once through the real transport. The Node executable is
122,678,944 bytes in the local Linux Node 24 container, versus 68,672
bytes on the development Mac. Instrumented Mac runs pass; cold
executable reads are a likely cause of the CI-only timeout.

**Expected behavior**
The deadline should measure real protocol rejection and consumer
failure, without reading a large unrelated executable as test fixture
data.

**Steps to reproduce**
1. Run the named test with the real transport and synthetic process
launcher.
2. For a deterministic probe, inject a six-second delay into the first
`readFileSync(process.execPath)` call.
3. The original test exceeds its existing five-second deadline. Both
cases pass after this change because neither reads the host executable.
The probe is temporary instrumentation, not part of this commit.

**Paperclip version or commit**
f12b647ae; the same failure also occurred on a38ccf997 and 9031516a7.

**Deployment mode**
Cloud readiness in GitHub Actions on Linux AWS runners. No duplicate
open PR found after searching runner timeout and durable PRP changes.

## What Changed

- Write a 26-byte synthetic runner artifact inside each existing
temporary test directory.
- Bind both the real authority and test client to that artifact's actual
SHA-256 digest.
- Retain synthetic process launchers, real wire exchange, all observer
and composed-runtime cases, integrity assertions, cleanup, and existing
five- and fifteen-second timeouts.

## Verification

- Passed all 107 tests across
`src/control-plane/durable-prp-control-plane.test.ts` and
`src/drivers/codex/codex-protocol-integrity.test.ts` using the package
Vitest configuration.
- With a temporary six-second host-executable read delay, the original
case times out. Both fixed cases pass in 235 ms combined under the same
fault injection.
- Passed `git diff --check`.
- Full workspace typecheck and build passed. The full local test command
stopped after the general server group: 10,694 tests passed and 15
failed. Thirteen failures involve macOS directory rename permissions in
the skill-cache suites. Two failures involve a missing local AgentMail
skill path. Later groups did not run in that local invocation. The
targeted runner tests passed; all Linux CI test groups passed.
- [Current-head CI run
34661107658](https://github.com/paperclipai/paperclip/actions/runs/34661107658)
passed. All 32 checks are green or intentionally skipped at
`e7053594e647fd8e9b71fc569cab6b7a3e9cd210`. Native runner verification
passed in 15m25s. Greptile is 5/5 on that head, with no unresolved
review findings.

## Risks

Low risk: this changes test fixture data only. The launcher never
executes the file. Artifact hashing and authentication still use real
bytes. Protocol behavior and existing test deadlines do not change. The
current Linux CI run passed both fixtures and the full native runner
verification. Further post-merge runs will test repeatability.

## Model Used

OpenAI GPT-6 through Codex, with reasoning, repository tools, and code
execution. The exact serving model ID and context window are not exposed
by this environment.

## 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 (targeted runner tests;
full local suite limitations are 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-11 17:39:57 -07:00
Nicky Leach dbf5ea432d
fix: protect starting runs during overlapping deployments (#13285)
## Thinking Path

> - Paperclip controls agent work across service deployments.
> - A run can provision a remote sandbox before a process or invocation
event exists.
> - Each container previously treated its own missing process handle as
proof that the run was orphaned.
> - Overlapping deployments could therefore fail a run owned by another
container.
> - This pull request records and renews a controller lease before
provisioning.
> - A recovery worker must revoke an expired owner before it finalizes
the run.

## Linked Issues or Issue Description

Merged PR #13272 records startup adapter identity and restores explicit
user continuation. This PR adds controller ownership on top of current
master. Refs #7997 and #10442 for related replica and ownership
problems. Related #13138 addresses silence and detached local processes;
this change does not infer death from silence.

**What happened?**
During an overlapping hosted service deployment, a new container reaped
a legacy conversation run that another container was provisioning. The
run had no PID or adapter invocation yet.

**Expected behavior**
A live controller keeps its run. After controller loss, one recovery
worker takes cleanup authority and the old controller cannot dispatch
further work.

**Steps to reproduce**
Claim a legacy run in controller A. Start controller B against the same
database before A finishes provisioning. Run the startup reaper in B.

**Paperclip version or commit**
Observed on `663c44cb2b9c28336d38d0b4a6971f4f1964bce6` in a hosted
Railway deployment with a Daytona environment.

## What Changed

- Add nullable controller boot ID, lease deadline, and execution stage
columns. Claim ownership in the queued-to-running update.
- Renew ownership independently of run output. Abort and reject dispatch
if renewal fails.
- Serialize reaper revocation against renewal. Let unfinished recovery
claims expire after a restart.
- Restrict graceful shutdown to legacy runs owned by the current
controller.
- Hand ownership back to the existing native coordinator when runtime
selection becomes native.
- Add twelve database regressions and document the lease contract.
Update the task-drain regression to require controller expiry before
reaping.

## Verification

- `pnpm exec vitest run
server/src/services/legacy-controller-lease.test.ts
server/src/__tests__/heartbeat-task-drain-admission-release.test.ts`: 14
passed after rebasing onto master (`f12b647ae`).
- Queue-interruption regressions in
`heartbeat-process-recovery.test.ts`: 2 passed after preserving the new
cleanup promotion from #13275.
- `pnpm --filter @paperclipai/server exec tsc --noEmit`: passed after
rebuilding runner TypeScript outputs for the updated master. Broad local
tests are omitted at the maintainer’s request; CI owns broad coverage.

- Latest-head CI passed on `f255e8e4d5ab2b24b12638a02434e6aa8a2285c5`:
[run
34658248569](https://github.com/paperclipai/paperclip/actions/runs/34658248569).
All test shards, browser suites, typecheck, build, canary, and security
checks passed. Greptile is 5/5 with no unresolved review threads.

## Risks

- Additive, idempotent migration; historical rows retain the previous
recovery behavior.
- Database unavailability aborts new dispatch rather than permitting an
unfenced controller to continue.
- Lease expiry is permission to clean up, not evidence that remote
inference stopped. Follow-up PRs add persistent cleanup and automatic
continuation.
- Mixed-version deployment still includes old binaries whose reapers do
not understand controller leases.

## Model Used

OpenAI GPT-6 through Codex, using reasoning, repository inspection, code
execution, and test tools. The precise backend revision 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-11 16:55:44 -07:00
Dotta f12b647ae8
fix: reliably interrupt and resume legacy message queues (#13275)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - A task can collect more messages while its agent works.
> - Legacy runners must stop the active process before they can receive
those messages.
> - The old Interrupt action cancelled the run but could leave the queue
idle and hidden.
> - Codex could also classify a cancelled run as successful or start a
fresh process after cancellation.
> - This pull request joins cancellation, preserves the provider
session, and dispatches the current queue after cleanup.
> - The benefit is reliable interruption with the saved message order,
edits, and deletions.

## Linked Issues or Issue Description

**What happened?**

Interrupt could strand a legacy message queue. The UI could hide pending
messages after the run stopped. A Codex signal exit could race the
cancellation write. A stale session warning could also trigger a fresh
process after an interrupted resume.

**Expected behavior**

Interrupt stops the active turn and sends the remaining messages once,
in their saved order. Deleted messages stay deleted. An interrupted
Codex turn keeps its session and does not restart itself.

**Steps to reproduce**

1. Assign a task to a legacy Codex agent that runs a long command.
2. Queue three messages. Edit one, discard another, and move the last
message first.
3. Click Interrupt in the queue.
4. Repeat the interruption while the resumed session runs another
command.

Related work: Refs #13160, which moves native queue steering into the
wake-queue module. This change fixes legacy interruption and keeps
native steering unchanged.

## What Changed

- Add a revision-checked, company-scoped endpoint for legacy queue
interruption.
- Promote only the requested queue after the provider stops and releases
its lease. Retry its persisted interrupt intent from the scheduler after
a promotion error or server restart.
- Keep pending legacy queues visible after a run stops. Use server state
for the interrupt result.
- Serialize owned process cancellation before classifying the adapter
result. Preserve late session and log metadata. Acknowledge cancellation
only when an actual process or process group was owned; scheduler
placeholders retain their normal release policy.
- Send Ctrl-C to legacy Codex. Prevent missing-session fallback once the
session has started.
- Add cancellation race, multi-actor queue order, durable retry, resume
fallback, and stale request regression tests. Document the behavior.

## Verification

- Real browser tests passed with legacy Codex CLI and ACP engines, using
Codex 0.153.4 and gpt-5.6-sol.
- All three automated ACP browser scenarios passed locally: immediate
Interrupt delivery, no replay of an unfinished write, and pause
requiring Resume. Updated the old test expectation that required a
separate “go” after Interrupt.
- Browser tests covered queued edits, deletion, reordering, deleting the
final message, and repeated interruption.
- Two consecutive CLI interrupts kept one provider session. Both stopped
processes exited. The final message arrived once.
- `pnpm -r typecheck` passed.
- `pnpm check:token-gates` passed.
- All 346 post-review scheduling, recovery, queue-route,
archived-company, worktree-suppression, and stale-queue regression tests
passed.
- All 318 process-recovery and durable-chat tests passed after the final
cancellation guard.
- Codex adapter, queue UI, issue-page, and OpenAPI contract tests
passed.
- `pnpm build` passed.
- Full local suite coverage completed with
`PAPERCLIP_IN_WORKTREE=false`, using the stable runner and its CI
shards: 618 general server suites, all 145 serialized server suites, and
all workspace groups. Every failing suite passed a targeted rerun after
the fixes, rebuilding the native test fixture, correcting macOS
temporary-path setup, or retrying setup/timing failures. Existing skips
remain.
- The original monolithic run reported failures before the final fixes;
its failed suites were rerun rather than rerunning all 618 suites again.
The final process-recovery/durable-chat regression run passed all 318
tests.
- All CI checks passed for `e30eaf787f23a5511a3cb3cdb5abbccab9ed001d`:
[run 34654820774, attempt
2](https://github.com/paperclipai/paperclip/actions/runs/34654820774/attempts/2),
including typecheck, build, all test shards, E2E, and canary. The
signoff and Cursor sandbox tests each hit a timeout in the initial
attempt; both suites passed locally, and both failed shards passed their
single CI rerun. All three corrected ACP browser scenarios passed in CI.
- Greptile reviewed `e30eaf787f23a5511a3cb3cdb5abbccab9ed001d`: 5/5, no
open review threads.

## Risks

Cancellation order affects local adapters. The tests cover signal exits,
graceful exits, adapter exceptions, termination errors, and cancellation
write errors. Embedded adapters keep their cancellation controls.
Ordinary run cancellation and task pause keep their distinct queue
policies. No database migration is required.

## Model Used

OpenAI Codex, GPT-6, with reasoning, tool use, browser testing, and code
execution. The exact serving model ID and context-window size are not
exposed in this session. The live test runner used OpenAI 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: Paperclip <noreply@paperclip.ing>
2026-09-11 18:26:59 -05:00
Dotta 9031516a7e
fix: recover legacy Daytona startup failures from task and inbox (#13272)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Legacy conversation adapters can run in Daytona sandboxes.
> - A server restart during provisioning can occur before the invocation
event exists.
> - Recovery then lacks the old adapter identity and leaves a hold that
ordinary user retries cannot clear.
> - A remote launch can also fail when its host relay looks for Node in
the sandbox PATH.
> - This pull request records the adapter at claim time and restores
explicit user continuation after verified cleanup.
> - Users can recover from the task or inbox while the failed run and
uncertain action history remain intact.

## Linked Issues or Issue Description

Refs #13237, #13239, #13254. Those changes cover recorded conversation
runs, native user continuation, and explicit remote Stop. This change
covers legacy failure before `adapter.invoke` and exact task/inbox
Retry.

Refs #9771 for overlapping generated-command quoting. This change also
supplies the absolute host Node executable. Refs #13163 and #13264 for
the separate native restart and retained-workspace work.

**What happened?**
A legacy Daytona run interrupted during provisioning became
`process_lost` without an invocation event. Recovery preserved an
execution hold, and Retry or a new task reply could not resume it.
Cleanup could also run before the Daytona plugin was ready. On a macOS
host, a subsequent ACP relay launch failed with `env: node: No such file
or directory` because the remote launch environment did not contain the
host Node path.

**Expected behavior**
An interrupted conversation can continue after its previous execution
stops. Explicit Retry and new user replies should start a fresh turn
with the task history. Cleanup failures must remain visible and
recoverable. The host relay must use the host Node executable.

**Steps to reproduce**
1. Use a legacy Claude adapter with a Daytona environment.
2. Interrupt the server after it acquires the sandbox lease and before
it records `adapter.invoke`.
3. Restart and inspect the task hold.
4. Retry from the task or inbox, or send a new task reply.
5. Confirm the old sandbox has stopped and one new response arrives.

**Paperclip version or commit**
Reproduced from master at `3bafac12f796fbea02e609e1074a9639f872e9c4`.
The branch is rebased on `51b0e01ea`, including #13261 and #13270.

**Deployment mode**
Built from source on macOS with a real Daytona sandbox and the legacy
Claude ACP adapter.

## What Changed

- Count new browser specs with the scheduler's median duration in the
shard-balance check. This fixes a false policy failure after new specs
arrive from both branches. The balance threshold is unchanged.

- Persist server-owned adapter identity in the queued-to-running claim
before provisioning starts.
- Wait for provider plugin startup before restart cleanup. Keep failed
cleanup leases as active ownership blockers.
- Admit exact board retries and new user comments after verified
termination. Retain the old run, task history, approvals, and unknown
action outcomes.
- Adopt repeated Retry requests. Permit one scoped cleanup attempt per
explicit user Retry after the automatic limit, with an activity record.
A later user Retry can recover after a transient provider failure;
automatic attempts remain capped.
- Resume replies deferred during cleanup, including historical legacy
startup failures.
- Launch the host ACP relay through the absolute host Node executable.
- Add a task-level Retry button and return actionable blockers when
retry admission is refused.
- Add database regressions and three browser recovery journeys. Exclude
installed third-party dependency skills from the shipped-skill audit.

## Verification

- Current head: `d23c84181`, rebased on `51b0e01ea`. Conflict resolution
retains the saved-message recovery, local stop receipts, and wait
reasons from #13270 alongside exact legacy Retry support.
- Real Daytona: interrupted the server after lease acquisition and
before adapter invocation. Restart cleanup confirmed provider
termination. Task Retry cleared a seeded historical hold and a real
Claude agent returned `Recovery verified.` in the task. Removed the
disposable sandbox and environment after testing.
- All three browser recovery journeys passed again after the final
rebase. Task Retry, Inbox Retry, and a new reply each produced one fresh
successor, completed the task, preserved the failed run, and retained
the answer after reload.
- All 29 e2e/server shard-partition tests passed. The balance check now
uses the scheduler's median fallback for unmeasured specs, with the same
balance threshold.
- Server typecheck passed after rebuilding the generated runner
dependencies. The combined recovery/route run passed 136 of 137 tests.
Its remaining route test timed out during the first cold module import
at its explicit 10-second limit; an isolated rerun reproduced that
timeout and passed the other 51 route cases. The complete CI suite
passed on this head. The same route file passed all 52 cases in CI,
including the first cold import in 7.5 seconds.
- Before the final rebase, recursive typecheck, full build, UI token
gates, 132 targeted server tests, and the complete [CI
workflow](https://github.com/paperclipai/paperclip/actions/runs/34650004085)
passed. The subsequent CI failure was the shard-balance accounting
mismatch fixed here.
- Greptile reviewed `d23c84181` at 5/5 with no outstanding actionable
findings. The complete [current CI
workflow](https://github.com/paperclipai/paperclip/actions/runs/34653327949)
passed on attempt 2. All test, typecheck, build, and canary jobs passed
on the first attempt. Docker setup timed out fetching BuildKit from
Docker Hub; retrying that job and its dependent aggregate succeeded.

## Risks

- Recovery admission changes executable authority. Company, task, agent,
user, approvals, process ownership, and provider termination checks
remain required.
- Explicit continuation starts a fresh conversation with history. It
does not certify unknown external action outcomes or rerun
non-conversation adapters automatically.
- Changing task status alone does not clear an execution hold. The task
now offers an explicit Retry action.
- Historical adapter claims and invocation events take precedence over
current agent settings. Known process or webhook runs retain their hold.
Pre-upgrade rows with no adapter evidence may receive only a new
explicit user turn after termination proof; they do not become eligible
for automatic replay.
- No schema migration or sandbox-image change is required. This branch
has not been deployed to production.

## Model Used

OpenAI GPT-6 through Codex, with repository inspection, code execution,
browser automation, and test execution. The exact deployment model ID
and context window are not exposed in this session.

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-09-11 18:08:14 -05:00
Dotta 51b0e01ead
fix: resume saved user messages after execution recovery (#13270)
Preserve verified native process-stop evidence and retry saved user messages through normal continuation admission after recovery cleanup. Show the current wait reason and serialize delivery so a saved message starts one fresh turn.

Validated with 410 focused tests, typecheck, build, token gates, all PR CI checks, and Greptile 5/5.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-09-11 17:12:55 -05:00
Dotta 250deab910
fix(runner): keep healthy native sessions alive (#13261)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Native sessions keep a provider process and its work alive across
control-plane operations.
> - A hidden 15-minute turn deadline stopped work even when the agent
timeout was zero.
> - A one-hour runner lifetime and fixed connection lease added two more
limits.
> - Recovery also rejected goal commands because it reconstructed their
startup summary with the wrong protocol version.
> - This pull request removes implicit duration limits and renews
authenticated leases in the harness.
> - Healthy sessions can continue without model action or a user
interface change.

## Linked Issues or Issue Description

Refs #13092 and #12845. Related: #13163 covers sandbox recovery after
app restarts; this change covers session duration and lease renewal.

**What happened?**

A native Codex session stopped after 15 minutes while a tool was still
running. The agent had `timeoutSec: 0`. Recovery then rejected a
`session.goal.get` startup command with `invalid provider startup
ownership fence`.

**Expected behavior**

An unlimited session keeps working while its provider and authenticated
controller remain healthy. Lease maintenance is transparent. Explicit
timeouts, cancellation and revoked authority still take effect.

**Steps to reproduce**

Start a native session with `timeoutSec: 0` and run a tool beyond 15
minutes. Before this fix, the runtime cancels the turn. A recovery
startup that uses a goal command also exposes the protocol-version
mismatch.

## What Changed

- Honor the agent turn timeout. Zero disables the timer. Long explicit
durations use timer chunks to avoid Node timer overflow.
- Default native runner lifetime to unlimited. Keep bounded startup,
reconnect and control-operation deadlines.
- Renew leases over the authenticated connection. Persist renewal before
the reply. Validate identity, epoch and expiry. Handle duplicate
requests and a lost reply on reconnect.
- Freeze renewal during warm ownership transitions and terminal
handling.
- Validate persisted goal startup commands with protocol v2.
- Add duration, renewal, ownership, recovery and real-process regression
tests. Update runner protocol and recovery docs.
- Add no UI components or controls. Renewal requires no model output or
user action.

## Verification

Current head: `348e369c35c5da8bb8be378f4b35dcf6f40882e7`. [CI
run](https://github.com/paperclipai/paperclip/actions/runs/34649767113).

- All 32 checks pass on this head. The two Storybook checks are skipped
as expected. CI includes full build, typecheck, runner verification,
browser suites, server tests and the canary package dry run.
- Greptile reports 5/5 on this head. All review threads are resolved,
and the security scan passes.
- Passed `pnpm -r typecheck` and `pnpm build` locally.
- Passed 219 native-runtime and controller tests, including fake-clock
tests for three weeks of renewal and 30-day explicit timeouts. Six
denial tests confirm that renewal cannot extend expired, revoked or
mismatched authority.
- Passed 337 executor, cancellation and restart-recovery tests, plus 278
Rust runner-core library tests.
- Passed a real runner with a silent fake Codex provider across its
original lease expiry. Runner PID, provider PID, thread and active turn
stayed unchanged. Warm-attach recovery tests also pass.
- Passed all 83 plugin-worker tests and 159 of 161 workspace-runtime
tests locally. The two remaining assertions passed with a canonical
macOS temporary directory, as did the changed runtime fixture. The full
affected server shard passes in CI.
- An unchanged GitHub callback-ordering test failed once in CI, passed
locally in isolation, and passed its one test-shard retry. The final CI
summary is successful.
- The full local `pnpm test:run` sweep was interrupted after dependency
setup failures and load-related timeouts. Identified failing suites
passed in isolated reruns after the dependency repair. The complete test
matrix passed remotely in CI.

## Risks

- Deploy the controller and runner together to enable renewal. Older
peers keep their existing bounded lease behavior.
- Unlimited runtime permits long resource use until completion, explicit
cancellation, configured timeout or loss of valid authority.
- Lease renewal changes authenticated protocol handling. Regression
tests cover stale, revoked and mismatched authority, lost replies and
warm handoff behavior.
- Simulated multi-week tests and a real lease-boundary test do not
constitute a weeks-long production soak.

## Model Used

OpenAI GPT-6 through Codex, with repository inspection, code execution
and TypeScript/Rust test tools. The exact backend revision and
context-window size are not exposed in this session.

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-09-11 17:09:43 -05:00
Dotta 2083bf6f9a
feat(connections): add AgentMail inboxes and email tasks (#13256)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Connections give agents controlled access to external services.
> - Experimental channels already map conversations to tasks and durable
work queues.
> - Email needs inbox ownership, recipient envelopes, delivery records,
and explicit sends.
> - This pull request adds AgentMail to that infrastructure and keeps
the provider key in the server vault.
> - Agents can receive and send email from local or sandbox execution
while the board follows each conversation in its task.

## Linked Issues or Issue Description

**Problem or motivation**

Agents need dedicated email addresses. Incoming email should become
assigned work. Internal task comments and progress must never become
outgoing email by accident.

**Proposed solution**

Add experimental AgentMail connections, an inbox assignment wizard,
durable email intake and publication, task email cards, and
authenticated API, CLI, and native runtime actions. Agents use Paperclip
credentials to request sends. Paperclip owns the provider key and
enforces access and task authority.

**Alternatives considered**

A general mailbox MCP connector does not provide durable task binding or
publication boundaries. A separate mailbox application duplicates task
collaboration. The board instead directs the agent through the normal
task conversation.

**Roadmap alignment**

This extends the existing experimental connections and task
infrastructure. Product scope and interaction design were reviewed with
the maintainer. Related connection authority work: #11831 and #11818.
The duplicate search found no competing task-based AgentMail
integration.

## What Changed

- Add AgentMail catalog data, shared contracts, company-scoped email
records, and an additive migration.
- Add vaulted setup, inbox assignment, access grants, trust guidance,
and provider-side allowlist guidance.
- Support WebSocket and signed-webhook intake through a shared durable
pipeline, deduplication, catch-up, and task wakeups.
- Queue explicit new conversations and replies with immutable send
intents, idempotency, delivery state, and uncertain-send resolution.
- Show inbound and outbound email cards in normal task conversations.
Keep internal messages internal.
- Add task-scoped CLI actions and the sandbox callback routes required
for Daytona execution.
- Provide a dedicated AgentMail skill automatically only to agents with
active authorized inbox assignments. Keep email instructions out of the
universal Paperclip skill.
- Advertise connector-owned `agentmail_inboxes`,
`agentmail_read_thread`, `agentmail_send`, and `agentmail_delivery`
tools only in eligible native sessions. Recheck live authority on
execution.
- Isolate Codex CLI connector skills by agent and skill revision.
Deliver the assigned skill in the run prompt for adapters that use
shared skill directories, including resumed turns. Keep automatic skills
out of manual persistent sync. Show them as read-only and document the
pattern in the connector playbook.
- Fix AgentMail health checks that entered local-stdio validation and
optional missing Codex credential cleanup in sandboxes.
- Add API, pipeline, authorization, sandbox, browser, and Storybook
coverage.

## Verification

- Live AgentMail testing covered WebSocket intake, signed webhooks,
restart catch-up, and a full receive → task → Daytona Codex CLI →
explicit reply → Delivered round trip. The reply was verified in the
other inbox. The normal task composer also initiated an outgoing email
child task.
- The connector-skill change was verified in the browser: AgentMail
appears once as an automatic, read-only skill with its assigned address.
Disabling experimental chat connections removes it; re-enabling restores
it. A regression test covers assignment data arriving after library
data.
- Connector regression coverage passed 178 runtime utility, email
integration, skill-route, and heartbeat tests. All 17 Codex execution
tests passed, including per-agent skill isolation, model identity,
revision changes, removal, and prompt delivery without shared skill
files.
- After rebasing onto master, all 44 focused email, heartbeat, and
native-authority tests passed. All 313 native-session executor tests
passed. The UI regression suite passed all 3 tests. These test sets
overlap earlier focused runs.
- Full workspace typecheck and build passed after the rebase. Token
gates passed. Earlier focused Playwright task/setup coverage and the
Storybook build also passed.
- Native connector tool execution uses deterministic integration tests.
Live Daytona qualification used the Codex CLI adapter; the new
shared-home prompt fallback has deterministic coverage.
- The full repository suite is run by CI. The earlier unsharded local
full-suite attempt was stopped after the equivalent CI suites passed and
is not reported as a completed local run. Greptile reviewed
`7e57dc267a8446d3c906e3cc5b8abc94fb8860eb` at 5/5 with no unresolved
threads. All server, workspace, serialized server, and browser suites
passed in CI. The build job hit a five-second timeout in a runner
transport test; both variants and the full 80-test file passed locally
with unchanged timeouts. The build passed on retry on the same commit
without code or timeout changes. All required CI gates, including the
final `ci / verify` and `ci / e2e` summaries, are green on
`7e57dc267a8446d3c906e3cc5b8abc94fb8860eb`.

## Risks

- Email from external senders can start normal agent work. Setup
recommends a low-trust agent and AgentMail sender controls. Sender
addresses never grant board membership.
- Provider timeouts can leave uncertain sends. Retries retain their
idempotency key; expired windows require reconciliation or operator
resolution.
- Connector skills and native tools are assignment-dependent and require
current access. Revocation denies retained calls; assignment changes
select a new runtime context.
- Activation remains behind the experimental-channel setting. The native
runner path has deterministic coverage; live Daytona qualification used
the Codex CLI adapter.
- Schema changes are additive. Inbox ownership is unique across
companies. Disconnect preserves provider inboxes and task history.

## Model Used

OpenAI GPT-6 (Codex). Used reasoning, repository tools, code execution,
and browser testing. The exact deployment 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-11 16:56:38 -05:00
Dotta a12bbd1824
fix: stop completion reviews caused by policy upgrades (#13266)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - The native runtime records completion assessments and task
decisions.
> - An application update can change the assessment policy version.
> - The previous code treated that version change as a reason for human
review.
> - An upgrade alone does not give the user a new decision to make.
> - This change keeps existing decisions and withdraws obsolete upgrade
review cards.

## Linked Issues or Issue Description

**What happened?**

A rules version change moved unfinished tasks into review and created a
card that said, "Review the superseding native policy assessment." The
task did not need new work or a human decision.

**Expected behavior**

New runs use the current rules. An upgrade leaves existing task
decisions alone. The saved policy version remains available in the audit
history.

**Steps to reproduce**

1. Save a native run assessment and a task decision.
2. Change the native status policy version.
3. Run finalization reconciliation without new task evidence.
4. The previous code created a review card. The corrected code keeps the
saved assessment and decision.

Related context: #13038 changed the native policy version. Searches
found no duplicate fix for upgrade-only completion reviews.

## What Changed

- Remove policy-version mismatch as a reconciliation trigger.
- Withdraw pending cards only when their source decision, effect ledger,
creator, key, and prompt match the old upgrade-only review.
- Restore the previous status only while that decision and status
version remain current and no other review gate is pending.
- Preserve answered cards, real review requests, later task changes, and
historical assessments and decisions.
- Record cleanup activity and retire any corresponding chat review
actions.
- Isolate cleanup failures so one old card cannot block other cleanup or
normal finalization.
- Update the status conformance fixture, regression tests, and
architecture documentation.

## Verification

- Passed: `pnpm exec vitest run
server/src/__tests__/native-status-arbiter-corpus.test.ts` (23 tests,
including the 53-fixture status corpus).
- Passed: `pnpm -r typecheck`.
- Passed: `git diff --check`.
- Passed: `pnpm build`.
- Passed: fresh Greptile review at 5/5 on `d24e5ecaf`, with no open
review threads.
- Passed: the 23 focused tests in the isolated full-suite environment.
- Local `pnpm test:run`: the server group finished with 10,638 passed
and one missing-fixture failure. Built the required
`fake-codex-app-server` fixture and reran the entire affected native
session-resume suite: 37/37 passed. The initial full command exited on
that server-group failure, so remaining groups are covered by CI.
- Passed: the workspace-runtime-exposure suite (25 tests, 3 platform
skips).
- Passed: all CI gates, including every test shard, browser tests,
typecheck, and build. The server shard passed on one retry after an
unrelated host-port conflict in the unchanged workspace-exposure tests.
- Cleanup tests cover repeat runs, real reviews, answered cards, later
statuses, newer decision identity, status changes back to review, other
pending requests, run scope, cleanup failures, retry, and live
publication failures.

## Risks

- Cleanup changes stored task state. It checks the exact obsolete
decision and status version under database locks before restoring
status.
- Pending approvals, interactions, and execution stages prevent
restoration out of review.
- The cleanup handles at most 100 matching cards per reconciliation
pass. It does not rewrite old decisions or accept an agent's completion
claim.
- New evidence and explicit task changes still use the existing
reconciliation paths. This change does not reevaluate old work merely
because Paperclip was updated.

## Model Used

OpenAI Codex, GPT-6. The exact deployment identifier and context window
are not exposed in this session. Used reasoning, repository inspection,
code editing, shell execution, and automated tests.

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-09-11 16:55:46 -05:00
Nicky Leach ad4f0b5867
Fix Codex API key authentication in tests and runs (#13260)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - Agent runtime settings can bind organization secrets to an adapter
environment
> - Paperclip redacts plain environment values when it returns a saved
agent to the UI
> - A saved-agent test sent the redacted `CODEX_HOME` value back to the
server
> - Codex ACP also received the API key without an ACP API-key
authentication request
> - This pull request restores saved environment values for tests and
selects API-key authentication for Codex ACP runs
> - The benefit is that Codex agents can test and run with an
organization-scoped OpenAI API key

## Linked Issues or Issue Description

**What happened?**

Testing a saved Codex agent sent `***REDACTED***` as `CODEX_HOME`.
Secret normalization rejected that placeholder. Remote Codex ACP runs
received `OPENAI_API_KEY`, but session creation stopped with
`Authentication required`.

**Expected behavior**

Paperclip must use the saved `CODEX_HOME` value when it tests an
existing agent. Codex ACP must select API-key authentication when
`OPENAI_API_KEY` is available.

**Steps to reproduce**

1. Create an organization-scoped secret named `OPENAI_API_KEY`.
2. Give a Codex agent access to the secret.
3. Save the agent runtime settings.
4. Test the saved agent again.
5. Run the agent in a remote sandbox through ACP.

**Paperclip version or commit**

Reproduced on master before commit
`68c17709d7c051a804a416263e2e08920f1dfcb1`.

**Deployment mode**

Self-hosted server with a remote sandbox environment.

**Installation method**

Built from source.

**Agent adapter(s) involved**

Codex.

## What Changed

- Send the saved agent ID with adapter environment tests.
- Restore redacted plain environment values from the saved agent before
test-time secret resolution.
- Select the Codex ACP `api-key` authentication method when
`OPENAI_API_KEY` is present.
- Add focused regression coverage for saved-agent tests and remote ACP
launch configuration.

## Verification

- `pnpm --filter @paperclipai/adapter-utils exec vitest run
src/acpx-engine/execute.test.ts`
- `pnpm --filter @paperclipai/server exec vitest run
src/__tests__/agent-adapter-validation-routes.test.ts`
- `pnpm --filter @paperclipai/ui exec vitest run
src/lib/test-agent-setup.test.ts`
- `pnpm -r typecheck`
- `pnpm test:run`
- `pnpm build`
- `git diff --check`

## Risks

- Low risk. The test route reads saved configuration only when the
request supplies a compatible agent ID and the caller can update that
agent.
- The Codex ACP change applies only when `OPENAI_API_KEY` exists and no
explicit `DEFAULT_AUTH_REQUEST` exists.
- There are no schema migrations or telemetry changes.

> 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 with `gpt-5`. The context-window size is not exposed in
this runtime. The model used reasoning, repository search, file editing,
command execution, 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-11 13:58:29 -07:00
Dotta 3bafac12f7
refactor: remove automatic productivity reviews (#13263)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Its recovery loop keeps assigned work moving after execution
failures.
> - Productivity review used run counts, comment counts, and elapsed
time to create management tasks.
> - Infrastructure failures could satisfy those rules and create more
tasks without evidence that the source work needed management review.
> - This pull request removes that detector and its continuation holds.
> - Bounded recovery, budgets, explicit blockers, and normal review
stages remain in place.
> - Existing task records stay readable and unchanged.

## Linked Issues or Issue Description

Refs #5897. That request describes unwanted automatic productivity
reviews and asks to preserve existing tasks. This change retires the
feature instead of adding another configuration switch.

Related prior approaches: Refs #9191, Refs #12489. Those changes
excluded infrastructure failures or bounded review creation. This
removal replaces the detector rather than tuning its thresholds.

## What Changed

- Delete the scheduled detector, automatic task creation, evidence
refresh, and productivity continuation holds.
- Remove computed productivity fields, special attention items, badges,
and Storybook fixtures.
- Retain historical origin values, decision compatibility, and recovery
recursion exclusions. Add no migration and change no existing task data.
- Update the execution contract. Replace feature tests with regressions
for legacy task reads, ordinary attention, and bounded continuation in
the presence of an old review.

## Verification

- Targeted attention, issue-route, startup, and UI tests: 4 files and
101 tests passed.
- Updated issue-route and UI tests: 2 files and 61 tests passed.
- Bounded continuation regression: 2 cases passed, including a legacy
review plus pre-dispatch cancellation churn.
- `pnpm check:token-gates`: all four gates passed.
- `git diff --check`: passed.
- `pnpm build-storybook`: passed.
- Greptile: 5/5 on `a5a612eea`, with no actionable findings.
- Scheduler and historical recovery regressions: 2 files and 28 tests
passed.
- Repository `pnpm -r typecheck` and `pnpm build`: passed.
- The complete `pnpm test:run` suite passed across the CI server,
serialized-server, and workspace shards on `a5a612eea`. Stopped the
duplicate local monolithic run after the full CI suite passed; no
completed local full-suite result is claimed. The targeted local suites
above passed.
- CI serialized shard 5 initially hit a 10-second timeout in the first
interaction-route test. The complete file passed locally (78 tests),
then the single CI rerun passed.
- All CI gates are green, including the build and end-to-end suites.
- A local merge check against current `master` (`ce09ea40b`) completed
without conflicts.

## Risks

- API responses no longer include the computed `productivityReview`
field. Consumers must stop using it.
- The scheduler no longer creates management work from elapsed time, run
counts, or missing comments. This is the intended behavior change.
- Existing review tasks and explicit dependencies remain in place.
Historical origins still prevent recursive recovery treatment. No task
cleanup or data migration occurs.
- The native review handoff repair is separate from this removal.

## Model Used

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

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (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-11 15:46:35 -05:00
Dotta 663c44cb2b
fix: continue conversations after confirmed remote runner stop (#13254)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Users can stop a run and send another message on the same task.
> - Remote runners need evidence from their sandbox provider that
execution stopped.
> - Local process checks cannot prove that a remote process exited.
> - This pull request records provider stop receipts and uses them for
conversation admission.
> - New user messages can proceed after confirmed cleanup without
repeating interrupted actions.

## Linked Issues or Issue Description

Refs #13237 and #13239. Related: #13163 covers app-restart recovery;
this change covers an explicit stop followed by a new user message.

**What happened?**

A stopped remote Claude ACP task kept its execution hold after Daytona
cleanup succeeded. Native runners also rejected remote process
identities and retained stale session cleanup gates. A message sent
during cleanup could stay deferred after the sandbox stopped.

**Expected behavior**

After the provider confirms that the old execution stopped, a new user
message starts a fresh turn. Pending user messages must not need another
message to trigger admission. Prior action outcomes remain recorded.

**Steps to reproduce**

1. Start a long-running task in Daytona with a legacy Claude ACP or
native ACP runner.
2. Cancel the run while its tool is active.
3. Send a new message immediately, or after cleanup completes.
4. Observe the execution hold despite the old sandbox having stopped.

**Paperclip version or commit**

Reproduced on master at 7b829efdf6. The
branch is rebased on current master.

## What Changed

- Add optional provider stop receipts to sandbox release and destroy
hooks. Old plugins remain compatible.
- Bind receipts to the company, run, lease, and provider resource.
Failed cleanup cannot supply stop authority.
- Acknowledge legacy remote cancellation after confirmed termination.
- Admit native user continuations using remote receipts instead of host
process checks.
- Retire only the settled cleanup owner matching the stopped company,
run, and provider resource. Isolate cleanup gates between remote
sandboxes, including two sandboxes owned by one run.
- Reconsider user messages deferred during remote cleanup through normal
admission, including successful later cleanup retries.
- Preserve receipts through cleanup retries and inline cleanup after
failed startup.
- Permit provider destruction after a terminal remote checkpoint
failure. Busy ownership still blocks destruction.
- Add regression tests and update execution semantics.
- Give the real preview fixture ten seconds for cold startup. Reuse
release-mode Rust artifacts for the filtered parity checks, avoiding a
duplicate debug test build that exhausted CI disk twice; test filters
and assertions are unchanged.

## Verification

- Recursive typecheck and build passed.
- Targeted server, Daytona plugin, and native runtime tests passed. They
cover missing or mismatched receipts, failed cleanup, local process
protection, exact cleanup ownership, and a message sent during cleanup.
- Live Daytona tests passed for legacy Claude ACP, native per-turn,
native warm, and a newly created native runner using disposable
sandboxes. Each original run was cancelled; its explicit follow-up
completed with no execution hold. The disposable case confirmed a new
sandbox after deletion.
- Native tests used the provider's Opus 5 selector, `opus[1m]`, and the
Linux runner bundle from the sandbox image. Existing checkpoint/sync
finalization warnings remained visible before the native follow-ups
reached committed success. This change does not repair those separate
warnings or guarantee recovery of uncheckpointed files.
- A direct live provider test also passed with the final delete-wait
change: the destroy hook returned its receipt only after Daytona
reported the sandbox destroyed. The final Daytona plugin suite passed
all 153 tests; its build passed.
- After rebasing on master, 284 targeted server/plugin tests and 313
native executor tests passed. The native session runtime suite passed
all 128 tests.
- The review regression passed all 145 tests across the continuation,
environment runtime, and pending-cleanup sweep suites. Recursive
typecheck and build passed again after that fix.
- The security review's exact-resource finding is fixed. Cleanup
completion requires the same provider-resource scope used during session
creation. All 128 native runtime tests, 61 server continuation/cleanup
tests, recursive typecheck, and build passed after this fix. The
two-sandboxes-in-one-run regression proves one receipt cannot retire the
other quarantine.
- Greptile reviewed the final commit at 5/5, the security scan passed,
and no review threads remain unresolved. The final native executor suite
also passed all 313 tests.
- The full local suite reached 10,616 passing tests before stopping on
four failures. All four now pass in focused reruns: the final-code
continuation/teardown suites, the attachment suite, and the native
session test after building its required fake-provider binary. The
original full run overlapped source edits and did not reach the
remaining groups; it is not counted as a full-suite pass.
- The preview exposure suite passed all 25 applicable tests (three
Linux-only tests skipped locally) after the startup allowance change.
Both release-mode Rust parity commands passed locally. All final-head PR
checks passed, including full server/workspace/browser test groups, full
native runner verification, build, typecheck, canary dry-run, and the
aggregate gates.

## Risks

- A provider must return a receipt only after confirmed termination.
Incorrect provider claims could permit overlapping execution.
- Older providers without receipts retain the existing hold. Missing
evidence, failed cleanup, active ownership, pauses, approvals, and
budgets still block admission.
- This change preserves unknown action outcomes and old checkpoints. It
does not authorize replay or alter historical runs.
- No database migration or telemetry contract change is required.

## Model Used

OpenAI GPT-6 through Codex, with repository inspection, code execution,
and browser tools. The exact backend revision 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 references)
- [x] My branch name describes the change and contains no internal
Paperclip ticket id or instance-derived details
- [x] I have run targeted 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-11 15:18:37 -05:00
Dotta b1efd65edc
fix: continue interrupted task conversations with bounded retries (#13237)
## Thinking Path

> - Paperclip manages AI agents and their tasks.
> - A task can outlive a provider process or a server restart.
> - Legacy recovery treated unknown tool outcomes as a permanent
execution hold.
> - That hold could also reject a later user message.
> - A conversation turn can use prior history without replaying prior
tool calls.
> - This pull request lets supported conversation adapters continue
within the existing retry budget.
> - Users can send a new message after automatic attempts stop.

## Linked Issues or Issue Description

**What happened?**

A server restart could interrupt a local ACP run and leave its task
behind a permanent recovery hold. A later user message could be
cancelled before the provider answered. The immediate recovery path
could also create a successor outside the durable failure counter.

**Expected behavior**

Continue with a bounded new conversation turn. Preserve a compatible
provider session or use full task context when it is unavailable. Do not
replay recorded tools. When automatic attempts stop, allow a new user
request through the normal execution gates.

**Steps to reproduce**

1. Start a task with a local conversation adapter.
2. Restart the server while the provider is working.
3. Let the previous run become interrupted.
4. Send a follow-up message and observe the recovery hold on the old
behavior.

Related work: Refs #13075 for durable task recovery. Refs #12946 for
retry-limit and checkout-lock handling. This change routes conversation
recovery through the existing bounded scheduler.

## What Changed

- Mark supported local conversation failures for continuation. Keep
native-runner and non-conversation recovery rules.
- Carry an interruption notice into the next turn. Retain stopped ACP
session history even when a write outcome is unknown.
- Clear unavailable ACP sessions so the next bounded attempt can use
full task context.
- Route immediate failure recovery through the same durable scheduler as
process-loss recovery. Release only the predecessor checkout when its
retry takes ownership.
- Retire obsolete conversation holds using immutable run evidence, in
bounded batches with an activity record. Preserve outcome evidence and
do not wake historical tasks.
- Block actual admission and Resume while a predecessor process or
environment lease is still active. Keep the original interruption notice
after a rejected wake. Preserve the upstream blocked-wake waiting
contract: bounded retry planning can happen during cleanup, while
deferred messages and execution remain gated.
- Add subprocess and database regression tests. Update the execution
contract.
- Add the current thread-status field to the native recovery provider
fixture so its damaged-journal test reaches the intended boundary.
Tolerate an already-exited fixture process during test cleanup while
still asserting both processes terminate.

## Verification

- Workspace typecheck passed: `pnpm -r typecheck`.
- Build passed: `pnpm build`.
- Module boundaries passed: `pnpm check:module-boundaries`.
- Focused tests passed: 293 recovery/session/dispatch tests, 66 retry
and response-gate tests, and 37 native-session tests. Some suites
overlap.
- Tests cover interrupted writes, missing sessions, concurrent retries,
restart persistence, pending questions and approvals, execution gates,
and historical holds.
- Built the Rust test executables with `pnpm --filter
@paperclipai/paperclip-runner build:rust` for native-runner
verification.
- Full Vitest coverage verified locally using the repository’s general
and serialized shards, with focused reruns for failures and files not
reached after a shard stopped. The ownership-gate regression is fixed
and the complete affected server shard passes (1,390 tests). Local
parallel runs also hit temporary-directory, resource, and timing
failures; those suites pass with canonical temporary paths and
sequential reruns. No test timeouts were increased.
- Final merged-branch regression run: 577 tests pass across process
recovery, retry scheduling, liveness, durable chat, wake-queue
application/adapter, dispatch, continuation, native sessions, and task
chat. Earlier focused verification also passed 19 native control tests.
Token gates and whitespace validation pass.
- Browser verification passed all three ACP Stop/continue/pause
scenarios, including a rerun after merging the upstream waiting
behavior: `PAPERCLIP_E2E_PORT=3397 pnpm test:e2e
tests/e2e/acp-stop-continuation.spec.ts`. The interrupted-write case
verifies that follow-up completes without a repeated write.

- Final-head [CI run
34625037394](https://github.com/paperclipai/paperclip/actions/runs/34625037394)
passed on `06ac4bd9d150f8b209a96e5fd609c696958794a0`: all 31 reported
checks are green, including server/workspace suites, all browser shards,
native runner verification, build, typecheck, release dry run, and
aggregate gates. The two conditional Storybook checks were skipped.
Greptile reviewed this exact commit at 5/5; all review threads are
resolved.

## Risks

- A new model turn can choose to repeat an action. Paperclip does not
replay recorded tool calls and does not certify unknown action outcomes.
- Conversation adapters now stop after their retry budget instead of
requiring action reconciliation. Explicit Stop, pause, dependency,
approval, budget, and ownership gates remain in force.
- No schema migration or dependency changes. Historical holds are folded
without changing task status or waking work.

## Model Used

OpenAI GPT-6 through Codex, with reasoning, repository tools, code
execution, and test execution. The session does not expose a more
specific model build 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-09-11 12:16:04 -05:00
Dotta 1616046c24
fix(runner): prevent trace scans from delaying live events (#13228)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - The native runner sends events that keep task state and steering
controls current.
> - Debug trace correlation reread and parsed the full trace for each
pending event.
> - Repeated scans blocked event delivery and left task state minutes
behind the provider.
> - This pull request indexes appended trace records once and reuses
those correlations.
> - Operators get current run state while native trace evidence remains
available.

## Linked Issues or Issue Description

**What happened?**
Native runs appeared live after their provider turn ended. Steering was
unavailable while the board still showed an active run. A CPU profile
attributed 93% of sampled time to trace lookup and file reads.

**Expected behavior**
Debug trace correlation must not delay run events or task state by
minutes.

**Steps to reproduce**
1. Enable native provider trace capture for a Codex run.
2. Produce a long event stream with pending correlations.
3. Compare provider event times with persisted run event times.

**Paperclip version**
Reproduced on source build 6dd48cad43.

**Deployment mode**
Self-hosted server with the native Codex runner.

Related event-delivery work: Refs #12208. This fix addresses synchronous
trace lookup rather than disconnect draining. Searches found no
duplicate trace-index fix.

## What Changed

- Add a transport-owned incremental index for native trace frame
correlations.
- Read at most 1 MiB per lookup and retry incomplete prefixes and
partial records.
- Preserve latest-frame and terminal-status ordering. Invalidate
replaced or truncated traces.
- Clear each index on transport close. Keep active indexes independent.
- Skip correlation records over 64 KiB without buffering or parsing
their full contents. Preserve the original trace file.
- Add regression tests for repeated misses, appended records, partial
UTF-8, large traces, replacement, and cleanup.
- Document the trace lookup performance constraint.

## Verification

- Latest revision: 11 index regressions and the existing real-runner
trace correlation test pass (12 tests).
- Includes 24 interleaved active traces, oversized records across
appends, and incomplete later interpretations.
- `pnpm build` and `pnpm -r typecheck` pass on final head `ddc74e42c`.
- The real-process hard-restart regression passes after rebuilding its
fake-provider binary from the rebased sources.
- The full local test command reports a pre-existing assertion mismatch
in `native-session-resume.test.ts`: the damaged-epoch recovery case
expects the old attach error instead of the new startup-history error.
The same exact failure was reproduced in an isolated checkout of
unchanged base `a20ecce40`. The PR does not change that test or startup
behavior.
- A recorded-trace benchmark reduced 120 lookups from 2.20 seconds to 22
milliseconds.
- The deployed hotfix removed the scan hotspot. The final main-thread
profile was 94% idle. A guarded restart reported no lost runs.
- All GitHub checks pass on `ddc74e42c`, including build, typecheck,
general tests, serialized server tests, end-to-end tests, canary dry
run, and security checks. Greptile is 5/5 on that exact head with no
open threads.
- Two timeout cases from the long local run pass in isolation: exhausted
quota-monitor evidence and native-question expiry. The duplicate full
local run was stopped after the complete CI suite passed.

## Risks

Each active transport retains event-to-frame mappings in memory and
clears them on close. Records over 64 KiB do not enter the correlation
index; the original trace file retains them. Large traces can need
multiple pending retries before a correlation is available. These
records are diagnostic; this change does not alter execution authority,
event acknowledgements, or provider commands.

## Model Used

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

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-09-11 09:57:34 -05:00
Nicky Leach 87b3e5fc61
fix(adapter-utils): stage selected skills into the sandbox for a remote Claude ACP run (#13196)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - A user selects skills for an agent, and the host materializes those
skills into a bundle the agent reads
> - An agent can run in a remote sandbox, where the host must stage
every file the agent needs
> - On the Agent Client Protocol lane the host built that bundle and
then named its host path in the prompt, but it never staged the bundle
into the sandbox
> - The agent therefore read a path that does not exist inside the
sandbox, and the run failed on the missing skill file
> - The command-line lane of the same adapter already stages a `skills`
asset and reads the in-sandbox directory back from the staged runtime
> - This pull request carries that proven pattern to the Agent Client
Protocol lane, so a selected skill reaches the agent in a remote run

## Linked Issues or Issue Description

No public issue exists for this change. The description follows.

**What happened?**

A remote run of the Claude adapter on the Agent Client Protocol lane
could not read any selected
skill. The host builds the skill bundle in its own state directory, then
writes that host path into
the prompt as `Skill root: <path>`. The remote seam of that lane staged
one asset only, the
configuration seed. It staged no skills asset, so no skill file crossed
into the sandbox. The agent
then tried to read the skill file at the host path, and the read failed
with a missing-file error.

**Expected behavior**

A remote run receives the skills the user selected, and the prompt names
the directory that holds
those skills inside the sandbox.

**Steps to reproduce**

1. Select one or more skills for an agent that uses the Claude adapter.
2. Start a run for that agent in a remote sandbox on the Agent Client
Protocol lane.
3. Ask the agent to read the skill file at the path the prompt names.
The file is not there.

**Agent adapter(s) involved**

The Claude local adapter, on its Agent Client Protocol lane. The shared
engine in
`packages/adapter-utils` carries the prompt rewrite.

**Additional context**

The command-line lane of the same adapter already stages a `skills`
asset and remaps onto the staged
directory. This change reuses that mechanism instead of adding a new
transport. One other adapter
shows the same host-path shape on its own Agent Client Protocol lane.
That lane is tracked
separately and this pull request does not change it.

## What Changed

- Return the host skill bundle directory from the Claude skill runtime
step, and carry it through the
remote managed-home context to the staging seam. The value is null for a
non-Claude agent, for a
run that selects no skill, and for a run whose selected skills all fail
to materialize.
- Stage that bundle as a `skills` asset on the Claude Agent Client
Protocol remote seam, and only
  when the run selected a skill.
- **Stage that asset with `followSymlinks: false`.** The bundle holds an
owned copy of each selected
skill, and the copy step never copies a symbolic link at the root or at
any depth. So the bundle
contains no symbolic link, and staging has none to follow. Refusing to
follow one also stops a link
planted in the bundle directory after the copy from pulling an unrelated
host file into the sandbox.
A regression test walks the real adapter sources and pins the reviewed
`followSymlinks` value at
  every skills staging site, so a new or changed site fails the test.
- **Drop a skill whose staged copy has no usable `SKILL.md`** from the
prompt, the skill identity, the
command notes, and the bundle, and log which skill was dropped and why.
Without this, a skill whose
copy failed, or whose `SKILL.md` is a symbolic link the copy step skips,
stayed advertised in the
prompt while its file was absent — the same missing-file symptom this
change exists to fix.
- Rewrite the `Skill root:` prompt line, the skill identity, and the
command notes onto the
in-sandbox directory. The rewrite runs in the engine, after the
workspace placement returns the
staged runtime. A compatible session resume reuses the cached staged
runtime, so the rewrite runs
  on that path too.
- Keep the session fingerprint on the host-independent skill identity. A
change to the selected skill
set still invalidates a warm session, and the volatile sandbox path
stays out of the hash.
- A local run, and a run with no selected skill, keep their current
behaviour.

## Verification

- `pnpm exec vitest run --project @paperclipai/adapter-claude-local
src/server/acp.test.ts` — 28 of 28
  pass.
- `pnpm exec vitest run --project @paperclipai/adapter-utils
src/acpx-engine/execute.test.ts
src/skills-staging-follow-symlinks.test.ts`
  — the new engine tests and the staging-site tests pass.
- `pnpm --filter @paperclipai/adapter-utils exec tsc --noEmit`, and the
same check on the adapter
  package — both exit 0.
- The end-to-end test drives the lane against a local sandbox stand-in.
It reads the skill root out
of the prompt the runtime received, and then opens the skill file at
that path. That is the
  reported symptom, proved closed.
- The new tests carry a sensitivity control. Restoring only the
production files to their previous
content fails 7 of the 9 new tests. The other 2 do not depend on
production code: one is a parser
  unit test for the source scanner.

## Risks

Low risk, and the change is a two-way door. A revert restores the
previous behaviour exactly.

- **Scope.** The change touches one adapter lane. It does not change the
local lane, and it does not
change any other adapter. No existing staging site changes its
`followSymlinks` value.
- **The staged bundle and the workspace.** The staged skills land under
the runtime directory inside
the workspace. The workspace restore excludes that whole runtime
directory, so the staged skills
never return to the host worktree. A test proves the exclusion end to
end.
- **Session reuse.** The rewritten path never enters the session
fingerprint, so it cannot invalidate
  a warm session, and a compatible resume applies the same staged path.
- **Direction of data.** Files move from the host into the sandbox only.
The change adds no path that
  writes sandbox content onto the host.
- **A dropped skill.** A skill with no usable `SKILL.md` is now absent
from the prompt instead of
named but unreadable. The run logs the skill and the reason, so the
cause is visible.

## Model Used

Claude Opus 5 (`claude-opus-5`), with extended thinking and tool use,
through Paperclip agents.

## Test plan

- [x] `pnpm exec vitest run --project @paperclipai/adapter-claude-local
src/server/acp.test.ts` passes — 28 tests.
- [x] `pnpm exec vitest run --project @paperclipai/adapter-utils
src/acpx-engine/execute.test.ts
src/skills-staging-follow-symlinks.test.ts` passes.
- [x] `pnpm --filter @paperclipai/adapter-utils exec tsc --noEmit` exits
0.
- [x] All continuous-integration gates are green.
- [x] The automated review reports no open finding against the current
head.

## Required 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 bug report
template
- [x] I have not referenced internal or instance-local Paperclip issues
or links
- [x] My branch name describes the change and contains no internal
Paperclip ticket id
- [x] I have run the targeted tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect this change
- [x] I have considered and documented the risks above
- [x] All continuous-integration gates are green
- [x] The automated review score is 5/5 with no open current-head
findings
- [x] I have addressed every reviewer comment that applies to the
current head

**Note on the branch history.** This branch first carried a different
change: a filename-based admission filter that refused to stage files
such as `.env` from a skill directory, together with a switch from
symbolic-link bundles to copied bundles. That approach was rejected and
**reverted** on this branch. It does not match the documented trust
boundary, because the host already delivers credentials into the sandbox
on purpose, and replacing the symbolic-link bundles broke live editing
of a skill. The revert is in this branch's history. The file that work
changed, `packages/adapter-utils/src/server-utils.ts`, is byte-for-byte
identical to `master` here and is not part of this diff. Earlier review
findings that name that file target the reverted code. All of them are
resolved, and the automated review passes on the current head.

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-09-11 07:50:06 -07:00
Dotta a05b828bcd
Reduce run polling and workspace inspection amplification (#13174)
## Thinking Path

> - Paperclip manages agent work and shows run progress to operators.
> - Run lists, live events, transcripts, and workspace details must
remain responsive as usage grows.
> - Run-list redaction rereads the full context for every run. Hidden
tabs can still trigger requests through live events and manual timers.
> - Workspace detail reads repeat Git inspection even when concurrent
callers request the same state.
> - This pull request batches registry reads, pauses hidden-tab
refreshes, and caches Git inspection for display.
> - Cleanup keeps fresh Git checks, and redaction keeps company and run
boundaries.

## Linked Issues

**What happened?**
Run-list responses perform one extra database read per run and parse
full context JSON to obtain small secret registries. Hidden tabs
continue transcript reads and event-triggered refetches. Workspace
detail requests repeat Git scans.

**Expected behavior**
A run list reads registries once. Hidden tabs stop recurring run reads
and reconcile when visible. Concurrent workspace detail reads share a
short-lived Git result.

**Steps to reproduce**
1. Open run lists and task transcripts in several tabs while agents run.
2. Hide some tabs and observe transcript and event-triggered requests.
3. Request a 200-run list and count redaction database queries.
4. Request the same workspace detail concurrently and count Git
inspections.

Related: #5255 adjusts polling cadence. This change addresses hidden-tab
lifecycle, batched registry reads, and workspace inspection reuse. No
duplicate with this scope was found.

## What Changed

- Batch heartbeat and live-run redaction into one company-scoped
registry query. Select only registry JSON for run and issue redaction.
- Resolve duplicate secret values once per request. Preserve each run's
registry and remove registry material from responses.
- Suspend company event sockets and transcript reads while hidden.
Refresh active queries and resume transcript offsets on return.
- Prevent queued event invalidations and developer health polling from
fetching in hidden tabs. Gate legacy run-log readers in both UI
variants.
- Exclude legacy plugin placeholder connections from remote health
probes. Select only due connection IDs in SQL before the sweep limit.
Preserve existing plugin records.
- Cache concurrent Git display inspections for five seconds, with at
most 256 entries. Leave close-readiness and cleanup checks uncached.
- Add regression coverage and document the performance behavior.
- Stabilize the existing Rust descendant-lineage fixture: allow a
bounded 30 seconds for 300 durable notifications under concurrent test
load, retaining every correctness assertion and adding timeout
diagnostics.

## Verification

- Regression coverage verifies one registry query for 200 runs, per-run
isolation, request-local secret resolution, decryption failures, Git
cache expiry/bounds, hidden-tab pause, and visibility recovery.
- Real PostgreSQL redaction/run-route suites passed all 57 tests;
workspace-service coverage passed. The health-sweep regression verifies
plugin placeholders and chat connections remain untouched and do not
consume the sweep limit.
- Both legacy transcript viewers retain history and resume their byte
offset after visibility changes. The related visibility/progress/chunk
suites passed all 29 tests. Other focused UI suites and token gates
passed.
- Full `pnpm -r typecheck` and `pnpm build` passed. Affected-package
typechecks/builds passed after review fixes. The concurrent Rust
provider suite passed 84 tests (two ignored), and Rust formatting
passed.
- Full local `pnpm test:run` stopped after the general-server group:
10,538 passed, 65 skipped, four failed. Fresh chat-delivery and
health-sweep reruns passed; building the debug runner fixture cleared
the native-event test. One unchanged native-session recovery assertion
still fails locally with a semantic-digest error instead of the expected
settled-session message. The full local command is therefore not green.
CI runs the later groups separately and skips the two native-session
tests requiring a prebuilt runner binary (confirmed in its 37-test
native-session suite).
- All CI gates pass on final head `ee610e737`: typechecking, general and
serialized tests, browser tests, runner verification, build, and canary
dry run. One server shard passed on its single retry after exposure
fixtures encountered port 42001 where they assumed 42000; that suite
also passed locally (25 passed, three platform-specific skips).
- Greptile reviewed the final head at 5/5 with no actionable findings.

## Risks

- Workspace delivery display can lag local Git changes by five seconds.
Destructive operations still inspect current state.
- Hidden tabs do not receive company live-event notifications until
visible. Active queries refresh on return.
- This change preserves legacy plugin records and does not repair
instance-specific workspace rows. There is no database migration.

## Model Used

OpenAI Codex, GPT-6 family, with reasoning, repository tools, code
execution, and browser inspection. The exact 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 (targeted regressions;
full-suite limitation 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-11 08:34:24 -05:00
Nicky Leach d1ba17eeca
fix(adapter-utils): fail fast when the sandbox control channel is lost mid-turn (#13158)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - Adapter utilities run agent turns and report their results to the
control plane
> - A lost sandbox control channel can leave an agent turn without a
result
> - The host then waits for the full adapter timeout instead of
reporting the loss
> - This pull request adds a push loss signal and a bounded host wait
> - The benefit is a prompt failure terminal when the agent stops
answering

## Linked Issues or Issue Description

**What happened?**

A sandbox control channel loss during an Agent Client Protocol turn left
the host waiting for the four-hour adapter execution timeout.

**Expected behavior**

The host should detect the terminal channel loss, stop the turn, and
report a safe failure without waiting for the agent.

**Steps to reproduce**

1. Start an Agent Client Protocol turn through a sandbox adapter.
2. Close the duplex control channel while the turn remains active.
3. Observe the host response before the adapter timeout expires.

**Paperclip version or commit**

Test the pull request commit set at
`10b6bbc5525a79fd575298607dd5a25ae448fc8a`.

**Deployment mode**

The change applies to sandbox-backed adapter execution.

## What Changed

- Add `onLoss(listener)` to the duplex bridge handle.
- Register the loss listener at turn start and read losses latched
before turn start.
- Cancel the turn on loss and arm a 30-second host deadline.
- Close the stream locally when the deadline wins and create a host
terminal.
- Derive the public error from the closed `DuplexLossReason` enum.
- Add tests for loss order, cancellation, timeout, and safe error
output.

## Verification

- Run `pnpm --filter @paperclipai/adapter-utils exec tsc --noEmit`.
- Run `pnpm --filter @paperclipai/adapter-utils exec vitest run
src/acpx-engine/execute.test.ts -t "run-disposition seam"`.
- Confirm that the full pull request workflow passes.

## Risks

The new deadline changes a lost-channel path from a long wait to a
host-built failure after 30 seconds. Orderly completion keeps its
existing behavior. The deadline race against a pending `turn.result` has
no direct test.

## Model Used

OpenAI Codex, GPT-5, with tool use and code execution. The runtime does
not expose a more specific deployment version or context-window size.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` /
`Closes: #` / `Refs: #` OR (b) described the issue in-PR following the
relevant issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [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-10 15:37:05 -07:00
Nicky Leach c1b55537ba
fix(paperclip-runner): bump claude-agent-acp pin to 0.73.0 (#13162)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - The Claude local adapter can run agent turns through an ACP (Agent
Client Protocol) server, `claude-agent-acp`, instead of the plain CLI
> - Two separate packages each pin their own copy of that dependency:
`packages/adapters/claude-local` (the server-side adapter) and
`packages/paperclip-runner` (which builds the provider pack baked into
every managed sandbox image)
> - `claude-local` moved to `^0.73.0` in #12730, but `paperclip-runner`
was never bumped past `0.70.0` — nothing keeps the two in sync when only
one changes
> - That split means a sandbox image built from `paperclip-runner`'s
provider pack ships a `claude-agent-acp` the server-side adapter was
never actually compatible with
> - This pull request bumps `paperclip-runner`'s pin to `0.73.0`, the
only version that satisfies both packages' declared ranges at once, and
fixes the matching hardcoded version assertion in
`docker/daytona-runner/Dockerfile`
> - The benefit is one consistent, compatible `claude-agent-acp` version
across both the server host and every sandbox image built from this
source, instead of a silent split that only surfaces as a runtime
failure

## Linked Issues or Issue Description

No public issue exists for this specific split; opening directly per
CONTRIBUTING.md path B, following the bug report template fields.

**What happened?**
`packages/paperclip-runner/package.json` pins
`@agentclientprotocol/claude-agent-acp` at an exact `0.70.0`.
`packages/adapters/claude-local/package.json` requires `^0.73.0` (added
in #12730, 2026-09-02). Nobody re-synced `paperclip-runner`'s pin after
that change — the two packages' dependency graphs are independent, so a
bump in one doesn't propagate to the other. `paperclip-runner`'s copy is
what the fleet sandbox image's provider pack actually ships, so every
managed sandbox built from current source carries a `claude-agent-acp`
version the server-side adapter's own declared compatibility range
excludes.

**Expected behavior**
The two packages' `claude-agent-acp` pins should stay within a mutually
compatible range, so a sandbox image built from this source always ships
a version the server-side adapter actually supports.

**Steps to reproduce**
1. Check `packages/adapters/claude-local/package.json`'s
`@agentclientprotocol/claude-agent-acp` range (`^0.73.0`).
2. Check `packages/paperclip-runner/package.json`'s pin for the same
package (`0.70.0` before this PR).
3. Note that `^0.73.0` on a `0.x` version only admits patch releases
(`>=0.73.0 <0.74.0` per semver caret rules), so `0.70.0` falls outside
it.

**Paperclip version or commit**
`master` as of this PR (paperclip-runner still at `0.70.0` prior to this
change; claude-local's `^0.73.0` requirement landed in #12730).

**Deployment mode**
Any deployment that runs `claude_local` agents through the ACP engine
against a sandbox image built from `packages/paperclip-runner`'s
provider pack (managed cloud sandboxes in particular).

Related PRs for context (not duplicates — none of these touch
`paperclip-runner`'s pin):
- #12730 — introduced the `^0.73.0` requirement in `claude-local`
- #11873 — the last time `paperclip-runner`'s pin moved (`0.69.0` →
`0.70.0`)
- #13105 — separately made an unavailable ACP engine a hard failure
instead of a silent CLI fallback, which is what turned this version
split into a visible, run-blocking error rather than a quiet downgrade

## What Changed

- Bump `@agentclientprotocol/claude-agent-acp` from `0.70.0` to `0.73.0`
(exact pin, matching this package's existing pin style for its other
agent-CLI dependencies) in `packages/paperclip-runner/package.json`.
- Update the corresponding hardcoded version assertion (`test
"$(claude-agent-acp --version)" = "0.70.0"`) in
`docker/daytona-runner/Dockerfile` to `0.73.0`, so its own build-time
check stays accurate instead of failing on the next build for an
unrelated reason.
- `pnpm-lock.yaml` is intentionally **not** included —
`pr-trusted.yml`'s `Validate dependency resolution and regenerate stale
lockfile` step already regenerates it for the merge tree and hands it to
downstream `--frozen-lockfile` jobs as an artifact, so a manual lockfile
commit here would just be stale the moment CI runs.

## Verification

- `0.73.0` is a real published version on npm (confirmed via `npm view
@agentclientprotocol/claude-agent-acp versions`), and it's the *only*
version satisfying claude-local's `^0.73.0` range, so this isn't a guess
at compatibility — it's the unique intersection of both packages'
declared ranges.
- `grep -rn "0\.70\.0" docker/ packages/paperclip-runner/package.json`
after this change shows no remaining stale references to the old pin.
- I did not run a full local install/test pass against a hand-updated
lockfile, since regenerating one locally would conflict with leaving
`pnpm-lock.yaml` untouched per the note above; CI's own
lockfile-regeneration step is the intended verification path for a
manifest-only dependency bump like this one.
- Downstream/full verification (does a sandbox image actually built with
this pin work end-to-end) is tracked separately in `paperclip-cloud` —
an unrelated internal-only repo, so not linked here — where a sibling
fix restores the ACP servers to the runtime `PATH` in the fleet sandbox
image itself; both fixes are needed together for a working sandbox, but
this PR is scoped to the version pin alone.

## Risks

- Low risk: single-line dependency version bump plus a matching
test-assertion update, no code changes. `0.73.0` is a patch release
within claude-local's own already-declared-safe range, so there's no
reason to expect it changes behavior tenants depend on.
- The main risk is unknown breaking changes between `claude-agent-acp`
0.70.0 and 0.73.0 that aren't caught by the version-string assertion
alone (that check only confirms the binary reports the right version,
not that its behavior is unchanged). I have not audited that package's
own changelog between those versions.
- `docker/daytona-runner/Dockerfile` is a parallel/reference image (per
its own header comment, meant to stay aligned with the private
`paperclip-cloud/fleet-sandbox-image/Dockerfile`, which is out of scope
here) — this PR does not touch that other Dockerfile.

## Model Used

Claude Sonnet 5 (`claude-sonnet-5`), via Claude Code, with tool use
(file edits, shell/git, `gh` CLI, `npm view` for version verification).
No extended-thinking mode. Standard Claude Code context window.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass — see Verification: a
manifest-only bump with the lockfile intentionally left to CI's own
regeneration step; no local test run applicable
- [x] I have added or updated tests where applicable — version-pin bump
only, no new behavior to test
- [x] I have updated relevant documentation to reflect my changes — none
applicable
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green — pending CI run on this PR
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups —
pending review
- [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 Sonnet 5 <noreply@anthropic.com>
2026-09-10 11:35:33 -07:00
Dotta 889947c238
feat: add experimental native chat connectors (#13038)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - People also ask agents for work in their existing chat tools.
> - Each external conversation needs one task and a current authorized
source.
> - Retries, Stop, and provider failures must not duplicate work or
expose private data.
> - The first chat PR establishes the opt-in provider and data
contracts.
> - This PR adds experimental channel integration and its durable
control plane.
> - Users can request work from connected channels and inspect delivery
in Paperclip.

## Linked Issues or Issue Description

Refs #13100 and #13092. This is the second of exactly two chat PRs.
Foundation #13100 is merged and changed 143 files. Runner prerequisite
#13092 is also merged. This PR changes 400 files against master, below
the 500-file review limit. It contains no wireframe images or HTML
galleries.

## What Changed

- Add native Slack, GitHub, Microsoft Teams, Telegram, and Discord chat
connections. Keep chat disabled unless the operator enables experimental
chat connectors. Preserve the production GitHub tool connection and its
normal setup path.
- Bind each provider bot identity to one immutable Paperclip agent. Bind
each admitted external conversation to one task. Paperclip owns tasks,
runs, permissions, and audit records.
- Add durable admission, per-conversation queues, questions, task
controls, progress, final replies, images, files, and delivery receipts.
Board comments remain internal unless explicitly sent to the channel.
- Check current identity, provider reach, resource access, credentials,
runtime generation, and exact source before provider effects. Keep
private responses private. Never send raw reasoning, private logs,
credentials, or tool arguments.
- Hold uncertain sends for explicit audited resolution. Make Board
Send-to-channel atomic and idempotent. Keep reconnect and setup
credentials in Paperclip secret storage.
- Preserve current native-runner authority across retries, lost
acknowledgements, and recovery. Keep immutable input and completion
contracts separate from newer user input. Receipt reconciliation cannot
launch a provider.
- Reconcile chat close/new ordering and provider-effect lock order.
Audit resource access changes in the same transaction. Submit only the
selected resource from each UI toggle so stale pages cannot undo
unrelated access changes.
- Drain Codex stdout before certifying process exit. Bound the drain
with the existing shutdown grace. Preserve observed terminal authority
without treating an undrained process as successful or reusable.
- Incorporate master `018ca5da` with its ACP Stop, mobile task layout,
runner packaging, and official lock changes. Preserve dedicated
chat-answer continuations in both directions when ordinary queued
comments are adopted after Stop.
- Fence late adapter readiness behind an earlier Stop for the same run.
Preserve verified cleanup for registered adapters. Handle single Stop,
agent pause, duplicate Stops, and failure release without creating a
false cancellation receipt.
- Incorporate master's `6dd48cad4` wake-queue extraction. Preserve exact
failed-chat retry authorization and lineage, retired question-source
suppression, and the block on generic recovery that would discard the
admitted source. Fresh deferred input retains its separate promotion
path.
- Incorporate master `2a05b5ed3` and its queue-admission extraction,
simplified transaction ports, and separate runner CI job. Preserve exact
durable receipts, actor separation, and dedicated-answer isolation
through the new module. A failed receipt insert rolls back the
accompanying deferred-wake merge.

## Verification

Current head: `afe19299d06253cb628eb398e91d1200ea9f412a`, incorporating
master `2a05b5ed3457ea33efd6895520447d1d97fe98d8`. The conflicts are
resolved. This successor fixes two test-harness boundaries exposed by
CI: per-case route-module preparation and actual durable-save completion
before intentional runner termination. Production code and all existing
test/turn deadlines are unchanged. [Exact-head Greptile
review](https://github.com/paperclipai/paperclip/pull/13038#issuecomment-5587250594)
is **5/5**, completed September 10 at 13:20:55 UTC, with no actionable
findings or open review threads. [Fresh exact-head
CI](https://github.com/paperclipai/paperclip/actions/runs/34481724341)
passes **all 24 jobs**, including Build and both required aggregates.
Normal exact-head guarded merge was attempted and rejected by the
remaining branch approval policy: CODEOWNER review is required and no
human approval is present. Normal **squash auto-merge is enabled** as of
September 10 at 13:36:26 UTC. Requested CODEOWNERS have been notified;
no approval bypass or self-approval was used. Earlier-head results below
remain historical evidence, not qualification of this successor.

- Final exact-head Linux evidence: 995/995 chat integration cases; 36/36
agent-skills routes; 35/35 runner live-session cases, including real
process kill/resume; 1948 runner Vitest cases with three existing
benchmark/platform guards; 870/870 API-authority cases; and 104 browser
cases with four existing optional skips. Rust, conformance/replay, full
repository build, typecheck, canary, all server/workspace shards, and
both required aggregates pass with normal CI concurrency. Earlier failed
attempts remain recorded below.

- Latest test-only qualification: 141/141
route/permissions/authentication cases pass in separate cold forks, with
plain server types and independent review clear. The real-runner suite
passes 35/35, with plain runner types and independent review clear. A
controlled premature-save acknowledgement fails as expected; matching
ownership/effect/process evidence, rejected saves, real turn outcome,
test abort, and pre-kill liveness are covered. No local reproduction of
the original CI scheduling failure is claimed. The preceding [CI
run](https://github.com/paperclipai/paperclip/actions/runs/34479680858)
passes 21/24 jobs, including all 995 Linux chat cases and browser
aggregate (104 passed, four existing optional skips); only Build, the
skills serialized shard, and the required verification aggregate fail.
Its exact-head Greptile review was 5/5. Both failed job logs are
retained.

- Final fixture qualification: all eight focused Discord cases and all
995 chat integration cases pass. The exact modal statement/PID is
observed before taking the real connection lock; the test then proves
its actual blocking relationship before mutation. Original SQL
execution, provider behavior, negative assertions, and 1s/15s timeouts
remain unchanged. Independent review is clear and test/production hashes
remain frozen. The preceding [CI
attempt](https://github.com/paperclipai/paperclip/actions/runs/34477184777)
passed 22 jobs, including Build/runner, typecheck, canary, all other
test shards, and browser aggregate (104 passed, four existing optional
skips); the two fixture failures and failed verification aggregate
remain recorded, not relabeled as a pass.

- Current queue-module composition: 308/308 recovery/batching/queue/Stop
tests; 995/995 full chat integration; 89/89 module tests, including real
PostgreSQL receipt-insert rollback; 24/24 workflow/module-boundary
tests; plain server and UI types. All four actual local process/ACP
browser paths pass in 1.4 minutes. Fresh databases, no skips or retries,
stable reviewed source hashes. The initial boundary failure is retained;
its no-op service wrapper was removed without changing recovery context
or weakening the check. An exploratory standalone test-directory
typecheck fails because its new upstream transformation config is not a
standalone typechecking project; standard CI/build does not invoke it,
and no configuration was weakened to suppress those diagnostics.

- The preceding head `e02a63d462ce5d47433b0aeb632bb6fd20aab1ba` passed
[all 24 CI
jobs](https://github.com/paperclipai/paperclip/actions/runs/34436462958)
and exact-head Greptile review at 5/5. Required CODEOWNER review
prevented its normal merge before master advanced again.

- Final extracted-module composition: 307/307 recovery, batching, queue
and Stop-control tests; 995/995 full chat integration; 49/49 module
tests including eight PostgreSQL adapter cases; and 19/19 issue-update
tests. Plain server types pass. All four actual local process/ACP
browser paths pass in 1.3 minutes. Fresh databases, no skips or retries
in these cohorts, frozen source hashes, and independent review clear.

- The preceding head `3e4e1c1c` passes [all PR CI
jobs](https://github.com/paperclipai/paperclip/actions/runs/34415826820),
including Build and required `ci / verify` and `ci / e2e`. Both the
original Rust failure and the previously load-sensitive lineage fixture
pass with unchanged Linux concurrency. Master advanced afterward and
required this reconciliation.
- Final master composition: 448/448 focused UI tests, 186/186 adapter
tests, 24/24 queue/control tests, and 11/11 packaging tests. Plain UI,
server, shared, and adapter types pass. Token gates and diff checks
pass. Independent server and UI reviews are clear.
- Stop-registration regression: both real-service cases fail against
exact `a95` source and pass with the fix. The full corrected
recovery/control suite passes 265/265. Duplicate-owner and failed-Stop
controls also pass. Plain server types pass. The readiness barrier
prevents provider startup without adding an acknowledgment to an already
terminal run.
- Final qualification strengthens terminal-field equality and repeats
both affected cases successfully on a fresh database. All four actual
local process/ACP browser paths pass again in 1.3 minutes, without skips
or retries. The final screenshot shows Cancelled, a paused subtree,
retained input, and no error toast.
- Two new actual-service regressions fail before the merge fix. They
prove that queued-comment adoption could consume a dedicated chat answer
or add unrelated input to that answer. The fixed four-case cohort
passes, including ordinary upstream continuation and adapter Stop
controls. Full recovery passes 257/257. All four actual local
process/ACP Stop browser flows pass in 1.4 minutes, without skips or
retries, on a fresh database.
- The unchanged runner artifact was qualified with 171/171 transport
tests, 870/870 API-authority tests, conformance 1/1, and replay 11/11.
Six controlled reader tests prove the exit/drain repair. Its local
serial Rust workspace passed 546 top-level cases plus two invoked
helpers; the later passing Linux CI supplies default-concurrency
evidence.
- Prior exact-source full chat integration passes 995/995. Settings
regressions cover concurrent stale pages, 501 destinations, pending
state, rejected updates, and explicit retry. These deterministic tests
do not prove live provider behavior.
- Retained failed attempts and their causes are in the [qualification
log](afe19299d0/doc/plans/chat-adapters/2026-09-08-chat-queue-and-webhook-repair.md).
The first merge adapter run timed out while macOS slept for 290 seconds.
Its unchanged repeat passed with a temporary sleep guard. No assertion,
deadline, or CI gate was weakened.

Review commands include `pnpm --filter @paperclipai/server exec vitest
run src/__tests__/heartbeat-process-recovery.test.ts
src/__tests__/issue-queued-comments-routes.test.ts` and `pnpm exec
playwright test --config tests/e2e/playwright.config.ts
tests/e2e/acp-stop-continuation.spec.ts`. Database suites require fresh
disposable databases. See the [browser
runbook](afe19299d0/doc/plans/chat-adapters/2026-09-04-chat-adapters-browser-e2e-runbook.md)
for provider setup and separate live acceptance steps.

## Risks

- This remains experimental. Deterministic tests and bounded live
evidence do not establish every provider feature, tenant, permission
layout, or media shape. Teams work-tenant qualification is still open.
- Failed and uncertain provider effects remain visible and can require
operator action. A transport receipt does not prove recipient
visibility.
- Native controller and runner artifacts must remain compatible.
Preserve lease ownership, terminal authority, source binding, and
quarantine during future changes.
- Access and audit rows commit together, but activity notifications
remain best-effort. This is not a new durable event outbox.
- The PR operation does not deploy a live server, replace its runner, or
change provider permissions. Remaining live qualification is documented
in the [temporary
handoff](afe19299d0/doc/plans/chat-adapters/2026-09-08-open-qualification-followups.md).

## Model Used

OpenAI Codex assisted with implementation, tool execution, testing, and
review. The work records `gpt-6-astra` assistance. The environment does
not report a context-window size. No private reasoning traces are
included.

## 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-10 10:06:45 -05:00
Devin Foley bce976d60d
feat: bind an agent to a Codex login whose account differs from the company default (#13067)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - The `codex_local` adapter signs agents in to OpenAI, and a company
keeps one default Codex identity in its shared company home
> - A login with a DIFFERENT account than the company default is
deliberately kept out of the shared home — one agent's sign-in must not
switch every unbound agent's credentials — but that left the
cross-account login inert: nothing connected the agent the operator was
configuring to the credential the login stored
> - The stored credential and its company secret already exist; only the
last mile — an agent actually using them — was missing
> - This pull request reports a non-secret binding claim on the
authenticated login and lets the agent page bind that one agent's
`CODEX_HOME` to the account's secret, exactly and only when the
identities differ
> - The benefit is that multi-account Codex becomes one click on the
agent that needs it, with company-wide identity untouched

## Linked Issues or Issue Description

**What happened?**

On an agent's detail page, "Sign in with Codex" using a different OpenAI
account than the company default succeeds but changes nothing for that
agent. The credential lands in the per-identity store and a company
secret names it, but the agent keeps using the company default. The Test
keeps reporting that authentication is needed, and no repeat login
helps.

**Expected behavior**

When the operator deliberately signs an agent's page in with a different
account, that agent starts using that account. Agents that were not part
of the action keep the company default. A same-account login keeps
working through the shared company home with no per-agent pinning.

**Steps to reproduce**

1. Configure a company whose Codex home holds account A.
2. Open a `codex_local` agent's detail page with a sandbox environment
and complete "Sign in with Codex" using account B.
3. Press Test. Before this change the agent still resolves account A and
the authentication-needed check returns.

## What Changed

- `packages/adapters/codex-local` — the prerequisite shield:
`isCodexAuthCachePath` recognizes per-identity credential-store entries,
and `seedManagedCodexHome` refuses to symlink, heal, or
API-key-overwrite an entry's `auth.json`. The seeding pass runs before
every probe and execute; without the shield, an agent bound to an entry
would have its stored login silently swapped for the host credential.
Static shared config files still copy in. Rotation already survives
binding: the sandbox copy-back writes rotated credentials into the
identity-keyed store slot.
- `server` — the promotion records whether the company default home
ended on a different account than the login (any read failure degrades
to `false`, so the client can never be told to bind wrongly). After the
terminal commit, the routes layer remembers a non-secret claim — the
opaque account-home secret id plus that verdict — in a bounded in-memory
map, and merges it into the owner read of an `authenticated`
`codex_local` session. A restart drops the claim; the panel then shows
plain success.
- `packages/shared` — `CodexAccountBindingClaim` on the owner session
response. It carries no account identifier and no credential byte.
- `ui` — the login panel reports the claim upward once. The edit-mode
form binds the agent's `CODEX_HOME` to the secret and saves in one step,
only when `companyIdentityDiffers` is true. Same-account logins bind
nothing on purpose: the company-home refresh already carried them, and
an unbound agent keeps following the company default across rotations.
Create mode is unchanged.

## Verification

- Adapter suite: 381 passed, 1 skipped (includes the new store-entry
shield tests and the path-predicate cases).
- Server suites (8 files): 130 passed, 15 skipped — including two new
route tests that drive a login to `authenticated` and assert the claim
with both identity verdicts.
- UI render suite: 85 passed — including a panel test that the claim is
reported upward exactly once.
- `tsc --noEmit` clean in `packages/shared`, the adapter package, and
`ui`; `server` clean for the touched file.

## Risks

- The bind changes one agent's configuration through the normal
agent-update patch, initiated by the operator's own login on that
agent's page. The failure direction of every fallback is "offer
nothing": a missing claim, a restart, or an unreadable company home all
degrade to no bind.
- The seed shield narrows what the seeding pass may touch; homes outside
the credential store behave exactly as before, covered by the existing
seed tests.
- Builds on the sign-in credential-resolution fix (#13064), now merged;
this branch is rebased onto master and the diff contains only the
binding feature. Supersedes #13066, which GitHub auto-closed when its
stacked base branch was deleted on merge.

## Model Used

Claude (Anthropic) — Claude Fable 5 (`claude-fable-5`), extended
thinking, agentic tool use in Claude Code (terminal).

**Related PRs (searched; no duplicates found):** #12740, #12082, and
#9621 touch adjacent Codex credential sync paths; #8495 is the standing
hardening effort for probe auth seeding.

## 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 (no
standalone docs cover this flow; the behavioral contracts are documented
in-line at each changed site)
- [x] I have considered and documented any risks above
2026-09-10 07:15:01 -07:00
Nicky Leach e25a6b797f
fix(runner): close two timing windows in the capability-live suspend path (#13143)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - The Paperclip Runner manages live agent sessions and their suspend
path.
> - A turn-timeout promise could reject before `reconcileActiveTurn()`
attached its handler.
> - A short provider-drain budget could reject a valid suspend on a
loaded continuous-integration host.
> - This pull request closes both timing windows and adds deterministic
regression tests.
> - The benefit is a fail-closed suspend path that does not report false
failures under load.

## Linked Issues or Issue Description

**What happened?**

Capability-live tests failed under load. A turn-timeout promise could
raise an unhandled rejection during a slow interrupt round trip. An idle
provider drain could also exceed its one-second proof budget during
suspend.

**Expected behavior**

The suspend path must observe turn-timeout rejections and allow enough
time for one provider command round trip. It must still fail closed when
the runner does not prove durable suspension.

**Steps to reproduce**

1. Run the capability-live tests on a loaded four-vCPU
continuous-integration host.
2. Delay a `turn/interrupt` reply beyond the turn timeout.
3. Close a live session and observe the suspend barrier.

**Paperclip version or commit**

`01b442b2926ac2010a2fcfbda6592802472ef07f`

**Deployment mode**

Built from source with the Paperclip Runner test suite.

## What Changed

- Attach the turn-timeout rejection handler inside `armTurnWaiter()` at
promise creation.
- Remove the redundant per-call-site guard in `sendMessage()`.
- Use a uniform five-second provider-drain proof budget, capped by the
outer preparation deadline.
- Remove the unused boolean return from the provider-turn-stop helper.
- Add deterministic tests for the delayed interrupt and the short close
grace period.

## Verification

- `npx vitest run
packages/paperclip-runner/src/live/live-session.test.ts` passed locally
with zero skipped tests.
- `npx vitest run
packages/paperclip-runner/src/live/runnerd-codex-transport.test.ts`
passed locally with zero skipped tests.
- The two new tests appeared in the local run output and were not
skipped.
- The package type-check passed locally.
- GitHub Actions must confirm the full continuous-integration suite,
including `Verify Paperclip Runner`.

## Risks

- The provider-drain wait now allows up to five seconds before the outer
deadline caps it.
- The fail-closed suspend barrier remains unchanged.
- The test suite still depends on the Rust runner binary for
capability-live tests.

## Model Used

OpenAI Codex, GPT-5. The runtime provided tool use and code execution.
The runtime did not provide a context-window value.

## 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-10 07:04:55 -07:00
Dotta 018ca5daaf
fix: verify ACP Stop and preserve safe continuation (#13119)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Task controls coordinate provider execution and queued user
messages.
> - Stop could finish before an embedded ACP provider stopped its tools.
> - A later request could be held for reconciliation without a clear
task response.
> - A restored provider could also retain the stopped run's API
credential.
> - This pull request verifies provider termination and preserves safe
session continuation.
> - Operators can continue known-safe work and see why uncertain work
cannot start.

## Linked Issues or Issue Description

**What happened?**

Stop could leave an embedded ACP provider running. A queued follow-up
followed by “go” could fail before it reached the provider. Task chat
could show a generic missing-response message. Even a restored session
could use the previous run's credential and fail its task update.

**Expected behavior**

Stop waits for confirmed provider termination. A later explicit wake
continues the same compatible session only when recorded actions have
known outcomes. It carries pending comments and the current run's
environment. Uncertain actions retain a visible reconciliation hold.
Composer Stop preserves the existing pause rule: conversation can
continue while paused, but task work requires Resume.

**Steps to reproduce**

1. Start an embedded ACP task.
2. Send a second request while the provider is running.
3. Interrupt the run, then send “go”. Also test composer Stop followed
by Resume work.
4. Check that the request is delivered once and that the provider can
complete the task through the current run's API credential.
5. Repeat with an unfinished write. Confirm that the write stops and
that further execution stays blocked with a visible reason.

**Paperclip version or commit**

Built from source on master at `3bc60dd8b` plus this branch.

**Deployment mode**

Local source build with an isolated embedded PostgreSQL instance.

Refs #11183. Refs #12552. Those changes address recovery after operator
cancellation. This change also covers embedded ACP termination, session
proof, pending-comment delivery, and task feedback.

## What Changed

- Propagate Stop into embedded ACP and wait for bounded adapter cleanup
and provider exit. Retain the actual ChildProcess object for forced
termination on all platforms; never signal a recycled numeric PID.
- Preserve interrupted checkpoints only for acknowledged, local,
persistent sessions with settled reads or no tools. Keep writes,
incomplete actions, and forced termination blocked.
- Restore the same compatible provider session with the current run's
environment. Reject fresh-session fallback for an interrupted
checkpoint.
- Adopt pending comments on the next explicit wake. Stop alone does not
dispatch them.
- Share the execution-blocker rule across dispatch, Resume, and task
detail. Show Stopped or Couldn't start with the recorded reason. Resolve
the stopped agent for the run link, including reviewer runs.
- Keep execution reconciliation holds intact when generic recovery sees
queued comments or healthy child tasks.
- Add process, service, component, and browser regression coverage. Fix
disposable database cleanup and React test settling exposed by the full
suite.

## Verification

- Passed `pnpm -r typecheck`, `pnpm build`, and `pnpm
check:token-gates`.
- Passed all three `acp-stop-continuation.spec.ts` browser journeys.
They use an actual ACP child process and require task completion through
the agent API.
- Passed 165 adapter execution, operator-stop, and child-process control
tests, 17 queued-comment route tests, and 65 tests in the two adjusted
UI suites. Earlier focused recovery, heartbeat, and task-control tests
also passed.
- Manually used the browser to queue a request, Stop, send “go” while
paused, and Resume. The same session answered once and moved the task to
Done with the current run's credential.
- Manually interrupted an unfinished write. Its file size stayed fixed
for five seconds. “Go” showed the reconciliation reason and did not
start another provider prompt.
- Separate live Claude ACP smoke checks confirmed that Stop ended a
disposable local write and that a no-tool interruption could resume the
exact provider session. The browser fixture does not call Drive or
another external app.
- Passed all 5,615 UI tests and 3,090 other workspace tests. The CLI and
general server groups pass with targeted retries: two transient server
failures passed together on retry, and two embedded-database startup
failures passed after removing abandoned shared-memory segments from
this task's completed browser fixtures. All 144 serialized server suites
completed, with 2,189 tests passing after two transient HTTP socket
failures passed on retry.
- Passed all 135 heartbeat process/recovery tests, including a
deterministic regression that failed before the recovery-sweep fix.
- Passed 18 dispatch integration tests, including stopped-reviewer
links, company boundaries, and malformed run IDs.
- Greptile is 5/5 on `7dd170d83`, with zero unresolved review threads.
The security scan and all required CI gates pass for the same commit.

## Risks

- Safe continuation depends on complete tool reporting and a restorable
local provider session. Unknown outcomes remain blocked and require
reconciliation.
- Provider cleanup can take time. A timeout does not grant replay
permission.
- The change adds optional adapter context fields and an optional issue
projection. It does not change the database schema or require a
migration.
- Test cleanup truncates company data only in a disposable test
database.

## Model Used

OpenAI GPT-6, running as Codex with repository tools, code execution,
and browser interaction. The runtime does not expose a more specific
model deployment 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-09-09 22:06:06 -05:00
Dotta 3bc60dd8bf
fix(adapters): probe Git context in the remote workspace (#13116)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Remote environments realize the workspace at a provider-owned path.
> - Run startup probes Git and network context before it starts the
agent.
> - The probe used the controller path inside the remote environment.
> - A missing directory stopped the run before any provider work began.
> - This pull request uses the remote execution target's working
directory.

## Linked Issues or Issue Description

Refs #13094, which introduced this probe. Related: #8997 and #10419
address other workspace-directory handoffs; this patch fixes the newer
Git-context probe.

**What happened?**

Remote runs failed with `setup_failed: Could not read execution-target
Git context`, including tasks that did not use Git. The provider shell
could not enter the controller's workspace directory.

**Expected behavior**

Startup must inspect Git and network context in the realized remote
workspace.

**Steps to reproduce**

1. Select a remote sandbox whose workspace is
`/home/daytona/paperclip-workspace`.
2. Start a task whose controller workspace is under
`/paperclip/instances/default/workspaces/`.
3. The startup probe exits when the controller directory does not exist
in the sandbox.

**Paperclip version or commit**

Reproduced on `622376e99` and in the regression test before this patch.

**Deployment mode**

Docker controller with a remote Daytona sandbox. The same helper also
serves SSH targets.

## What Changed

- Use `remote.remoteCwd` for the remote Git-context probe.
- Cover a missing controller directory in both credential modes.
- Verify that SSH reads Git metadata from the remote workspace even when
the caller directory exists.

## Verification

- Before the fix, both new missing-directory tests failed with the
reported error.
- The launcher environment suite passes: 18 tests.
- The adapter-utils suite passes: 1,085 passed, 11 skipped.
- Adapter-utils typecheck passes.
- A disposable sandbox with the affected deployment's image reproduced
the old `cd` failure and passed with the corrected helper. The sandbox
was deleted afterward.
- Full repository typecheck and build pass locally. All CI gates pass at
`61b522c`: regular test shards, serialized server suites, browser
shards, Runner verification, build, policy, and security checks.
- The first CI Build attempt hit a Runner suspension-acknowledgment
timeout outside the changed code. The affected 13-case recovery group
passes locally with its Rust fixtures built, and the unchanged CI job
passed on its single retry.
- The full serial local test run was stopped in favor of the complete CI
matrix; it is not claimed as a local pass.

## Risks

The probe now uses the provider-resolved target directory for sandbox
and SSH execution. Local execution keeps its existing directory. There
are no schema or API changes. Existing local credential and Git metadata
tests pass.

## Model Used

OpenAI GPT-6 in Codex, with tool-assisted code analysis, implementation,
and live and automated testing. The exact model identifier 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-09 16:52:11 -05:00
Dotta 3b550c80fa
fix(codex): correct startup trust, history reads, and resume usage (#13110)
## Thinking Path

> - Paperclip runs Codex locally and in remote sandboxes.
> - The runner must preserve startup configuration and session identity.
> - Missing project trust can disable repository configuration.
> - Full-history requests use deprecated provider fields.
> - Resume usage describes old work and must not become new run usage.
> - This change corrects startup trust, state reads, and usage
classification.

## Linked Issues or Issue Description

**What happened?**

Normal Codex runs could show repository-trust and history-deprecation
warnings.
Resume could report the preceding turn's token snapshot as a late-turn
warning.
The historical last-usage value could also be attributed to the new run.

**Expected behavior**

Trust the server-selected startup root in isolated configuration. Read
lightweight
provider state and paginated evidence. Use historical cumulative usage
as a
baseline without a new charge or user-facing warning.

**Steps to reproduce**

1. Start a native Codex task in a selected repository.
2. Finish the turn and resume the provider thread.
3. Inspect provider notices, history requests, and per-run usage.
4. Repeat startup and cold resume inside a Daytona sandbox.

**Paperclip version or commit**

Codex CLI 0.153.4 is the pinned runtime and reproduced baseline.
Replayed onto master at 6abeb6733. Related authority work: Refs #13092.
This PR retains its startup cleanup and protocol-integrity checks.

**Deployment mode**

Local source checkout and disposable Daytona sandbox.

## What Changed

- Classify the exact historical resume usage event before the generic
stale-turn warning.
- Persist cumulative usage baselines across recovery of the same run.
- Use excludeTurns on resume and lightweight thread reads.
- Page turn metadata and selected turn items with cursor and identity
validation.
- Reject unsupported or incomplete history instead of guessing that
execution is idle.
- Trust the startup execution root on its host, including Git worktree
trust keys.
- Start Codex in that root and retain the selected sandbox profile on
later turns.
- Keep unrelated isolated configuration and Codex's separate hook trust
policy.
- Add Rust, TypeScript, accounting, native integration, and local
run-log documentation.

## Verification

- Codex and native-transport TypeScript: 333 passed before PR replay.
- Adjacent OpenCode/ACPX driver and accounting tests: 49 passed.
- Rust library, serialized: 226 passed. Native Codex integration: 72
passed, 1 ignored, plus two pagination regressions.
- Repository typecheck and build passed. All repository test groups have
passing coverage after fixture and resource retests; the initial
monolithic command was not clean.
- Fresh real Codex native browser tasks returned correct answers without
the three targeted notices. Answers persisted after refresh and restart.
- Real same-thread TypeScript driver tests passed locally and in
Daytona, including cold resume, configuration, skills, and an approved
harmless hook.
- Local usage summed to 64,607 tokens. Daytona usage summed to 42,737
tokens. Each sum matched its final session total exactly.
- See doc/plans/2026-09-09-codex-integration-acceptance.md for the scope
and limits of the live tests.
- After replay onto current master and review fixes: 334 Codex, backend,
and live-session tests passed, including checkpoint serialization and
real-runner process restart. TypeScript checks passed.
- The native Codex integration run passed 83 tests; the large lineage
test passed separately with the release runner (its debug build exceeded
the test deadline).
- All GitHub checks passed on the final PR head. Greptile is 5/5 with no
unresolved review threads. CI regenerates the lockfile for the added
TOML dependency, per repository policy.
- The first server shard hit a timing-dependent duplicate-key failure in
the unchanged artifact-document concurrency test. Its focused 11-test
suite passed locally. One CI retry on the same head passed all 103 files
and 1,405 tests (2 skipped): [retry
result](https://github.com/paperclipai/paperclip/actions/runs/34398832930/job/102631274667).

## Risks

- Trust applies only to the server-selected startup root and isolated
configuration. Sandbox and tool permissions remain authoritative.
- Codex still requires approval of individual hook hashes. This change
does not bypass that policy.
- Providers without the required history APIs fail explicitly.
- Daytona acceptance used the production TypeScript driver. Remote
Paperclip UI and remote Rust execution were not tested.
- No new public API, database state, recovery policy, or UI control is
included.

## Model Used

OpenAI Codex, GPT-6 (`gpt-6-astra`). Used for reasoning, code edits,
tool use,
and test execution. The exact context-window limit is not exposed in
this
session. Real-provider acceptance used Codex CLI 0.153.4 with
`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
#` 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-09 15:35:18 -05:00
Dotta ca96e1eb0a
fix(runner): keep streaming after task completion tools (#13108)
Keep receiving provider events after paperclip_finish, drain pending event persistence, and select the final assistant answer after the provider turn ends. Preserve cancellation, failure, and governed-wait behavior.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-09-09 15:22:00 -05:00
Dotta 5cb4f061dd
fix(ui): simplify provider notices and hide completion calls (#13109)
## Thinking Path

> - Paperclip shows agent work in task feeds.
> - Native tools and provider notices appear in that feed.
> - A routine completion call adds no useful action for the user.
> - A provider notice needs readable text to explain its warning.
> - This change hides the completion call and displays the notice
summary.
> - Saved run events remain available for inspection.

## Linked Issues or Issue Description

**What happened?**

The feed showed paperclip_finish as a normal tool call. Provider notices
showed
a generic name or a large key-value table instead of a clear warning
message.

**Expected behavior**

Hide the routine completion call from the task feed. Show a warning
icon,
a short severity heading, and the full notice summary across the row.

**Steps to reproduce**

1. Open a native Codex task that calls paperclip_finish.
2. Inspect its tool activity in the task feed.
3. Inspect a run with a repository-trust provider notice.

**Paperclip version or commit**

Reproduced on the implementation checkout. Replayed onto master at
6abeb6733.
The search found no duplicate PR for this display change.

**Deployment mode**

Local source checkout with native task feeds.

## What Changed

- Hide paperclip_finish calls and results in task-feed adapters.
- Preserve the raw events for run-log inspection.
- Carry provider-notice text into the transcript.
- Render notices with an icon, severity heading, and full-width summary.
- Cover the display and transcript mapping with regression tests.

## Verification

- The affected UI tests and the token gates passed on the implementation
checkout.
- Browser inspection confirmed the warning text is readable and
completion calls are hidden.
- Repository typecheck and build passed. Repository test groups passed
after resource retests.
- On this PR branch, 123 focused UI tests and the token gates passed.
All GitHub checks passed; Greptile is 5/5 with no unresolved threads.

## Risks

- The task feed hides one known internal tool. Raw run events remain
unchanged.
- Long warning text must wrap within the available width.
- No provider warning classification, accounting, or recovery behavior
changes here.

## Model Used

OpenAI Codex, GPT-6 (`gpt-6-astra`). Used for reasoning, code edits,
tool use,
and test execution. The exact context-window limit is not exposed in
this
session. Real-provider acceptance used Codex CLI 0.153.4 with
`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
#` 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-09 15:06:20 -05:00
Dotta 6abeb67334
feat: add opt-in chat provider and data foundation (#13100)
Add dormant provider contracts, qualified patched adapters, tenant-scoped persistence and lifecycle ownership without activating chat routes. Preserve the experimental integration as dependent PR #13038.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-09-09 13:49:12 -05:00
Dotta 2991a59b17
fix(adapters): prevent engine fallback and preserve usable runtime defaults (#13105)
## Thinking Path

> - Paperclip manages agents that must write work and report task
outcomes through its API.
> - Local adapters select an execution engine and its permission
settings.
> - A higher ACP Node requirement can make an unchanged installation
lose access to its default engine.
> - The adapter then silently selects CLI, which can change permissions
and block API access.
> - This pull request keeps the engine choice fixed and reports missing
prerequisites before work starts.
> - It also gives explicit Codex CLI runs usable defaults and keeps
managed services on a supported Node runtime.

## Linked Issues or Issue Description

Refs #12215. Related changes: #11792 raised the Node requirement; #13094
addressed separate runner networking behavior. This change fixes the
engine-selection and managed-launcher paths.

**What happened?**

An unchanged agent could switch from ACP to CLI after an upgrade. Codex
CLI then used read-only permissions with networking disabled. The run
could finish without updating its task. Repeated recovery attempts used
the same unavailable setup. Managed updates also skipped the Node check
and did not refresh old launchers.

**Expected behavior**

An unavailable engine must fail with a clear setup error. It must not
silently select another engine. Explicit CLI runs must be able to write
workspace files and call the API unless the operator configures stricter
settings. Managed updates must validate Node and keep child tools on
that runtime.

**Steps to reproduce**

1. Run an ACP-default agent under Node 22 after the ACP minimum rises to
24.11.
2. Leave the engine unset and disable the approval/sandbox bypass.
3. Observe the old adapter select CLI and fail to write task disposition
through the API.
4. Start a managed service with an old launcher and a supervisor PATH
that selects a different Node for child tools.

## What Changed

- Remove automatic engine fallback for Codex, Claude, Gemini, and Kimi.
Check prerequisites for default and explicit ACP selections.
- Return a configuration error with proof that provider work did not
start. Stop automatic continuation retries for this error.
- Enable Codex ACP workspace networking at the actual turn boundary.
Upstream mode presets otherwise force it off even when config.toml
enables it. Preserve explicit network denial and read-only mode.
- Set workspace-write and network access defaults for explicit Codex CLI
runs. Preserve explicit sandbox modes, profiles, and network
restrictions.
- Pin the validated Node directory in managed launcher PATH. Refresh
legacy launchers during installs and npm/Git updates.
- Reject updates on unsupported Node. Keep update checks, dry runs, and
rollback available.
- Synchronize the qualified Codex ACP executable identity across server,
TypeScript runner, Rust runner, and provider-pack launch paths.
- Add regression tests and update engine and installation documentation.

## Verification

- [Full CI passed on the final
head](https://github.com/paperclipai/paperclip/actions/runs/34387099695):
typecheck, build/native runner verification, all general and serialized
test shards, all browser shards, release registry, canary dry run, and
policy checks.
- Greptile: 5/5 on `2c1d6e2815830a5cd39e36c8a082cc0c4441b6c0`, with no
unresolved review findings. Security gates are green.
- Full workspace typecheck and build also passed locally. The final
deployed Linux build passed.
- Full Codex, Claude, Gemini, and Kimi source test suites: 804 passed, 2
skipped. Installer, updater, and launcher tests: 47 passed. Installed
ACP turn-boundary tests: 3 passed. ACP packaging tests: 14 passed.
Focused recovery classification tests also passed.
- Real Linux Codex CLI runs, both fresh and resumed, wrote a workspace
file and reached the control-plane health API with the new defaults.
- Explicit read-only and network-disabled control probes retained those
restrictions.
- A real ACP run on the final deployed Linux build wrote a file and
reached the control-plane API with HTTP 200, without engine fallback.
The same probe failed DNS before the turn-policy patch.
- Executable-identity and installed-policy contracts: 12 passed.
Affected native server tests: 197 passed. Runner factory tests: 21
passed. Rust qualification and native provider integration tests: 11
passed.
- Deployed the production changes to a Linux service on Node 24.20 after
a verified database backup. Health, bootstrap readiness, static UI,
executable/cwd identity, and guarded restart checks passed. The restart
lost no runs.
- Corrected stale Kimi skill-default and Gemini remote-archive fixtures;
both suites pass.

## Risks

- Default or legacy auto engine settings now fail when ACP is
unavailable. Operators who intend to use CLI must select it explicitly.
- Codex CLI now permits workspace writes and networking by default, and
ACP workspace-write turns permit networking by default. Explicit
operator sandbox settings remain authoritative.
- Old managed launchers keep their pinned Node until they are
reinstalled under a supported runtime. An old updater cannot repair
itself; the documentation gives the current installer command.
- Custom service wrappers and global/source installations must configure
their runtime PATH. No database migration is required.

## Model Used

OpenAI Codex, based on GPT-6, with reasoning, repository inspection,
shell execution, and test tools. 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-09 13:27:24 -05:00
Dotta 8cfd30fb07
feat(ui): add composer Stop and simplify task controls (#13104)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - The task composer is where operators direct running agents.
> - Operators need to stop work without leaving the conversation.
> - Existing pause controls already hold task trees and interrupt both
runner types.
> - This pull request connects the composer to those controls and
removes repeated feedback.
> - Operators can pause work quickly and still queue messages while
agents run.

## Linked Issues or Issue Description

**What existing behavior does this improve?**

Task pause, resume, and cancellation in the task page and composer.

**Current behavior**

The empty composer cannot stop a running task. Task controls require
extra confirmation and reason text. Pause can show several notifications
for the task already on screen.

**Proposed behavior**

Show Stop while this task runs and the composer is empty. Text or
attachments switch it to Send. Stop and the menu use the same manual
pause hold. Parent pauses include descendants. Keep task cancellation in
the menu with a compact confirmation. Show one quiet pause row and gray
cancelled-run details.

**Reason and benefit**

Operators can interrupt execution with one click. Drafts and queued
messages keep their existing behavior. The UI waits for actual
termination, including native cancellation acknowledgment.

**Breaking changes**

No endpoint, schema, or task-status change. Pause no longer asks for
confirmation or a reason. Resume now honors the existing wake-agents
option. Task notifications are suppressed for the task and subtree
currently in view.

Related UI work: #8228 changes navigation and composer shortcuts. This
PR covers execution controls. No duplicate Stop-button PR was found. The
change improves existing controls and does not duplicate a roadmap
milestone.

## What Changed

- Add Stop, pending feedback, duplicate-click protection, and inline
errors to the composer.
- Share the pause mutation across the composer, active-run controls, and
menu.
- Poll affected runs after a pause request. Require native cancellation
acknowledgment.
- Remove pause confirmation and shared reason fields. Reduce cancel
confirmation to its task count and actions.
- Honor wake-agents for executable tasks only. Preserve the pause when
recovery review is needed; show partial wake failures inline.
- Preserve explicit legacy reconciliation decisions while their
continuation waits for dispatch.
- Suppress notifications for visible task trees. Use quiet pause and
cancellation feedback.
- Add interactive stories using production controls and native/legacy
end-to-end tests.

## Verification

- User reviewed the running feature and revised Storybooks in the
browser.
- Rebased focused checks passed: 295 original targeted tests, 161
updated route/page/notification/status tests, and 26 recovery
integration tests.
- Both isolated runner journeys pass on the final revision (1.7
minutes). Coverage includes queueing, parent and child interruption,
persisted holds, no automatic continuation, reconciled resume,
cancellation, terminal exclusions, and no Stop toast.
- Native coverage uses real runnerd with a deterministic provider
fixture. Legacy coverage checks actual process termination. Live
hosted-provider execution was not tested.
- Repository typecheck and build, Storybook build, and token gates
passed after rebase. The final server typecheck/build also passed.
- The broad local run completed its general-server stage with 7,219
passing tests, 48 skipped, and two failures from cached pre-fix source
and a stale native provider fixture. Both failed tests pass in fresh
final-head reruns after rebuilding the fixture; the script did not
continue to its later local stages. CI runs all test groups on the final
revision.
- Final revision: all 31 applicable CI checks passed; Storybook visual
regression was skipped by its workflow conditions. Greptile: 5/5, zero
unresolved comments.
- Review `Tasks / Execution Controls` in Storybook. Type and clear a
draft, stop a run, expand cancellation details, and test the menu on
desktop and mobile.

## Risks

- Stop pauses descendants for a parent task. This is the existing pause
contract.
- A held task can remain active if interruption fails. The UI shows an
error instead of claiming termination.
- Resume can start multiple assignees when wake-agents is selected.
Backlog, blocked, and terminal tasks stay excluded. Existing execution
reconciliation remains mandatory where required; Resume never invents
action-outcome evidence.
- Notification suppression uses the visible task and cached subtree.
Notifications for unrelated work remain enabled.

## Model Used

OpenAI GPT-6 through Codex. The exact runtime snapshot and
context-window limit are not exposed in this session. Used reasoning,
tool calls, code execution, and browser inspection.

## 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-09 12:18:56 -05:00
Dotta fac07b42ad
fix(runner): preserve durable native session authority across recovery (#13092)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - The native runner carries tool results and task output to the
control plane.
> - A lost connection must not change which run owns a result.
> - A session must not become reusable while provider output is still
pending.
> - This pull request adds strict recovery evidence and bounded drain
barriers.
> - It preserves current PRP version negotiation and session-goal
support.
> - The benefit is safer reuse of native sessions after a transport
failure.

## Linked Issues or Issue Description

Refs #13038. This is the first of two stacked pull requests. It contains
the native runtime prerequisites. The second pull request contains the
experimental chat-channel integration. It preserves the provider
identity and typed terminal-failure contracts in #13074 and the durable
recovery work in #13075.

**What happened?**

Native session failures could leave retained provider events, incomplete
tool results, or warm handoff state that was not safe to reuse. A later
run could observe output from an earlier authority.

**Expected behavior**

Recovery must preserve exact run, tool, process, artifact, and lease
evidence. Uncertain or corrupt state must fail closed. A successful
close must prove that retained provider output is settled.

**Steps to reproduce**

Run the transport and control-plane regressions. They hold and drop
authenticated frames, fail durable writes, and restart fresh controllers
and runner processes with retained state. Provider executables are local
test fixtures.

## What Changed

- Preserve pending provider cleanup and semantic-result evidence across
session close and restart.
- Add an authenticated warm handoff with exact old and new identities,
durable receipts, and completion acknowledgement.
- Drain retained provider events under the cumulative acknowledgement
fence.
- Reject corrupt tool-result contracts without unsafe provider replay or
reusable checkpoints.
- Keep ordinary PRP v1 sessions and current session-goal behavior.
Require negotiated PRP v2 and acknowledged native session evidence
before warm authority rotation.
- Preserve late semantic inputs and exact durable result receipts until
close can prove settlement.
- Add transport, crash-window, artifact, checkpoint, and final-output
regressions.
- Deduplicate resolved execution delivery under the current issue lock.
Reuse the exact existing successor after concurrent scans or a lost
acknowledgement. Preserve newer operator evidence.
- Persist idle provider integrity/capacity failures before process
retirement, retain permanent model-rejection classification, and keep
external question identifiers out of task instructions.
- Expose only the context source on native status events. Keep thin
dispatch projections compatible without exposing the complete context.

## Verification

- Review-fix revision: 128 runtime-context/native-session tests, five
idle-failure/adjacent Rust cases, 24 warm crash-window cases, three
startup-notification/close cases, and five attach/backlog cases passed.
The security and idle-failure cases were first reproduced failing.
- Prior merged revision: runner production build, TypeScript typecheck,
complete Rust workspace tests and formatting passed; 272 focused runner
tests and two real PostgreSQL regressions passed.
- Earlier full runner runs and CI Build failed on missing
semantic-result fixture receipts, stale local provider fixture bytes,
startup-notification ordering, and a confirmation-loss fixture that
could accidentally send its final ACK. Each cause was reproduced and
corrected without relaxing production authority or close assertions.
These earlier runs are retained as failures, not represented as passing
verification.
- The first local repository-wide run failed before later phases because
the isolated install omitted PostgreSQL's native-library aliases; it
also encountered an unrelated occupied-port fixture. Those results are
retained, not represented as a passing run.
- Exact `335b2ee52709afb3885d4d6ebb2a3ece4b5864d6`: the complete runner
suite passed 1,888 tests, with 10 existing skips. The full Rust release
workspace passed with serial test scheduling. The unchanged parallel
Rust run hit the five-second 300-descendant fixture deadline; that
failure is retained. No deadline or assertion was relaxed.
- The resolved-execution regression suite passed 57 tests, including
concurrent delivery, lost acknowledgement, superseded authority, and
newer operator evidence. Plain server typecheck passed. The
duplicate-delivery cases were first reproduced failing.
- Prior exact `335b2ee52709afb3885d4d6ebb2a3ece4b5864d6` CI passed all
required jobs and Greptile reported 5/5. Its local general-server run
passed 7,208 tests but failed one responsibility fixture; later phases
did not run. The fixture started the next wake while its bounded handoff
was active. It also used nonexistent comment IDs, which hid the current
stored-message-author identity rule. The updated tests use real message
authors, preserve task ownership, and await exact automatic handoffs. No
production identity policy changed.
- Current head `aa39275a1f300f7d1a0b16cd0885eea567cff6b0` includes
current master and the native context-source projection. The focused
identity/status cohort passed 27 tests and plain server typecheck
passed. Fresh full repository tests, types, build, required CI, and
Greptile review are pending. Final results will be updated before merge.
- This is deterministic local-provider evidence. It is not a claim of
complete live-provider qualification.

## Risks

- This changes authenticated recovery and close ordering. The TypeScript
transport and runner binary must be built from the same revision.
- Failed or incomplete evidence intentionally prevents reuse and can
require a fresh run.
- PRP v1 ordinary/cold sessions remain supported. A v1 connection lease
cannot upgrade in place. A current v2-capable runner held on a v1 lease
was qualified through owned-process retirement/join, fresh bootstrap on
the same old authority, v2 observation/ACK, then warm rotation. Legacy
binary replacement and adopted-owner migration are not qualified by that
test; rollout must not present them as automatic same-lease upgrades.
- This pull request has no database migration or chat-channel
activation. The second pull request keeps the channel feature
experimental.

## Model Used

OpenAI Codex assisted with implementation, tool execution, tests, and
reconciliation. The existing implementation records OpenAI `gpt-6-astra`
assistance. The current environment does not report a context-window
size. No private reasoning traces are included.

## 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-09 11:02:59 -05:00
Dotta 82f662656a
fix(runner): restore legacy Git access and independent networking (#13094)
## Thinking Path

> - Paperclip runs agents for people with different GitHub accounts.
> - Managed operations must use the intended person's eligible
connection.
> - A failed duplicate connection must not hide a healthy grant for the
same account.
> - Legacy hosts also need their existing Git configuration when managed
access is not configured.
> - Runner networking and local Git operations must not depend on GitHub
broker availability.
> - This pull request separates those policies and improves failure
diagnostics.

## Linked Issues or Issue Description

**What happened?** New runs always cleared host Git credentials and
installed managed launchers. Network permission depended on GitHub
environment variables. A launcher failure could stop even local `git
status`. A newer unhealthy duplicate could take precedence over a
healthy connection, and generic health errors were shown as reconnect
requirements.

**Expected behavior:** Use a healthy eligible managed connection for the
intended account. Preserve host authentication only for unconfigured
standard-trust local or SSH execution. Permit local Git during broker
failures and keep network permission independent of GitHub credentials.

**Steps to reproduce:** Configure healthy and unhealthy grants for one
GitHub account, dispatch an agent, and execute Git commands. Separately
run an unconfigured legacy host with existing GitHub CLI authentication.
Stop the broker and run local `git status`.

**Paperclip version or commit:** Master at 668110469. **Deployment
mode:** Self-hosted. **Installation method:** Git checkout. **Agent
adapters involved:** Native Codex runner and shared adapter execution
setup. **Database mode:** Existing instance database; no migration.
**Access context:** Responsible person's managed grant, or explicitly
unconfigured legacy host. **Node.js version:** 26.4.0 locally.
**Operating system:** macOS development and Linux execution hosts.

**Relevant logs or output:** Previously `GitHub credential context
unavailable` hid configuration, transport, and capability errors. New
diagnostics identify these categories without credential values.

**Additional context:** Refs #13005 and #13022. Dependency provisioning
is addressed separately in #13093.

## What Changed

- Prefer healthy eligible grants and retry credential acquisition once
for the same principal and account before starting an operation.
- Preserve host Git configuration only when managed access is
unconfigured on a standard-trust local or SSH target.
- Project authentication mode and validated Git metadata into native
runner boundaries; refresh resumed provider settings when modes change.
- Enable network access through an explicit standard-trust controller
decision, independently of GitHub. Omitted or restricted decisions stay
disabled; replace warm providers when that decision changes.
- Run local Git with cleared credentials when the managed broker fails,
with specific redacted diagnostics.
- Retry access-refresh conflicts once without treating concurrency as
expired authorization.
- Show retry instead of reconnect for transient GitHub health failures.
Add optional authorization and run-diagnostic fields without a database
migration.

## Verification

- All latest-head CI gates are green, including typecheck, general and
serialized suites, browser tests, canary, native runner verification,
and build. Greptile is 5/5 with no remaining findings; the security scan
passed.
- Full recursive typecheck and build passed. UI token gates passed.
- Full general server run: 7,110 passed, one transient socket hangup;
that file passed on retry. All remaining workspace groups passed,
including 5,552 UI and 478 CLI tests. The complete serialized rerun
passed all 144 suites / 2,179 tests after the initial isolated timeout
passed on retry.
- 195 final launcher and native session tests passed, including
host/managed transitions, local/remote warm network-policy changes,
broker rotation, and attempts to override validated controller
filesystem roots.
- GitHub gateway fallback, duplicate connection selection, refresh
conflicts, per-user reauthorization, and native transport/security
suites passed.
- Additional live native fixtures passed SSH public-key authentication
and a Git credential helper in fresh and resumed host-mode sessions. An
unwritable managed configuration directory preserved local Git (exit 0)
while GitHub CLI failed with `configuration_directory_unavailable` (exit
4). The temporary SSH listener and keys were removed.
- Applicable Rust suites passed except two timing failures under load;
each failed case passed in isolation. The final environment contract
test passed.
- Linux native runner acceptance passed in both managed and legacy host
modes: DNS, HTTPS, npm package download, fresh-worktree Git status,
authenticated GitHub user lookup, repository read, and a new run
continuing the same provider conversation. Managed broker outage
preserved local Git and rejected authenticated access without host
fallback.
- Matching Linux server/runner artifacts and the separate provisioning
repair are deployed to the development instance. A fresh UI-dispatched
task and a new run after a server restart both passed all six shell
checks through the live controller and credential broker. Both runs
selected the expected healthy connection/grant and retained the same
provider conversation. Neither connection was repaired or reconnected.

The sandbox roots are assigned from the validated execution-target probe
**after** ordinary bindings are merged. Regression coverage supplies
forged roots and verifies they cannot override the controller paths.
Networking is enabled only for an explicit
`PAPERCLIP_RUNNER_NETWORK_ACCESS=enabled` controller decision; omitted
values remain disabled.

## Risks

Unconfigured standard-trust local and SSH runs regain access to host Git
authentication resources. Managed, sandbox, plugin, and low-trust runs
do not gain this fallback. Revoked managed access never falls back to
another account. Deploy server and runner artifacts together;
already-started operations retain their captured identity. An
unauthenticated command can still fail when it requires GitHub access.

## Model Used

OpenAI GPT-6 through Codex, with code editing, shell execution, tests,
and browser inspection. The exact model 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-09 10:15:10 -05:00
Dotta 35fdc0c66b
fix: make task recovery durable and preserve current requests (#13075)
Make task recovery durable and preserve the latest user request across native and legacy continuations. Keep routine recovery quiet and prevent replay when action outcomes are uncertain.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-09-09 09:14:25 -05:00
Dotta 6681104692
fix(runner): preserve provider identity and terminal failures (#13074)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - The runner translates provider events into durable task execution.
> - Provider notifications can refer to another thread or a descendant.
> - Root validation treated these notifications as fatal, and later
layers could lose the original failure.
> - This pull request classifies event identity and preserves structured
terminal failures.
> - The server can then choose safe recovery without weakening tool
authority.

## Linked Issues or Issue Description

Refs #13038. This change incorporates the shared protocol-integrity and
bounded-cleanup prerequisites from that PR. It does not include the chat
feature. Related failure classification work: #13028.

**What happened?**
An informational provider notification for another thread could
terminate the root session. A failed stream could then become a
missing-result error and lose its cause.

**Expected behavior**
Ignore unrelated informational notices with bounded diagnostics. Reject
invalid authoritative events. Preserve the original failure code and
recovery meaning through cleanup.

**Steps to reproduce**
Run a native Codex task. Deliver a notification for an unrelated thread,
or close the stream after a structured failure. Inspect the root outcome
and recorded failure.

**Paperclip version or commit**
Reproduced before e20010472. This branch includes the current
session-goal contract from that commit.

**Deployment mode**
Built from source. Native runner with Codex.

## What Changed

- Classify root, provider-confirmed descendant, stale, unrelated, and
invalid provider events.
- Keep tool requests bound to their original execution authority.
- Preserve typed failures through transport, session, and durable
control-plane cleanup.
- Keep bounded cleanup failures separate from the primary execution
failure.
- Add compatible shared contracts for continuation context, execution
status, and explicit reconciliation. The dependent PR adds their server
and UI consumers.

## Verification

- Runner TypeScript and ACPX suites: 1,733 passed, 7 skipped. Node
contracts: 38 passed.
- Real provider-process fixtures cover 300 descendant identities across
restart, the 4,096-identity capacity boundary, and rejection of
continuation after terminal acknowledgement and restart.
- Repository build, typecheck, and full `pnpm test:run` passed on the
rebased stack (18,448 tests passed, 49 skipped). The full Rust workspace
passed with `--test-threads=1`; parallel execution exposed an existing
fixture port-reservation race. All latest-head CI checks passed. One
unchanged artifact-document concurrency test failed on the first CI run
and passed on its single rerun.
- Added notification, streaming failure, protocol integrity, cleanup
quarantine, and durable failure tests.

## Risks

Provider event classification must retain the new session-goal behavior
on master. Descendant notifications must never gain root tool authority.
Shared contract fields are additive. This PR does not migrate data or
start replacement provider work.

## Model Used

OpenAI GPT-6 through Codex. The exact deployment ID and context window
were not exposed. Used reasoning, tool use, code execution, and browser
automation.

## 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-09 08:53:07 -05:00
scotttong 5acf56658b
feat(onboarding): first task opens as a chat with a chief of staff (#13068)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - Onboarding ends by handing a new user to their first agent on a
seeded first task
> - Today the wizard asks for a mission up front, the UI composes what
the agent is told, and the agent starts running before the user says
anything
> - New users get a cold, ticket-shaped start, and nobody can edit the
agent's brief or persona without a code change
> - This pull request makes the first task a short chat: a four-step
wizard, a chief-of-staff persona, a greeting plus a two-option opening
card, server-owned markdown texts, and no run until the user answers
> - It also gives question cards one consistent action row (Cancel /
Skip / Next), makes agent hires idempotent within a run, and turns the
Paperclip Runner flag on by default for self-hosted instances
> - The benefit is a first run the user steers, with texts a board
operator can edit as markdown

## Linked Issues or Issue Description

No public GitHub issue exists for this change. The feature request
fields follow.

Related PRs and issues:

- Refs #11043 — an earlier draft of the first-task onboarding
experience. This PR supersedes it.
- Refs #11280 — a report about the onboarding first-task route test.
This PR extends that test file.

### Subsystem affected

Onboarding wizard, the seeded first task and its texts, task-chat
question cards, agent hiring, and the instance experimental settings.

### Problem or motivation

The onboarding wizard collects a mission through two extra steps and a
questionnaire. The UI then composes the first agent's instructions and
the first task description from those answers. The first task wakes the
agent at once, so the agent runs and posts before the user types a word.
Board operators cannot change the greeting, the brief, or the persona
without editing TypeScript. Question cards in chat behave differently
per adapter, and a single-select pick submits on click. A misread hire
response could create a duplicate agent that the creating agent cannot
remove.

### Proposed solution

Reduce the wizard to four steps and stop the UI from authoring agent
texts. Move the greeting, the brief, the chief-of-staff persona, and the
opening question into markdown and JSON files that the server loads at
runtime. Seed the persona onto the first agent through an explicit hire
marker. Do not wake the first task until the user answers the opening
card or types. Give every question card the same Cancel / Skip / Next
actions. Add an experimental toggle that switches the single-task
proposal between one confirmation card and a plan document with a
checkbox card. Make agent hires idempotent within a run.

### Alternatives considered

- Keep the mission questionnaire and feed it into the brief. Rejected:
the agent asks better questions in chat, and the wizard gets shorter.
- Keep the first task open-ended with a plain composer. Rejected: a
two-option card gives the user a clear first move.
- Derive the plan-document behaviour from the user's intent only.
Rejected in favour of an explicit experimental toggle so operators can
choose.
- Key the "pick does not submit" behaviour off the presence of a submit
label. Rejected: several adapters set a submit label on single-select
cards, and their cards would change behaviour.

### Roadmap alignment

`ROADMAP.md` lists no planned core work on onboarding or the first task.
This change refines the existing flow and does not duplicate planned
work.

## What Changed

- Wizard: four steps (Name your organization, Create your first agent,
Connect a model, Review). The front door and both mission steps are
removed with their state and saved-progress keys. The UI no longer
composes the first agent's instructions or the first task description.
- Server-owned texts: the greeting, the brief with two proposal
variants, the chief-of-staff persona, the opening question, and a README
live in `server/src/onboarding-assets/first-task/` and load at runtime.
The create route stores the assembled brief and ignores any client
description.
- Persona seed: an `onboardingFirstAgent` marker on the hire lets the
server seed the chief-of-staff persona over the first agent's entry
file. Board-authored hires only. The persona tells the agent the hire
response shape and to list agents before it acts on an unclear result.
- No auto-run: the first task does not queue an assignment wake. The
stranded-assignment reconciler leaves it idle until a user comment or an
answered card exists.
- Opening card: the server seeds an `ask_user_questions` card right
after the greeting with two options: "Interview me and propose a plan
and an agent team to execute it." and "I have a task in mind" with free
text. Answering wakes the agent.
- Experimental toggle `enableFirstTaskPlanProposal` (default off): the
single-task proposal is one confirmation card, or a plan document plus a
checkbox card when on.
- Question cards: every `ask_user_questions` card renders Cancel, Skip,
and Next (the submit label on the last question). Skip hides on required
questions. Picking an option no longer advances or submits by itself.
- Wizard guards: the dashboard's agentless offer ignores a cached empty
agent list while a refetch is in flight. The hire step adopts an agent
that already carries the typed name instead of hiring "Name 2".
- Agent hires are idempotent within a run: a retry of the identical
request under the same run id returns the existing agent with `200` and
`idempotent: true`. The fingerprint covers the whole validated request,
so a corrected payload is a new hire. Lookup, create, and activity
record run under one lock per company and run, so overlapping retries
cannot both create.
- The Paperclip Runner experimental flag defaults to on for self-hosted
instances. Cloud keeps its declared default: a managed instance whose
tenant row and managed overlay omit the flag resolves it to off.
- Question cards: a send that finds an earlier required answer missing
returns to that question with a message instead of failing silently.
- The two onboarding e2e specs follow the new wizard: the front door and
growth intake shots are gone, and the planning-mode spec dismisses the
opening card before it reads the composer.
- Docs: `docs/board-operator/editing-first-task-texts.md` explains how
to edit the texts and the toggle.

## Verification

Commands, run from the repo root:

```
pnpm -r --filter './packages/*' --filter '!@paperclipai/paperclip-runner' build
pnpm --filter ./packages/shared typecheck
pnpm --filter ./ui typecheck
pnpm --filter ./server exec tsc --noEmit
pnpm check:token-gates
pnpm --filter ./ui exec vitest run OnboardingWizard onboarding QuestionForm InteractionCard ProtocolCard TaskChatComposer Dashboard feature
PAPERCLIP_IN_WORKTREE=false pnpm --filter ./server exec vitest run onboarding-first-task heartbeat-process-recovery agent-hire-idempotency instance-settings agent-skills-routes issue-onboarding onboarding-greeting --testTimeout=90000
```

Results on this branch:

- Typecheck is clean for shared, ui, and server.
- Token gates: 4 of 4 clean.
- UI: 344 tests pass across 23 files.
- Server: all suites pass. The first test in `agent-skills-routes` has
its own 10 s cap and needs about 15 s on my laptop for the app cold
start. It passes with a longer cap. This PR does not change that cap.

Manual steps on a dev instance:

1. Open `/onboarding`. Confirm four steps: Name your organization,
Create your first agent, Connect a model, Review.
2. Finish the wizard. Confirm the first task shows the chief-of-staff
greeting and the opening card with two options. Confirm no run starts.
3. Pick "Interview me…". Confirm no run starts. Press Continue. Confirm
a run starts and an interview card of 3–4 questions arrives.
4. On a fresh organization, pick "I have a task in mind", type a task,
and press Continue. Confirm a proposal arrives as one confirmation card.
5. Turn on Settings → Experimental → "First task: propose with a plan
document" and repeat step 4. Confirm a plan document and a checkbox card
arrive.
6. Visit the dashboard after the hire. Confirm the wizard does not
reopen and one agent exists.
7. Open any question card. Confirm Cancel returns the plain composer
with the card still pending, Skip advances an optional question, and
Next moves to the next question.

Design reference with flow diagrams, chat mock-ups, and live captures:
https://pages.paperclip.ing/first-task-flow/proposed/

## Risks

- `pnpm dev` now builds the runner daemon because the Paperclip Runner
flag is on by default. Developers without a Rust toolchain must set
`PAPERCLIP_RUNNER_BINARY` or turn the flag off. Self-hosted instances
that never set the flag now let qualified agents use the runner.
- The wizard drops the mission steps and their saved-progress keys. A
user who is mid-wizard on an older build restarts at step 1 after an
upgrade. Existing organizations are not touched.
- The first task no longer runs on its own. A user who neither answers
the card nor types sees no agent activity. This is intended.
- The persona seed applies only to hires that carry the marker from the
wizard. API hires are unchanged.
- Hire idempotency is scoped to one run id and to the exact request.
Retries across runs, or with a changed payload, still create a second
agent. The lock is per server process, which matches how an instance
serves its API.
- Single-select question cards no longer submit on pick. Users of
adapters that relied on that behaviour now press Next.
- No database migrations.

> 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 (Anthropic) through Claude Code. `claude-fable-5-1` with
extended thinking, tool use, and code execution wrote most commits.
`claude-opus-4-8` wrote the toggle, texts, wizard, and idempotency
commits, as the `Co-Authored-By` trailers show.

## 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: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-08 20:19:14 -07:00
Dotta e200104727
feat: review connection actions from tasks (#13063)
Bring governed connection reviews into task history and composer approvals. Share resolution with Connections, add scoped remembered permissions, and resume agents through durable outcome receipts.

Keep cards compact, collapse raw results, isolate untrusted provider output, bound continuation payloads, and reconcile missed live events. Add Storybook coverage, browser journeys, and service regression tests.

Verification: all PR CI gates passed, Greptile 5/5, security scans passed, five connection-review browser journeys passed, and real native Codex approval/continuation was verified against the local MCP fixture.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-09-08 19:37:13 -05:00
Devin Foley fe5e68d7a5
fix: make Codex sign-in and the environment test agree on the credential a run uses (#13064)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - The `codex_local` adapter signs agents in to OpenAI with a
device-code login, and the agent page has a Test button that probes the
sandbox with the credentials a real run would use
> - The login stored its credential where the Test never looked: the
company Codex home kept an old shape-valid credential, so the Test
failed with "authentication needed" right after a successful sign-in
> - The Test also staged a different Codex home than a real run
resolves, so the Test and real runs could disagree in both directions
> - This pull request makes the login, the seeding pass, and the Test
probe agree on one credential resolution
> - The benefit is that a sign-in from the agent page fixes the Test on
the next click, and a green Test means the same thing a real run
experiences

## Linked Issues or Issue Description

**What happened?**

Sign in with Codex works during onboarding but not on the agent detail
page. The operator completes the device-code login. The panel reports
success. The Test button still reports that authentication is needed. No
number of repeat logins changes the result.

Three defects combine to cause this:

1. The device-login promotion only wrote the company default Codex home
when that home held no shape-valid credential. A stale credential (for
example a symlink to an old host login) blocked the write forever, so
the fresh login stayed invisible to the Test.
2. The seeding pass that runs before every probe and execute replaced a
same-identity regular-file `auth.json` with a symlink to the host
credential, with no freshness comparison. Even a freshly promoted
credential was deleted on the next Test.
3. The sandbox hello probe always staged the company default home. An
agent with a configured `CODEX_HOME` was tested against one credential
and ran with another.

**Expected behavior**

A completed sign-in updates the credential the Test probes. The Test
stages the same Codex home a real run resolves. A stale credential never
outranks a strictly newer one from an interactive login.

**Steps to reproduce**

1. Configure a company whose Codex home holds a shape-valid credential
that no longer authenticates (for example an old host login symlink).
2. Open a `codex_local` agent's detail page with a sandbox environment
and press Test. The result shows the authentication-needed check.
3. Complete the "Sign in with Codex" device-code flow from the panel.
4. Press Test again. Before this change the result still shows
authentication needed.

## What Changed

- `packages/adapters/codex-local/src/server/adapter-auth-promotion.ts`:
the promotion writes the company default home unconditionally. The
shared `last_refresh` merge predicate scopes the write. It seeds an
absent or unusable slot, refreshes a same-identity slot only with a
strictly newer credential, and keeps a slot a different account or an
API-key file holds. The atomic rename replaces a symlinked `auth.json`
at the link itself. It never writes through into the host home.
- `packages/adapters/codex-local/src/server/codex-home.ts`: the
same-identity heal in `seedManagedCodexHome` is freshness-aware. A
regular-file credential is swapped for the shared symlink only when the
shared source is strictly fresher by `last_refresh`. Ties and
unparseable timestamps keep the file, which matches the predicate's
fail-closed direction. A genuine stale copy still heals as soon as the
host credential rotates past it.
- `packages/adapters/codex-local/src/server/test.ts`: the sandbox hello
probe prepares and stages the same home a real run resolves. The
identity-anchored cache vend runs first. A configured managed
`CODEX_HOME` is seeded in place and staged. A genuine external override
is staged as-is and never seeded or mutated.
- Tests: new pins for the strictly-newer company-home refresh, the
different-account keep, the symlink-replaced-without-writing-its-target
property, the freshness-aware heal (newer kept, older healed, ties
kept), the configured-home staging, and the external-home no-mutation
proof. The remote-probe suite now pins `CODEX_HOME`/`PAPERCLIP_HOME` to
scratch directories so no test can touch a real `~/.codex`.

## Verification

- `pnpm exec vitest run packages/adapters/codex-local/src --root
packages/adapters/codex-local` — 378 passed, 1 skipped.
- Server suites for device login, reconciliation, and the codex adapter
(8 files) — 128 passed, 15 skipped.
- `tsc --noEmit` clean in the adapter package.

## Risks

- Behavioral shift is scoped by the shared merge predicate: only a
strictly newer same-identity login can displace a company-home
credential, so a second account still never takes over the company slot,
and API-key files are never displaced.
- The heal keeps ties and unparseable timestamps instead of swapping. A
kept file self-corrects on a later seed once the source is provably
fresher; deleting a promoted credential is irreversible, so the failure
direction is chosen deliberately.
- The probe change makes the Test exercise the credential a run uses. A
Test that previously passed against the company home while the agent's
configured home was broken now fails honestly.

## Model Used

Claude (Anthropic) — Claude Fable 5 (`claude-fable-5`), extended
thinking, agentic tool use in Claude Code (terminal). Diagnosis traced
through the live promotion locks, the on-disk Codex homes, and the
adapter's credential-resolution code paths.

**Related PRs (searched; no duplicates found):** #12740, #12082, and
#9621 touch adjacent Codex credential sync paths; #8495 is the standing
hardening effort for probe auth seeding.

## 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 (no
standalone docs cover this flow; the behavioral contracts are documented
in-line at each changed site)
- [x] I have considered and documented any risks above
2026-09-08 17:16:17 -07:00
Dotta 2043e0c735
fix: repair runner configuration, macOS execution, and artifact galleries (#13062)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Agent adapters select a provider, a model, and a runtime.
> - Runner conversion rejected existing Claude agents. The model list
mixed providers.
> - The native Claude runner rejected custom models and could not launch
on macOS.
> - This pull request fixes conversion, model selection, and verified
macOS execution.
> - It also groups configuration fields consistently across adapters and
opens artifact images in the task gallery.
> - Operators can change an agent configuration and run the selected
model on their Mac.

## Linked Issues or Issue Description

**What happened?**

Converting an existing Claude agent to Paperclip Runner failed with a
Codex-only restriction. ACPX Claude showed unrelated models and required
`claude-sonnet-5`. Its native runtime rejected macOS. Configuration
mixed common model settings with process controls. Artifact cards
labeled “Open gallery” navigated to attachment URLs instead of opening
the task gallery.

**Expected behavior**

Conversion keeps agent identity and compatible settings. ACPX Claude
uses the normal Claude catalog and accepts typed model IDs. Codex uses
the native runner. The verified Claude runtime can launch on macOS ARM64
and x64. Common configuration sections place the same fields together
across adapters. Artifact images open in the shared task gallery with
navigation and downloads.

**Steps to reproduce**

1. Open the configuration of an existing Claude agent.
2. Convert it to Paperclip Runner.
3. Select ACPX Claude and a different catalog model or a typed model ID.
4. Save the agent and run a disposable task on macOS.
5. Inspect configuration and advanced run-policy controls across
adapters.

**Paperclip version or commit**

The bugs were reproduced on `165ca56a22adb60e5fda56045442d9c8498116a8`.
This branch was rebased onto `7ed122911`.

**Deployment mode**

Built from source. Local test-drive instance on macOS ARM64 with an
isolated database.

Related work: #11798 addresses unsupported ACP session options in the
existing adapter path. #13048 addresses working-folder preservation.
This change fixes native runner configuration and launch behavior.

## What Changed

- Remove the Codex-only conversion restriction. Preserve agent identity,
instructions, directories, credentials, and compatible model settings.
Reset incompatible sessions while retaining history.
- Show ACPX Claude and native Codex as distinct provider choices. Remove
ACPX Codex from advertised configuration. Normalize legacy
configurations before fresh runs without rewriting historical run
descriptors.
- Select model catalogs and cache entries by provider. Support refresh
and typed model IDs. Pass exact Claude IDs through session creation,
model changes, and recovery.
- Add verified macOS ARM64 and x64 Claude SDK snapshots. Bound
executable allocation and total snapshot size. Preserve package checks,
dependency isolation, process ownership, cancellation, and Linux
descriptor loading.
- Probe local runtime readiness. Report remote platform checks as
incomplete until the remote runner verifies its runtime.
- Surface actual model rejection and allow correction and retry.
- Repair missing ACPX goal-capability helpers exposed by the post-rebase
live test. Persist and restore the optional capability without breaking
session startup.
- Put Agent identity first and intentionally remove the Capabilities
editor, as requested. This is removal of UI editing, not relocation:
preserve existing capability metadata and API compatibility without
adding another editor. Use the themed select for configurable permission
modes, with normal text instead of monospace.
- Put model and provider under Adapter. Give environment variables their
own section. Fold command and arguments under Configuration. Fold
lifecycle, timeout, and interrupt grace under Advanced Run Policy. Hide
single-option permission controls.

- Open image and video artifact cards in the existing task gallery,
including cards in the artifacts panel. Chat attachment images use the
same gallery. Preserve standalone media previews and download links.

## Verification

- Rebased focused UI/API/database suites: 293 tests passed.
- Rebased native runtime and ACPX suites: 242 passed, 7 skipped.
- Repository typecheck, build, and token gates passed for the runner
changes. Gallery follow-up UI typecheck, build, and token gates also
passed.
- Follow-up UI suites passed (86 tests), packaging checks passed (14
tests), and the final focused runtime suites passed (126 passed, 7
skipped).
- Linux container isolation and lifecycle fixtures passed before rebase
(57 passed, 2 skipped). Rust ACPX provider-session tests passed after
rebase (8 tests).
- Browser tests completed actual Claude and native Codex tasks on macOS
ARM64. They covered conversion, catalog refresh, a non-default catalog
model, a typed `haiku` ID, save/reload, cancel, follow-up session
continuity, invalid-model errors, and recovery.
- Final-revision live tests completed a typed Claude task, a follow-up
with the same provider session, and a native Codex task on macOS ARM64.
- Browser tests confirmed the moved interrupt-grace field saves and
survives reload. Cross-adapter tests cover Claude, Codex, Gemini,
process, gateway, and schema forms.
- Full local run: 7,080 passed, 30 skipped, and two timeouts. Both
timeout suites passed on isolated rerun (84 tests); the failures were
the plugin login-worker exit diagnostic and the runner real-server
vertical slice.
- Final follow-up checks: 50 registry tests and 45 snapshot/installation
tests passed (6 platform-specific skips). Oversized executable rejection
is covered before allocation or reading; unsupported-platform tests
invoke the real installation probe.
- Runner head `ddb5101c483a297f74875ab96b3c66035b002d50`: all CI gates
green, including full runner verification, repository build, typecheck,
general/serialized server suites, browser tests, and canary dry run. [CI
run](https://github.com/paperclipai/paperclip/actions/runs/34286178670).
- Greptile: 5/5 on that runner head. All four review threads resolved.
Superagent, Socket, and Snyk checks green.
- After snapshot hardening, another real Claude task completed on this
Mac using the rebuilt runtime.

- Gallery follow-up: 148 focused tests passed, covering artifact
selection, shared attachment collections, deduplication, image/video
cards, standalone previews, downloads, and closing. Live browser
verification completed on the settings follow-up: artifact selection,
6-image pagination with wrapping, download action, and closing all
stayed on the same task URL. All checks passed on gallery head
`96136da58ff195bf6ca00b281eb3022ad12d7bd8`: [CI
run](https://github.com/paperclipai/paperclip/actions/runs/34287987536).
Greptile returned 5/5 on that exact head with no unresolved threads.

- Final settings polish: 96 focused tests, UI typecheck/build, and token
gates passed. A real browser walkthrough verified readable permission
options, identity placement, Capabilities removal, and permission
save/reload. Original test-agent permission mode restored. All 31 checks
passed on final head `e46540d6bf32bfb0566dca16b2f4a75ba437618c`: [CI
run](https://github.com/paperclipai/paperclip/actions/runs/34292797886).
Greptile returned 5/5 with no unresolved threads.

## Risks

- Capabilities intentionally has no editable UI field after this change.
Existing values remain readable and API-compatible; removing the field
does not erase stored metadata.

- macOS launch now copies verified package files into private snapshots.
The implementation must retain isolation and clean up snapshots on exit.
- Runtime provider or model changes reset the current session.
Historical runs remain available.
- The macOS x64 SDK executable digest was verified, but a live Intel Mac
run was not available. Linux verification used container fixtures, not a
real Claude task.
- Remote environment tests report a warning when only the platform has
been checked. They do not claim package readiness from the server host.

## Model Used

OpenAI Codex, based on GPT-6. The exact served model identifier and
context-window limit are not exposed in this session. Used reasoning,
repository inspection, code execution, Rust and TypeScript tests, and
browser automation.

## 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 and both
timeout suites on rerun; full-run counts 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-08 19:10:09 -05:00
Dotta 7ed122911b
Add end-to-end session goals to Paperclip Runner
Add capability-aware slash-goal controls, durable provider goal state, PRP v2 negotiation, autonomous goal execution, and safe local session recovery. Integrate with current master, preserve provider session identity, and verify the browser goal/chat/replacement/clear workflow and unsupported-agent rejection.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-09-08 16:18:47 -05:00