## 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>
## 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>
## Thinking Path
> - Paperclip manages AI agent work and the execution state for each
task.
> - Remote agents run in sandbox environments such as Daytona.
> - Daytona keeps files while a sandbox is stopped, but deletion removes
those files.
> - Runner Codex did not copy successful remote workspace changes back
to the host workspace.
> - A warm sandbox could therefore hide data loss until Daytona replaced
or deleted the sandbox.
> - This pull request makes the host workspace durable after every
successful turn and keeps verified reusable sandboxes warm.
> - The benefit is reliable multi-turn work across warm reuse, restart,
stop, and sandbox replacement.
## Linked Issues or Issue Description
**What happened?**
A successful native Codex turn in Daytona could leave workspace changes
only in the remote sandbox. A later warm turn appeared to work because
it reused that filesystem. A replacement sandbox could start from stale
host data and lose the successful changes.
**Expected behavior**
Paperclip must merge each successful remote turn into the authoritative
host workspace before it completes the run. A verified warm lease may
reuse its remote files. A replacement lease must reconstruct the exact
durable workspace seed.
**Steps to reproduce**
1. Run Codex in a reusable Daytona environment.
2. Write a file during one successful turn.
3. Replace the Daytona sandbox before the next turn.
4. Observe that the next turn can start without the prior file on the
unpatched code.
Related remote workspace foundation: #10070.
## What Changed
- Added explicit `host_current`, `durable_seed`, and `adopt_remote`
workspace preparation modes.
- Added atomic, versioned native workspace descriptors and seed archives
under `PAPERCLIP_HOME`.
- Added real native sandbox export and three-way host merge before
terminal result completion.
- Added workspace-only recovery after a proposed result. Recovery does
not submit another provider turn or consume the provider retry budget.
- Added fail-closed handling when a sandbox with unexported changes is
gone.
- Kept healthy reusable Daytona sandboxes started for legacy Codex and
Runner Codex.
- Kept the Runner Codex process and provider session across verified
warm turns.
- Added the paid `daytona-warm-continuity` browser suite. It contains
exactly the legacy Codex and Runner Codex cells. Each cell performs
three measured turns.
- Documented `pnpm test:e2e:runner -- --suite daytona-warm-continuity`.
No package script was added.
- Added no database migration. The metadata format is backward
compatible and idempotent.
## Verification
- `pnpm typecheck`
- `pnpm test:e2e:runner:unit` — 114 passed
- Native workspace, finalizer, session, and environment tests — 232
passed
- Daytona provider tests — 150 passed
- Workspace staging and merge tests — 98 passed
- Runner transport tests — 63 passed
- Legacy Codex restore tests — 5 passed
- Rust format and compile checks pass through root typecheck
- The paid Daytona suite was not run locally because the required
Daytona, OpenAI, and immutable image credentials are not present.
## Risks
- The main risk is an incorrect workspace identity or merge after a
crash. Durable descriptors bind the run, workspace, lease, provider
lease, local root, remote root, and baseline digest. Ambiguous evidence
fails closed.
- The host merge may conflict with concurrent host edits. The existing
three-way merge and exclusion rules handle this case and surface
failures.
- A deleted sandbox cannot recover unexported bytes. Paperclip now
blocks with `workspace_sync_out_unrecoverable` instead of reporting
success or rerunning the provider.
- There is no database migration. Descriptor writes and recovery are
atomic and idempotent.
## Model Used
OpenAI Codex with GPT-5. The run used agentic reasoning, repository
inspection, code execution, test execution, Git, and GitHub CLI tools.
## Checklist
- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge
## Thinking Path
> - Paperclip is the open source app people use to manage AI agents for
work.
> - Agent authentication uses server sessions, plugin workers, and
browser login panels.
> - A page reload loses an active login session, and one worker permits
only one login terminal.
> - These limits cause lost work and prevent two owners from logging in
through one worker.
> - This pull request lets the browser resume active sessions and lets
workers serve concurrent login terminals.
> - The benefit is reliable login recovery with a bounded process-wide
route limit.
## Linked Issues or Issue Description
**What existing behavior does this improve?**
It improves agent credential login recovery and concurrent login
terminal handling.
**Subsystem affected**
Cross-cutting (multiple of the above).
**Current behavior**
A page reload loses the active login session. A shared plugin worker
rejects a second login terminal.
**Proposed behavior**
The browser reads and resumes the owner's active session. A worker
supports multiple login terminal routes under a process-wide ceiling.
**Reason and benefit**
Owners keep login progress after a reload. Two owners can log in through
one worker without removing the route limit.
**Breaking changes**
None. The change adds owner-scoped read routes and changes login
terminal concurrency.
## What Changed
- Replace the single worker login route with maps keyed by host route
and worker session identifiers.
- Add a process-wide login route ceiling and release each reserved slot
on every exit path.
- Add owner-scoped active-session reads with consistent negative
responses and private cache control.
- Keep the device-login prompt while the session has an active public
status.
- Add a durable setup-token cancel fallback for a lost in-memory
session.
- Resume active sessions when the agent configuration or onboarding
panel mounts.
- Remove routine unmount cancellation and keep explicit Cancel behavior.
## Verification
- `pnpm --filter @paperclip/server test` — server route, service, and
plugin-worker-manager suites.
- `pnpm --filter @paperclip/plugin-sdk test` — worker RPC host suite.
- `cd ui && npx vitest run
src/components/AgentConfigForm.render.test.tsx
src/components/OnboardingWizard.test.tsx`.
- `cd ui && npx tsc -b`.
- `tests/e2e/onboarding.spec.ts` — reload during login.
- CI must pass on this pull request.
## Risks
The change affects agent authentication and the sandbox-to-host
boundary. Route cleanup must release every reserved slot. Owner checks
must prevent cross-owner session access. Tests cover route cleanup,
owner scope, reload recovery, and concurrent worker routes.
## Model Used
Codex, OpenAI GPT-5, tool use and code review support. The
implementation author owns the exact model details for the code changes.
## 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 with the relevant issue-template
fields
- [x] I have not referenced internal/instance-local Paperclip issues or
links
- [x] My branch name describes the change and contains no internal
Paperclip ticket id
- [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 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>
## Thinking Path
> - Paperclip manages AI agents and their provider runtimes.
> - The paid runner workflow installs target dependencies with lifecycle
scripts disabled.
> - The bundled Daytona plugin depends on an audited repo-local plugin
SDK link.
> - The lifecycle-safe install path did not create that link.
> - This pull request restores only the trusted Daytona preparation step
before provider secrets are exposed.
> - The benefit is a working Daytona canary without enabling dependency
lifecycle scripts.
## Linked Issues or Issue Description
**What happened?**
The Daytona paid canary stopped before lease or provider startup. The
trusted paid job disabled root lifecycle scripts, so the repo-local
plugin SDK link was absent. The plugin install returned a missing
runtime dependency error for @paperclipai/plugin-sdk.
**Expected behavior**
The trusted workflow must prepare the bundled Daytona plugin without
running untrusted dependency lifecycle scripts. The paid cell must start
only after its runtime dependencies and entrypoints pass validation.
**Steps to reproduce**
1. Dispatch the runner full-stack paid workflow for
core-compatibility.runner-acpx-claude.daytona.message-marker.
2. Let the trusted job install root dependencies with lifecycle scripts
disabled.
3. Observe the Daytona plugin installation fail before a lease or
provider process starts.
**Paperclip version or commit**
Feature head 781ac7e08c. The failed canary
is Actions run 33803959325.
**Deployment mode**
GitHub Actions paid runner validation.
**Agent adapter(s) involved**
ACPX Claude through the bundled Daytona plugin.
**Additional context**
This is a small trusted-workflow prerequisite for public PR #12769. Old
green run 33118525827 created the SDK link through root postinstall.
This change keeps lifecycle scripts disabled and restores only the
audited prerequisite.
## What Changed
- Install standalone Daytona dependencies with lifecycle scripts
disabled.
- Run the audited repo-local plugin SDK linker before provider secrets
are exposed.
- Build the bundled Daytona plugin and verify its runtime dependency
plus both entrypoints.
- Add a security regression for ordering, scope, and secret isolation.
## Verification
- Five focused workflow-security tests passed.
- Seven focused linker tests passed.
- The exact Daytona preparation command completed locally in nine
seconds.
- Prettier and diff whitespace checks passed.
## Risks
Risk is low and limited to Daytona paid cells. The setup still disables
dependency lifecycle scripts. The trusted step runs before provider
credentials enter the job. Any missing or mismatched path fails closed
before provider startup.
## Model Used
OpenAI GPT-5 Codex with repository tools and code execution.
## Checklist
- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used with version and capability
details
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have described the issue in this PR with the bug template labels
- [x] I have not referenced internal or instance-local Paperclip issues
or links
- [x] My branch name describes the change
- [x] Focused local tests pass
- [x] I added tests for the change
- [x] I updated the relevant trusted-workflow security regression
- [x] I documented the risks above
Bumps @pierre/diffs from 1.3.5 to 1.3.6.
<details>
<summary>Maintainer changes</summary>
<p>This version was pushed to npm by <a
href="https://www.npmjs.com/~ije">ije</a>, a new releaser for
<code>@pierre/diffs</code> since your current version.</p>
</details>
<br />
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
## Thinking Path
> - Paperclip is the control plane for companies that use AI agents for
work
> - Local adapters connect Paperclip agents to provider command line
tools
> - The Codex adapter stores login data in a shared company home
> - A shared home cannot keep credentials for more than one Codex
account
> - This pull request gives each account a safe home and a matching
company secret
> - The benefit is that one company can use multiple Codex accounts at
the same time
## Linked Issues or Issue Description
**Problem or motivation**
A company can hold only one Codex subscription credential because device
login uses one shared home. A second account cannot log in without
replacing or conflicting with the first credential.
**Proposed solution**
This change validates the vendor account identifier, stores each
credential in its own home, and creates a company secret that points to
that home. Repeat login calls return success when the matching secret
already exists.
**Roadmap alignment**
The change supports the roadmap goal for centrally managed secrets with
scoped access and audited resolution.
**Additional context**
The security review returned approve with no blocking finding. The
branch adds shared account-handle validation and tests for device login
and the Codex local adapter.
## What Changed
- Add strict allowlist validation for Codex account handles.
- Store each Codex account credential in a separate home under the Codex
cache root.
- Verify that the resolved account home stays inside the cache root.
- Create the `CODEX_HOME_<handle>` company secret for each account.
- Keep repeat and concurrent login calls safe and idempotent.
- Add shared helper and route, adapter, and validation tests.
## Verification
- `pnpm --filter @paperclipai/adapter-codex-local test` passes with 343
tests.
- `pnpm --filter @paperclipai/server test
src/__tests__/agent-device-login-routes.test.ts` passes with 25 tests.
- The adapter suite passes with 23 tests.
- The shared package and Codex adapter typechecks pass.
- Continuous integration must pass on every check before merge.
## Risks
The account handle becomes part of a directory path and secret name. The
strict allowlist and root containment check reduce path traversal risk.
Existing single-account homes remain unchanged unless a new device login
creates an account-specific home.
## Model Used
OpenAI GPT-5 (exact runtime model ID: gpt-5), with tool use and code
execution. The runtime context window is not exposed in this run.
## 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
- [ ] 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>
## Thinking Path
> - Paperclip manages agents that use different model providers and
adapters.
> - Paperclip must keep agent execution rules clear and predictable.
> - The cheap-model profile added a second execution mode across
adapters, task recovery, APIs, and the UI.
> - That mode increased configuration and recovery complexity.
> - This pull request removes the cheap-model profile as a product
feature.
> - The benefit is one model-selection path for normal work and recovery
work.
## Linked Issues or Issue Description
**What existing behavior does this improve?**
This change simplifies model selection across agent configuration, task
execution, recovery, and adapter capabilities.
**Current behavior**
Paperclip exposes cheap-model profiles in adapter metadata, agent
runtime configuration, task overrides, recovery rules, APIs, and the
board UI. Recovery work can select a different model profile from the
agent's configured model.
**Proposed behavior**
Paperclip uses the agent's configured model for normal work and recovery
work. Status-only recovery stays limited to coordination work. The API
rejects legacy model-profile configuration. A migration removes stored
model-profile values from existing agent, issue, and historical revision
records.
**Reason and benefit**
One model path reduces configuration, API, UI, and recovery complexity.
It also prevents status recovery from becoming a separate product-level
model-routing feature.
**Breaking changes**
This change removes model-profile fields and adapter capability
metadata. Existing stored model-profile values are removed by an
idempotent migration. The validators reject new legacy profile values
with clear errors.
## What Changed
- Removed model-profile types, adapter capabilities, API fields, and
model selection logic.
- Removed cheap-model controls from agent and task UI surfaces.
- Kept status-only recovery limited to coordination context while normal
continuations use the configured agent model.
- Added an idempotent migration that removes stored model-profile values
from agents, issues, and configuration revisions without changing issue
update timestamps.
- Updated tests and product documentation for the single-model behavior.
## Verification
- `pnpm check:token-gates` passes.
- `pnpm -r typecheck` passes.
- `pnpm build` passes.
- `pnpm test:run` completed with 5,607 passing tests and 8
environment-sensitive failures in unrelated fixed-port and
database-deadlock suites. The same failures repeated in an isolated
rerun. CI is the final clean-room result.
## Risks
- This is an intentional breaking change for clients that send
model-profile fields.
- The migration changes legacy agent, issue, and configuration-revision
JSON. It is idempotent and preserves unrelated fields and issue update
timestamps.
- The change is cross-cutting because the removed feature existed in
adapters, shared contracts, the server, plugins, and the UI.
> 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`. Reasoning and tool use were enabled. The
runtime did not expose the 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)
- [ ] 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>
## Thinking Path
> - Paperclip is the open source app people use to manage AI agents for
work.
> - Paperclip Runner gives native runs a durable and governed execution
path.
> - The current native path runs on the control-plane host.
> - Remote environments need an authenticated execution-target contract.
> - The contract must not change direct adapters or enable new runtimes
by default.
> - This pull request adds the remote execution substrate and Daytona
ingress.
> - The benefit is a bounded base for later remote runner transport
work.
## Linked Issues or Issue Description
Refs #12616.
Refs #12352.
**Subsystem affected**
Cross-cutting. This change touches runner transport, server
orchestration, plugin contracts, and shared settings.
**Problem or motivation**
Native execution cannot resolve an authenticated runner ingress through
a remote environment. The server also lacks one provider-neutral
contract for remote execution targets.
**Proposed solution**
Add a default-off runner preview ingress capability. Add
transport-neutral runner connectivity. Add remote execution target and
lifecycle handling. Add a Daytona ingress implementation with redacted
credentials.
**Alternatives considered**
A provider-specific server path would duplicate orchestration and
authorization. A public endpoint without an environment contract would
weaken the trust boundary.
**Roadmap alignment**
This work supports the Cloud and Sandbox agents milestone. It also
supports self-healing runs and governed tool access.
## What Changed
- Added execution-target traits for local, SSH, and sandbox
environments.
- Added plugin RPC contracts for runner ingress endpoints.
- Added authenticated Daytona preview ingress.
- Added transport-neutral PRP outbound connections.
- Added remote runner artifact verification and fail-closed provider
selection.
- Added bounded native session resume, cancellation, and lifecycle
recovery.
- Preserved Codex-only selection for fresh experimental runner starts.
- Preserved all direct adapter execution and finalization paths.
- Removed stale Pi provider-pack requirements that security review
rejected.
- Kept the rollout controls off by default.
- Did not change pnpm-lock.yaml, Cargo, database migrations, or GitHub
workflows.
## Verification
- GitHub Actions will run the repository test, typecheck, build,
security, and policy gates.
- Focused tests cover ingress validation, redaction, execution targets,
remote lifecycle, cancellation, resume, and legacy adapter selection.
- Local tests were not run. The requested verification policy uses
GitHub Actions for this series.
- `git diff --check origin/master...HEAD` passes.
- The diff contains 52 files.
## Risks
- Remote execution crosses a trust boundary.
- The implementation validates target capabilities, artifact digests,
provider-pack pins, and connection metadata.
- The feature remains default-off.
- Fresh native selection remains Codex-only.
- Existing direct adapters remain on the legacy path.
- This PR does not yet make remote Codex runnable. The next PR adds the
Rust WSS and TLS transport.
## Model Used
OpenAI Codex with GPT-5.6. The work used high-reasoning agent mode,
repository tools, GitHub tools, and parallel code-audit agents.
## 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 or instance-local Paperclip issues
or links
- [x] My branch name describes the change and contains no internal
Paperclip ticket id
- [ ] 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 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
## Thinking Path
> - Paperclip is the open source app people use to manage AI agents for
work.
> - Agents need a governed way to request app connections during issue
work.
> - The catalog now describes the available providers and setup methods.
> - A request must become a durable, company-scoped intent before an
operator acts on it.
> - This pull request adds that intent runtime across server, agent,
CLI, and shared contracts.
> - The benefit is a safe bridge from agent need to operator-approved
setup.
## Linked Issues or Issue Description
Refs #11965
This is stack 7 of 11. It depends on stack 6 and replaces another
reviewable part of #11965.
## What Changed
- Add connection intent types, validation, service logic, and routes.
- Add agent runtime tools and CLI support for connection requests.
- Add issue-thread interaction support for connection intents.
- Add runtime, route, adapter, and contract tests.
- Hold the final resolved-continuation row lock through asynchronous
adapter preparation until an actual process spawn, so parking or
reassignment cannot cross that boundary.
- Report Hermes Gateway's first remote run request through the shared
dispatch hook so the resolved-intent lock is released at the true
dispatch boundary.
- Revalidate the addressed user's live non-viewer membership and
connection-management authority for every intent mutation, including
OAuth completion.
## Verification
- `pnpm --filter @paperclipai/server typecheck`
- `pnpm --filter @paperclipai/server exec vitest run
src/__tests__/tool-access-service.test.ts`
- Result: 176 tests passed.
- `pnpm build`
- `pnpm --filter @paperclipai/server exec vitest run
src/__tests__/heartbeat-stale-queue-invalidation.test.ts` (32 passed;
includes non-process dispatch lock-release coverage)
- `pnpm exec vitest run --project @paperclipai/server
server/src/__tests__/connection-intents-service.test.ts -t
"addressed-user mutation"` (1 passed)
- `pnpm exec vitest run --project @paperclipai/server
server/src/__tests__/tool-access-service.test.ts -t "binds OAuth
callback completion to the initiating board session"` (1 passed)
- `pnpm --filter @paperclipai/hermes-paperclip-adapter test --
src/gateway/server/execute.test.ts` (23 passed; includes dispatch-hook
ordering and exactly-once coverage)
- `pnpm --filter @paperclipai/hermes-paperclip-adapter typecheck`
## Risks
- A malformed intent could create an unusable operator request.
- Validators and company checks reject invalid or cross-company
requests.
- The final continuation gate holds the issue row lock through adapter
preparation until process or remote dispatch; later operator changes use
the normal active-run interruption path.
- The change does not add a database migration.
> I checked `ROADMAP.md`. This stack continues the existing app
connection work from #11965 and does not duplicate another planned item.
## Model Used
OpenAI Codex, GPT-5. The runtime model ID and context window were not
exposed. The model used reasoning, tool use, and code execution.
## Checklist
- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have linked the public source pull request with `Refs #`
- [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 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>
## Thinking Path
> - Paperclip is the open source app people use to manage AI agents for
work
> - Paperclip uses adapters to connect agents and model providers to its
control plane
> - The sandbox login panel supports displayed-code login for selected
adapters
> - Grok users need the same login path and a private credential home
for later runs
> - This pull request adds Grok support to the shared device-login path
and preserves the existing Codex path
> - The benefit is one secure login flow for both adapters with
company-scoped credential storage
## Linked Issues or Issue Description
**Agent or provider**
Grok Local needs displayed-code login support in the sandbox login
panel.
**Why this adapter is useful**
This change lets users sign in to Grok from the sandbox login panel. It
also gives later Grok runs access to the stored credential.
**How the agent is invoked**
The Grok local adapter uses its login command through the shared
displayed-code login flow. Later runs receive the managed home through
`GROK_HOME`.
**Additional context**
The change uses adapter-scoped login lifecycle handling. It stores the
credential in a company-scoped directory with mode `0700`, and it stores
the credential file with mode `0600`.
## What Changed
- Rename the shared device-login modules to adapter-neutral names.
- Scope the shared login lifecycle to a closed adapter set.
- Return the device-login URL that the provider prints.
- Add the Grok prompt parser, login command, capability, and login panel
entry.
- Store the Grok credential in a private, company-scoped home directory.
- Pass `GROK_HOME` to later Grok runs.
- Add tests for the Grok adapter, the Daytona sandbox provider, the
server login path, and the user interface.
## Verification
- Run `pnpm vitest run
packages/adapters/grok-local/src/server/adapter-auth-promotion.test.ts`.
- Run the Grok adapter package suite.
- Run the Daytona sandbox provider suite.
- Run the server device-login suites.
- Run the user interface suite.
- Confirm the full CI suite passes.
## Risks
The change extends shared login lifecycle code to another adapter. A
regression could affect Codex login. The credential path uses explicit
`chmod` calls to keep the directory at mode `0700` and the file at mode
`0600`.
## Model Used
OpenAI Codex, GPT-5. The runtime used tool calls and code review
support. 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
- [ ] 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>
## Thinking Path
> - Paperclip is the open source app people use to manage AI agents for
work
> - Sandbox providers let agents run in remote environments
> - The Daytona login flow creates a home directory for each login
session
> - The create path ran owner, mode, and link-type checks inside the
sandbox
> - These checks cannot protect the host because sandbox code can change
the checked state
> - This pull request uses one `mkdir -p` command and removes the unused
helper scripts
> - The benefit is a simpler login path with the host-side credential
checks unchanged
## Linked Issues or Issue Description
**What happened?**
The Daytona login flow used helper scripts and inside-sandbox checks for
the session-home directory. The standalone package build also copied a
scripts directory that no longer existed after the helper scripts were
removed.
**Expected behavior**
The login flow must create the session home with one `mkdir -p` command.
The package build must complete without copying a removed directory.
**Steps to reproduce**
1. Build the Daytona plugin package.
2. Start a Daytona device login.
3. Inspect the session-home create command and the package output.
**Paperclip version or commit**
Commit `dfdf5914ba37caa1e3bc380236844a7d76237e12`.
**Deployment mode**
Built from source.
## What Changed
- Replace the session-home helper checks with one `mkdir -p` command.
- Remove the two unused session-home helper scripts.
- Remove the dead build copy steps for the deleted scripts directory.
- Add coverage for a failed session-home create command.
- Keep the host-side credential reader unchanged.
- Keep the Kubernetes provider package unchanged.
## Verification
- Package unit tests pass: 220 passed, 6 skipped.
- Package typecheck passes.
- The package build passes and emits 56 files in `dist`.
- The roadmap check confirms that this change stays within the planned
sandbox-provider work.
- GitHub search found no open duplicate or related pull request.
## Risks
The login flow no longer reports owner, mode, or link-type errors from
inside the sandbox. Those checks did not protect the host. The host-side
credential reader still uses no-follow path opens and accepts only a
regular file with owner and exact mode `0600`. Risk is low because this
change removes checks that cannot enforce the host security boundary.
> For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and
discuss it in `#dev` before opening the PR. This pull request updates an
existing sandbox-provider path, not a new core feature.
## Model Used
OpenAI Codex, GPT-5. The runtime provides tool use and code execution.
The runtime does not expose the context window size or a more specific
model identifier.
## 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>
## Thinking Path
> - Paperclip is the open source app people use to manage AI agents for
work
> - Sandbox providers run agent work in isolated environments
> - The Daytona inbound file-sync path writes selected sandbox data to
host paths
> - Its in-sandbox lexical and realpath guards do not protect host-write
or Paperclip API authority
> - This pull request removes those guards and simplifies the inbound
file-sync commands
> - The benefit is a smaller path with the same outbound controls and
host extraction validation
## Linked Issues or Issue Description
No public issue exists for this change. This pull request describes the
enhancement.
**What existing behavior does this improve?**
It improves inbound file and directory synchronization for the Daytona
sandbox provider.
**Subsystem affected**
`packages/plugins` — the Daytona sandbox provider.
**Current behavior**
The inbound path checks lexical and realpath confinement inside the
sandbox. It uses file-descriptor-pinned commands for file promotion,
archive extraction, and decompression. These checks do not protect
host-write or Paperclip API authority.
**Proposed behavior**
Remove the inbound lexical and realpath checks. Use `mv -f` for file
mappings, `tar -xf` for directory mappings, and `zstd -d -o` for
decompression. Keep outbound source checks, atomic snapshot downloads,
and tarball member validation.
**Reason and benefit**
The sandbox boundary protects the relevant authorities. The removed
guards run inside that boundary and only produce early errors. The
simpler commands reduce code and preserve the controls that protect the
host boundary.
**Breaking changes**
The inbound path no longer rejects mappings because of sandbox-side
lexical or realpath confinement. Outbound source validation and tarball
member validation remain unchanged.
## What Changed
- Remove lexical and realpath confinement guards from inbound file
mappings, inbound directory mappings, and post-upload command working
directories.
- Replace file-descriptor-pinned promotion with one `mv -f` command per
file mapping.
- Replace file-descriptor-pinned extraction with one `tar -xf` command
per directory mapping.
- Replace retained-descriptor decompression with `zstd -d -o`.
- Keep outbound source guards, atomic snapshot-and-download, and tarball
member validation.
- Update Daytona tests for the new command shapes and remove tests for
the removed rejections.
## Verification
- The author ran the Daytona package test suite: 232 tests passed and 6
tests skipped.
- The author ran the Daytona package typecheck successfully.
- Review the diff and confirm it changes only the three Daytona files
named in this description.
- Confirm the Storybook check may report `SKIPPED` as an expected
repository state.
## Risks
The inbound path now trusts the sandbox boundary for host-write
protection. A later change that gives sandbox code host-write or
Paperclip API authority could require new guards. Outbound source checks
and archive member validation remain in place. No Kubernetes or core
runtime file changes exist.
## Model Used
OpenAI GPT-5; exact model version and context window were not provided;
tool use and code review assistance.
## 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>
## Thinking Path
> - Paperclip is the open source app people use to manage AI agents for
work
> - Adapter utilities transfer files between the host and an agent
environment
> - A sandbox target already provides the security boundary for inbound
files
> - The generic fallback adds a temporary file and a rename that do not
add protection inside that boundary
> - This pull request writes a mode-constrained inbound file directly to
its target and applies the mode after the write
> - The benefit is a simpler transfer path while host targets keep the
strict pre-write mode rule
## Linked Issues or Issue Description
**What existing behavior does this improve?**
The inbound file-sync fallback for a mode-constrained file stages the
file under a temporary name, applies the mode, and renames the file into
place.
**Subsystem affected**
`packages/adapter-utils` and `packages/plugins`.
**Current behavior**
A sandbox target uses a temporary path before it receives the file. The
host then changes the mode and renames the file to the target path.
**Proposed behavior**
A sandbox target receives the file at its target path. The host applies
the mode after the write. A host target still applies the mode before
the first byte.
**Reason and benefit**
The sandbox boundary already protects the target. The direct write
removes an unnecessary staging path and rename.
**Breaking changes**
None. The directory path and outbound transfer path keep their existing
behavior.
## What Changed
- Write a mode-constrained single-file inbound transfer directly to the
sandbox target.
- Apply the mode after the direct write and keep the confinement check
before post-upload commands.
- Scope the protocol comment by transfer direction and preserve the
strict host-target rule.
- Keep directory inbound transfers and outbound transfers unchanged.
## Verification
- Run the targeted unit suite for the changed package.
- Verify the suite covers direct target writes, post-write mode
application, and confinement rejection.
- Run `tsc --noEmit` for both changed packages.
- Review the full GitHub Actions check set after the PR opens.
## Risks
- A sandbox provider that assumes a temporary inbound path could expose
a behavior mismatch.
- The confinement check remains before post-upload commands, which
limits escape risk.
- Host targets keep the pre-write mode rule, so host permission behavior
does not change.
## Model Used
OpenAI GPT-5. This model assisted with Git operations, PR preparation,
review coordination, and tool use. Context window size and reasoning
mode are not exposed by the runtime.
## Checklist
- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (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>
## Thinking Path
> - Paperclip is the open source app people use to manage AI agents for
work
> - Sandbox providers run agent work in isolated environments
> - The Daytona documents described a command wrapper that the provider
no longer uses
> - Those documents therefore described a control that the code does not
have
> - This pull request states the real sandbox boundary and the controls
for paths that cross it
> - The benefit is accurate security guidance for sandbox provider
authors and operators
## Linked Issues or Issue Description
**Issue type**
Outdated (no longer matches behavior).
**Where is the issue?**
`packages/plugins/sandbox-providers/SANDBOX-REQUIREMENTS.md` and
`packages/plugins/sandbox-providers/daytona/README.md`.
**What's wrong?**
The Daytona provider no longer uses the documented command wrapper,
package installation commands, or sudoers rule. The requirements
document also lacked a clear statement of the sandbox security boundary.
**Suggested fix**
State that the sandbox provides the boundary. Name outbound workspace
synchronization and the application programming interface bridge as the
paths that cross the boundary. State that a provider must not map a host
path into a sandbox synchronization path.
## What Changed
- Replace stale wrapper requirements with the actual sandbox security
boundary.
- State the controls that apply to outbound workspace synchronization
and the application programming interface bridge.
- State that this repository does not enforce the provider path-mapping
duty today.
- Remove obsolete Daytona package-install commands and the sudoers rule.
## Verification
- Confirm the difference contains the two documentation files and the
test file changed by the follow-up fix.
- Confirm that no unrelated source, configuration, or fixture file
appears in the difference.
- Run the repository continuous integration checks and confirm that
every required check passes.
- Run the repository review bot and confirm its final verdict.
## Risks
Low risk. This pull request changes two documents and closes a database
client in one integration test. It does not change product runtime
behavior or configuration.
## Model Used
OpenAI Codex, GPT-5, with tool use and code execution. The model
produced the documentation change and the pull request text.
## 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 the affected test locally; continuous integration
provides complete test verification.
- [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>
## Thinking Path
> - Paperclip is the open source app people use to manage AI agents for
work
> - Sandbox providers transfer files between the host and an agent
sandbox
> - The Daytona file-mapping upload path sends staged tar files without
compression
> - Large raw uploads use more transfer bandwidth and storage
> - This pull request adds transparent zstd-3 compression for eligible
inbound file mappings
> - The benefit is lower transfer size without changes for callers or
post-upload commands
## Linked Issues or Issue Description
**Subsystem affected**
The change affects `packages/plugins`, in the Daytona sandbox provider.
**Problem or motivation**
The Daytona file-mapping upload path sends eligible staged tar files
without compression. This increases transfer size and storage use.
**Proposed solution**
Compress eligible files on the host with zstd level 3. Upload the
compressed bytes to a confined remote scratch path. Decompress them
during the existing promote command, then promote the raw file. Use the
raw upload path when compression cannot run or does not reduce size
enough.
**Alternatives considered**
Keep the raw path for all uploads. This avoids compression work but does
not reduce transfer size. Add a new sandbox round trip for
decompression. This adds latency, so the change uses the existing
promote round trip.
**Roadmap alignment**
`ROADMAP.md` lists Daytona under cloud and sandbox agents. This focused
plugin change does not duplicate a planned core feature.
**Additional context**
The directory-mapping flow stays on the raw path. Callers and
post-upload commands keep the same behavior.
## What Changed
- Add transparent zstd-3 compression to `syncInFileMappings`.
- Upload compressed artifacts to confined remote scratch paths and
decompress them during promotion.
- Keep the raw upload fallback when zstd is absent, compression fails,
or the compressed result does not reduce size enough.
- Create the raw scratch file once with atomic exclusive no-clobber open
and write through the retained descriptor.
- Stage compressed host artifacts in private `0700` directories with
`0600` files.
- Remove temporary directories on success and failure.
- Add regression tests for compressed uploads, fallbacks, decompression
failures, and cleanup.
## Verification
- `pnpm --dir packages/plugins/sandbox-providers/daytona test` passes
with 20 tests.
- The compressed success path produces a byte-identical remote file.
- A target without zstd uses the raw upload path.
- A decompression failure does not promote a partial raw file.
- Temporary files and directories do not remain after success or
failure.
- The newest cleanup regression test fails when the production cleanup
fix is reverted and passes with the fix.
## Risks
- Compression adds host CPU work for eligible file mappings.
- The raw path remains available when compression is unavailable or
ineffective.
- Decompression runs during the existing promote command and can fail
before promotion.
- The change does not alter the directory-mapping flow or caller
interface.
## Model Used
OpenAI Codex, GPT-5, tool use and code execution enabled. The model
assisted with repository review and pull request preparation.
## 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>
Bumps [esbuild](https://github.com/evanw/esbuild) from 0.28.1 to 0.28.2.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/evanw/esbuild/releases">esbuild's
releases</a>.</em></p>
<blockquote>
<h2>v0.28.2</h2>
<ul>
<li>
<p>Fix tree shaking bug due to TypeScript import alias (<a
href="https://redirect.github.com/evanw/esbuild/issues/4507">#4507</a>)</p>
<p>This release fixes a bug that could cause esbuild to incorrectly
tree-shake imports that are used in a TypeScript type alias under
certain circumstances. Affected code uses a TypeScript-specific
<code>import</code> assignment and looks something like this:</p>
<pre lang="ts"><code>import Base from './dep.js';
import Alias = Base.SomeType;
</code></pre>
</li>
<li>
<p>Fix CSS minification bug involving <code>&</code> (<a
href="https://redirect.github.com/evanw/esbuild/issues/4497">#4497</a>)</p>
<p>This release fixes a bug where esbuild's CSS minifier incorrectly
removed a <code>&</code> when it was unsafe to do so. Here is an
example:</p>
<pre lang="css"><code>/* Original code */
.a .b {
& .b:not(& .c) {
color: red;
}
}
<p>/* Old output (with --minify) */<br />
.a .b{.b:not(& .c){color:red}}</p>
<p>/* New output (with --minify) */<br />
.a .b{& .b:not(& .c){color:red}}<br />
</code></pre></p>
<p>This should match <code><span class="a"><span
class="b"><span
class="b">yes</span></span></span></code>
but not <code><span class="a"><span
class="b">no</span></span></code>. The old
output incorrectly matched both.</p>
</li>
<li>
<p>Avoid overwriting input files without <code>--allow-overwrite</code>
(<a
href="https://redirect.github.com/evanw/esbuild/issues/4484">#4484</a>)</p>
<p>For example: <code>esbuild input.js --outfile=input.js</code> tells
esbuild to overwrite <code>input.js</code> with the output of running
esbuild on it. This was supposed to already be prevented by default, but
it accidentally regressed in version 0.17.0 and apparently didn't have
any test coverage. The error message was being printed but the input
file was still being overwritten. Oops.</p>
<p>This release puts the original behavior back. With this release,
esbuild should now actually avoid overwriting input files unless
<code>--allow-overwrite</code> is explicitly present. This is done by
not writing out any files when a build error is encountered.</p>
</li>
<li>
<p>Fix incorrect code generated when using top-level await (<a
href="https://redirect.github.com/evanw/esbuild/issues/4498">#4498</a>)</p>
<p>Previously esbuild could generate code containing a syntax error in
complex scenarios involving top-level await used in a dependency cycle.
The problem was a missing <code>async</code> on one or more module
wrapper closures. With this release, esbuild now uses a fixed-point
iteration algorithm to correctly annotate all dependencies in the cycle
as needing an <code>async</code> module wrapper.</p>
</li>
<li>
<p>Fix a minification bug with lowered logical assignment operators (<a
href="https://redirect.github.com/evanw/esbuild/issues/4508">#4508</a>)</p>
<p>This release fixes a bug that could cause esbuild to generate
incorrect code for logical assignment operators when lowering them to an
older target environment. Specifically the lowering process requires
duplicating the left-hand side, but esbuild incorrectly failed to count
the duplicate as a new usage when the left-hand side is an identifier.
That then caused the minifier to believe that the left-hand side was
only used once and could attempt to incorrectly inline an initializer
into the first usage. This bug has now been fixed:</p>
<pre lang="js"><code>// Original code
function foo() {
let x
bar(x ||= {})
</code></pre>
</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/evanw/esbuild/blob/main/CHANGELOG.md">esbuild's
changelog</a>.</em></p>
<blockquote>
<h2>0.28.2</h2>
<ul>
<li>
<p>Fix tree shaking bug due to TypeScript import alias (<a
href="https://redirect.github.com/evanw/esbuild/issues/4507">#4507</a>)</p>
<p>This release fixes a bug that could cause esbuild to incorrectly
tree-shake imports that are used in a TypeScript type alias under
certain circumstances. Affected code uses a TypeScript-specific
<code>import</code> assignment and looks something like this:</p>
<pre lang="ts"><code>import Base from './dep.js';
import Alias = Base.SomeType;
</code></pre>
</li>
<li>
<p>Fix CSS minification bug involving <code>&</code> (<a
href="https://redirect.github.com/evanw/esbuild/issues/4497">#4497</a>)</p>
<p>This release fixes a bug where esbuild's CSS minifier incorrectly
removed a <code>&</code> when it was unsafe to do so. Here is an
example:</p>
<pre lang="css"><code>/* Original code */
.a .b {
& .b:not(& .c) {
color: red;
}
}
<p>/* Old output (with --minify) */<br />
.a .b{.b:not(& .c){color:red}}</p>
<p>/* New output (with --minify) */<br />
.a .b{& .b:not(& .c){color:red}}<br />
</code></pre></p>
<p>This should match <code><span class="a"><span
class="b"><span
class="b">yes</span></span></span></code>
but not <code><span class="a"><span
class="b">no</span></span></code>. The old
output incorrectly matched both.</p>
</li>
<li>
<p>Avoid overwriting input files without <code>--allow-overwrite</code>
(<a
href="https://redirect.github.com/evanw/esbuild/issues/4484">#4484</a>)</p>
<p>For example: <code>esbuild input.js --outfile=input.js</code> tells
esbuild to overwrite <code>input.js</code> with the output of running
esbuild on it. This was supposed to already be prevented by default, but
it accidentally regressed in version 0.17.0 and apparently didn't have
any test coverage. The error message was being printed but the input
file was still being overwritten. Oops.</p>
<p>This release puts the original behavior back. With this release,
esbuild should now actually avoid overwriting input files unless
<code>--allow-overwrite</code> is explicitly present. This is done by
not writing out any files when a build error is encountered.</p>
</li>
<li>
<p>Fix incorrect code generated when using top-level await (<a
href="https://redirect.github.com/evanw/esbuild/issues/4498">#4498</a>)</p>
<p>Previously esbuild could generate code containing a syntax error in
complex scenarios involving top-level await used in a dependency cycle.
The problem was a missing <code>async</code> on one or more module
wrapper closures. With this release, esbuild now uses a fixed-point
iteration algorithm to correctly annotate all dependencies in the cycle
as needing an <code>async</code> module wrapper.</p>
</li>
<li>
<p>Fix a minification bug with lowered logical assignment operators (<a
href="https://redirect.github.com/evanw/esbuild/issues/4508">#4508</a>)</p>
<p>This release fixes a bug that could cause esbuild to generate
incorrect code for logical assignment operators when lowering them to an
older target environment. Specifically the lowering process requires
duplicating the left-hand side, but esbuild incorrectly failed to count
the duplicate as a new usage when the left-hand side is an identifier.
That then caused the minifier to believe that the left-hand side was
only used once and could attempt to incorrectly inline an initializer
into the first usage. This bug has now been fixed:</p>
<pre lang="js"><code>// Original code
function foo() {
let x
</code></pre>
</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="609683d892"><code>609683d</code></a>
publish 0.28.2 to npm</li>
<li><a
href="11b1fe48df"><code>11b1fe4</code></a>
add to release notes</li>
<li><a
href="ab50d91559"><code>ab50d91</code></a>
css: fix green/blue channel swap in oklch gamut mapping (<a
href="https://redirect.github.com/evanw/esbuild/issues/4488">#4488</a>)</li>
<li><a
href="04627b6cf9"><code>04627b6</code></a>
fix <a
href="https://redirect.github.com/evanw/esbuild/issues/4498">#4498</a>:
<code>async</code> TLA checks need a worklist</li>
<li><a
href="5c15177a30"><code>5c15177</code></a>
disable <code>gopls</code> in the <code>go</code> folder</li>
<li><a
href="fc2ee9babc"><code>fc2ee9b</code></a>
css: adjust parser to allow <code>--foo: {...}</code></li>
<li><a
href="209db54371"><code>209db54</code></a>
release notes for css nesting bugfix</li>
<li><a
href="c625d31bf0"><code>c625d31</code></a>
fix <a
href="https://redirect.github.com/evanw/esbuild/issues/4497">#4497</a>:
preserve nested ampersands during minification (<a
href="https://redirect.github.com/evanw/esbuild/issues/4500">#4500</a>)</li>
<li><a
href="34474e2785"><code>34474e2</code></a>
better isolation of current part in js parser</li>
<li><a
href="07f6e8c506"><code>07f6e8c</code></a>
fix <a
href="https://redirect.github.com/evanw/esbuild/issues/4507">#4507</a>:
<code>import</code> assignment tree-shaking bug</li>
<li>Additional commits viewable in <a
href="https://github.com/evanw/esbuild/compare/v0.28.1...v0.28.2">compare
view</a></li>
</ul>
</details>
<br />
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
## Thinking Path
> - Paperclip is the open source app people use to manage AI agents for
work
> - Sandbox providers carry agent work through controlled execution
channels
> - The Daytona callback bridge uses a bespoke line-framed protocol over
its duplex channel
> - The bespoke protocol adds framing work and does not use the Node
transport that already supports multiplexed streams
> - This pull request carries raw bytes across the channel, adds a Node
HTTP/2 bridge, and selects it for Daytona
> - The benefit is one authenticated, multiplexed callback session with
queue_v1 as the bounded fallback
## Linked Issues or Issue Description
**Subsystem affected**
The packages/plugins Daytona provider and the shared duplex execution
path.
**Problem or motivation**
The Daytona callback bridge uses a bespoke line-framed protocol over the
provider duplex channel. This adds protocol work and limits stream
handling.
**Proposed solution**
Carry raw bytes through the cross-layer channel. Add an authenticated
Node HTTP/2 host server and sandbox client gateway. Select http2_v1 for
Daytona and retain queue_v1 as the fallback.
**Alternatives considered**
Keep the current duplex_v1 protocol. This keeps the bespoke framing path
and does not provide one HTTP/2 session for callback streams.
**Roadmap alignment**
ROADMAP.md lists Daytona under cloud and sandbox agents. This change
improves the shipped Daytona provider path.
**Additional context**
The branch adds no dependency. Node 24 provides the http2 module. The
host token check and canonical path parser remain the single dispatch
path.
## What Changed
- Carry raw Uint8Array chunks through the adapter, plugin, worker,
runtime, and Daytona layers.
- Encode bytes as base64 only across the JSON-RPC hop, because JSON has
no binary type.
- Add the bounded host HTTP/2 server and the in-sandbox HTTP/2 client
gateway.
- Authenticate every stream with the per-run bridge token before route
work.
- Parse the path once and reuse the canonical result for route and
forwarding work.
- Select http2_v1 for Daytona and fall back once to queue_v1 when the
client preface is absent.
- Add transport, session, stream, and fallback telemetry.
- Mark HTTP/2 as the preferred transport and queue_v1 as the
soft-deprecated fallback.
## Verification
- `npx vitest run packages/adapter-utils/src` — 990 passed and 4
skipped.
- `npx vitest run
server/src/__tests__/plugin-worker-manager-duplex.test.ts` — 32 passed.
- `npx vitest run --config
packages/plugins/sandbox-providers/daytona/vitest.config.ts` — 220
passed and 6 skipped.
- `npx tsc --noEmit` in `packages/adapter-utils`, `packages/shared`,
`packages/plugins/sdk`, and `server` — clean.
- No `package.json` or `pnpm-lock.yaml` file changed.
- The live Daytona test skips when `DAYTONA_API_KEY` is absent.
- The root `npx tsc --noEmit` command has a pre-existing missing
`packages/adapters/droid-local` reference on this branch and on
`master`.
## Risks
- The transport change affects several duplex layers and could expose
byte-boundary errors.
- A missing HTTP/2 client preface falls back once to queue_v1 and
records `preface_missing`.
- The host token check and canonical path parser must remain on the
shared dispatch path.
- The live Daytona test needs `DAYTONA_API_KEY` and does not run in this
agent sandbox.
## Model Used
OpenAI GPT-5, tool-enabled coding agent with repository inspection,
GitHub CLI, and shell 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>
## Thinking Path
> - Paperclip is the open source app people use to manage AI agents for
work
> - Agent adapters use provider-specific login flows
> - Codex device login needs a live pseudo-terminal (PTY), while the
shared channel still uses Claude-specific names
> - The old streamed-exec path does not provide the prompt transport
that Codex needs
> - This pull request moves Codex device login to the shared login PTY
and removes the dead streamed-exec path
> - The benefit is one controlled login transport with fail-closed
capability checks and safer credential reads
## Linked Issues or Issue Description
**Problem or motivation**
Codex device login used a streamed-exec path that did not provide the
required prompt transport. The shared login channel also exposed
Claude-specific names outside Claude code.
**Expected behavior**
The host selects a fixed login command from trusted adapter data. Codex
login uses the provider login PTY. Providers without that capability
fail closed.
**Proposed solution**
Use a server-controlled session home, create and validate it as a fresh
0700 directory, read credentials from one validated descriptor, and
rename shared channel names to the neutral login PTY family.
**Alternatives considered**
Keep the shared login PTY as the single transport. Do not keep the
removed streamed-exec path because it cannot provide the required prompt
transport.
**Roadmap alignment**
This change supports the planned login transport work. It does not add a
separate roadmap item.
## What Changed
- Route Codex device login through the shared login PTY transport.
- Select the login command from a closed internal command key.
- Carry a server-controlled session home through the launch contract.
- Create and validate the session home as a fresh 0700 directory owned
by the login user.
- Read the credential file with descriptor-relative, no-follow path
walking and final descriptor checks.
- Gate the login route and run lease on the provider login PTY
capability.
- Rename shared channel names to the neutral login PTY family.
- Remove the streamed-exec transport value, selector field, driver
branch, and related tests.
- Hide Codex login in the user interface when the provider lacks the
login PTY capability.
## Verification
- Server unit suites pass: 89/89.
- Adapter-utils suites pass: 262/262.
- Codex-local suites pass: 326/326.
- Credential-read reader suite passes: 20/20.
- Daytona login PTY suite passes: 30/30.
- Device-login suites pass: 56/56.
- TypeScript checks pass for server, adapter-utils, and UI.
- GitHub Actions must pass after pull request creation.
- Greptile review must reach 5/5 with no open P2 findings,
recommendations, or follow-ups.
## Risks
- Providers without a login PTY capability lose Codex login support by
design.
- The credential read rejects invalid ownership, mode, type, path, and
size.
- The launch-time sandbox directory race remains outside the threat
model because the login runs inside the sandbox and a hostile sandbox
already controls its credential.
## Model Used
OpenAI Codex, GPT-5, tool use and code review assistance. The exact
context window and reasoning mode are not exposed by the runtime.
## Checklist
- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (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>
## Thinking Path
> - Paperclip is the open source app people use to manage AI agents for
work
> - Paperclip runs agent work through adapters and sandbox providers
> - The Daytona duplex path sends host input through a provider
pseudo-terminal WebSocket
> - Large messages exceed the provider limit, and a transport close can
look like a process exit
> - This pull request chunks UTF-8 input and carries transport-close
state through the duplex path
> - The benefit is reliable large input and accurate loss reporting
## Linked Issues or Issue Description
**What happened?**
The Daytona duplex path sent a full input payload as one WebSocket
message. A payload above the provider limit closed the channel. The wait
path also mapped a non-numeric exit result to a process exit without
exit data.
**Expected behavior**
The provider must receive large input as ordered UTF-8 chunks. A
transport close without exit data must record `transport_closed`, while
a numeric exit must record `provider_exit`.
**Steps to reproduce**
1. Start a Daytona duplex session.
2. Send an input payload larger than 65536 bytes.
3. Observe that one message closes the provider channel.
4. End a session without a numeric exit code.
5. Observe that the loss reason reports a process exit.
**Paperclip version or commit**
Commit `1761e79ec9097c65d94f90a8ba20416f8ab718a6`.
**Deployment mode**
Built from source with the Daytona sandbox provider.
## What Changed
- Add a shared UTF-8 byte chunker with a 32768-byte cap.
- Route both Daytona pseudo-terminal write paths through the chunker.
- Preserve multi-byte UTF-8 sequences across read-side chunks.
- Carry an explicit `transportClosed` state through the worker and host
wait paths.
- Record `transport_closed` for a reason-less transport close and
`provider_exit` for a numeric exit.
- Keep orderly completion suppression for both exit paths.
## Verification
- The Daytona plugin suite passes 194 tests.
- The adapter-utils broker, codec, and telemetry suites pass 73 tests.
- The plugin SDK duplex and worker RPC host suites pass 37 tests.
- The server plugin worker manager duplex suite passes 78 tests.
- The execution target sandbox and ACPX execute suites pass 257 tests.
- TypeScript checks pass for adapter-utils, plugin SDK, server, and the
standalone Daytona plugin.
## Risks
The chunk size adds a loop for large input payloads. The 32768-byte cap
stays below the provider limit. The optional loss field preserves
compatibility for other providers.
## Model Used
OpenAI Codex, GPT-5, extended reasoning, tool use, and code execution.
The runtime does not expose a separate 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>
## Thinking Path
> - Paperclip is the open source app people use to manage AI agents for
work.
> - Sandbox adapters provide controlled execution for untrusted provider
environments.
> - The sandbox channel needs one persistent duplex transport with
strict host control.
> - The transport must remain off unless the instance setting and
provider capability both allow it.
> - The host must detect loss, bound resource use, and expose only safe
telemetry.
> - This pull request adds the broker, gated selection, kill-switch
wiring, fixed observability, and real-process proof.
> - The benefit is safer sandbox execution with bounded failure behavior
and inspectable transport results.
## Linked Issues or Issue Description
No public issue exists for this change. The related pull requests are
#11738 and #11750.
**Problem or motivation**
The sandbox duplex channel needs a host-controlled broker, strict
transport gates, bounded provider input, and safe loss telemetry.
Without these controls, a provider can cause replay, resource growth,
unsafe endpoint selection, or data exposure through telemetry.
**Proposed solution**
Add a host broker with nested time limits, request limits, one-shot
loss, and per-id deduplication. Select duplex transport only when the
instance setting and provider capability both equal true. Assign the
endpoint and nonce on the host. Reject invalid readiness data and use
the file bridge on failure. Add fixed redacted telemetry and a
real-process end-to-end test harness.
**Alternatives considered**
Keep the file bridge as the only transport. This avoids new channel
behavior but does not provide persistent duplex operation for supported
sandbox providers.
**Roadmap alignment**
This change supports the Cloud / Sandbox agents section in ROADMAP.md.
## What Changed
- Add the duplex bridge broker with bounded forward, response, and
gateway wait budgets.
- Bound concurrent requests, lifetime requests, and request-id bytes
before retention or forwarding.
- Select duplex transport only when both required gates are true.
- Assign the loopback port and nonce on the host and enforce a
liveness-only READY frame.
- Fall back to the file bridge after invalid readiness, contamination,
bind failure, or timeout.
- Carry the kill switch through the server, acpx engine, and six local
adapters.
- Add fixed, redacted duplex telemetry with a provider allowlist.
- Add a real-process end-to-end harness for readiness, round trips,
loss, and teardown.
- Add regression coverage for limits, loss, UTF-8 splits, concurrency,
and telemetry dimensions.
## Verification
- Adapter-utils, server, and Daytona typechecks pass locally.
- Adapter-utils tests pass, including the codec, broker,
execution-target sandbox, and real-process harness.
- Server kill-switch tests pass.
- Live Daytona tests pass with the required provider key and skip
without that key.
- The root pnpm-lock.yaml file has no diff.
- The branch contains ten commits after origin/master.
## Risks
- Duplex transport remains disabled unless both gates equal true.
- A provider remains an untrusted boundary and needs least-privilege
credentials and quotas.
- The server telemetry recorder stays deferred; the default recorder
does nothing.
- A provider that pre-binds the host port causes a fail-closed fallback
to the file bridge.
- The change adds no database migration and changes no root lockfile.
## Model Used
OpenAI GPT-5, exact model family GPT-5, large context window, reasoning,
and tool use. The model assisted with Git handoff validation and PR
preparation. The implementation commits came from the engineering
worktree.
## 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/... or 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
- [x] I searched the GitHub PR list for similar PRs and confirmed this
is not a duplicate
---------
Co-authored-by: Paperclip <noreply@paperclip.ing>
## Thinking Path
> - Paperclip is the open source app people use to manage AI agents for
work.
> - Paperclip runs across the CLI, server, adapters, plugins, CI, and
container images.
> - These surfaces declared different Node.js versions from 20 through
24.
> - A newer `@types/node` major can expose APIs that the supported
runtime does not provide.
> - Node.js 20 is no longer a suitable project baseline, and Node.js 24
is the current LTS line.
> - This pull request sets Node.js 24.11.0 as one repository-wide
baseline, adds a drift check, and gives users actionable startup
guidance when their runtime is too old.
> - The benefit is one clear runtime contract for development, release,
installation, and published packages.
## Linked Issues or Issue Description
Refs #2734
Refs #11727
Refs #739
## What Changed
- Require Node.js 24.11.0 or newer in all 42 package manifests and
runtime checks.
- Use Node.js 24 in GitHub Actions, Docker images, smoke images, sandbox
setup, portable installs, and esbuild targets.
- Align every direct `@types/node` declaration on `^24.0.0`.
- Prevent Dependabot from opening major `@types/node` upgrades without a
matching runtime decision.
- Add `.nvmrc` and a CI policy check for Node version drift.
- Update ACP version gates, tests, and user documentation for the new
minimum.
- Print a non-blocking warning on CLI and server startup when Node is
unsupported, with remediation through a version manager or the
documented downloaded `install.sh` workflow.
- Deduplicate that warning when `paperclipai run` boots the CLI and
server in the same process.
## Verification
- `node scripts/check-node-version-policy.mjs`
- `node --check scripts/check-node-version-policy.mjs`
- `node --check cli/esbuild.config.mjs`
- `node --check scripts/generate-npm-package-json.mjs`
- `bash -n scripts/install.sh scripts/test-install-sh-docker.sh
scripts/e2e-install-lifecycle.sh`
- Parsed all 42 package manifests and confirmed `engines.node` is
`>=24.11.0`.
- `git diff --check`
- `vitest run
packages/adapter-utils/src/sandbox-install-command.test.ts` passed with
3 tests.
- `vitest run cli/src/node-version.test.ts` passed with 4 tests.
- Directly exercised the shared warning helper for unsupported-version
messaging and same-process deduplication.
- The focused exe.dev suite could not resolve the locally unbuilt plugin
SDK from this isolated worktree. A full offline workspace install was
also blocked because the package-manager signature verifier requires
registry access. The full suite was not run locally; draft CI performs a
clean install and evaluates the wider impact.
## Risks
- This is a breaking runtime change for users, plugins, and deployments
that still use Node.js 20 or 22.
- Published workspace packages will now produce an engine warning or
failure in strict package managers on older Node.js releases.
- Node.js 24 can reveal dependency, native module, Playwright, or agent
CLI compatibility issues in CI.
- The bootstrap installer now installs Node.js 24 when the current
runtime is older than 24.11.0.
- The portable sandbox fallback is pinned to Node.js 24.11.0 and depends
on that upstream tarball remaining available.
- Unsupported runtimes continue booting after a warning, so a later
incompatibility can still fail at its point of use.
- The CLI and server share the warning policy through the published
`@paperclipai/shared` package; packaging checks must keep that subpath
export available.
- This PR does not commit `pnpm-lock.yaml` because repository policy
assigns lockfile generation to CI.
> For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and
discuss it in `#dev` before opening the PR. Feature PRs that overlap
with planned core work may need to be redirected — check the roadmap
first. See `CONTRIBUTING.md`.
## Model Used
- OpenAI Codex based on GPT-5. The exact deployment ID and context
window are not exposed in this session. Reasoning, repository tools,
shell execution, and GitHub tools were enabled.
## 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>
## Thinking Path
> - Paperclip is an open source app that manages AI agents for work
> - Paperclip runs agents in local and remote sandbox environments
> - A sandbox needs a bounded channel for commands and asynchronous
input
> - Daytona needs a real pseudo-terminal transport for this channel
> - The sandbox gateway also needs a mode that handles channel loss
safely
> - This pull request adds the Daytona transport and gateway mode behind
a default-off kill switch
> - The benefit is a tested foundation for later transport selection
## Linked Issues or Issue Description
**Subsystem affected**
Cross-cutting (multiple of the above): sandbox providers, plugin SDK,
server settings, and shared types.
**Problem or motivation**
The merged sandbox protocol has no runtime transport for Daytona. The
generated sandbox gateway also has no duplex mode. A later
transport-selection change needs both parts and a safe per-run gate.
**Proposed solution**
Add a Daytona `duplexCommandStream` transport over a raw
pseudo-terminal. Add a generated gateway mode named `duplex_v1`. Add the
`enableSandboxDuplexBridge` setting with a default value of `false`.
Keep transport selection disabled until a later pull request.
**Alternatives considered**
Keep the protocol unused until the transport-selection change. This
would delay provider tests and leave the gateway path without direct
coverage.
**Roadmap alignment**
This change supports the completed Roadmap item for cloud and sandbox
agents. It extends the merged sandbox channel foundation in pull request
#11738.
**Additional context**
The Daytona provider remains an untrusted boundary. Deployments must use
least-privilege provider credentials and provider-side quota controls.
Operators must name an owner for duplex telemetry retention before
rollout.
## What Changed
- Add the Daytona `duplexCommandStream` capability over a raw
pseudo-terminal.
- Add a launch wrapper that disables echo and newline translation for
NDJSON frames.
- Close channels on lease release, destroy, resume of a stopped worker,
and worker shutdown.
- Declare the capability in the Daytona manifest and set
`PLUGIN_VERSION` to `0.1.5`.
- Add the worker-to-host notification sink at `ctx.duplexChannel.data`
and `ctx.duplexChannel.exit`.
- Add the generated sandbox gateway mode
`PAPERCLIP_API_BRIDGE_MODE=duplex_v1`.
- Add channel-loss results of `409 outcome_indeterminate` and `503
bridge_unavailable`.
- Add the per-run setting `enableSandboxDuplexBridge`, with a default
value of `false`.
- Add unit tests, generated-source codec tests, lifecycle tests, and a
credential-gated live Daytona test.
## Verification
- Daytona suite: 185 tests pass.
- Adapter utilities: 754 tests pass and 4 tests skip.
- Plugin SDK: 62 tests pass.
- Shared package: 28 tests pass.
- Server duplex tests pass.
- Shared, plugin SDK, server, and Daytona TypeScript checks pass.
- The live Daytona test passes 3 cases when `DAYTONA_API_KEY` is set.
- The live Daytona test skips 3 cases without `DAYTONA_API_KEY`.
- CI must run the full workspace typecheck, test, and build gates after
PR creation.
## Risks
- The Daytona control plane and pseudo-terminal remain untrusted
boundaries.
- The duplex gateway changes behavior only when the mode and per-run
setting enable it.
- A lost channel fails requests without replay, so callers must handle
indeterminate outcomes.
- The transport-selection change must require both `duplexCommandStream
=== true` and `enableSandboxDuplexBridge === true`.
- The provider credential and quota limits need operator control before
rollout.
## Model Used
OpenAI Codex, GPT-5, tool use and code execution.
## Checklist
- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` /
`Closes: #` / `Refs: #` OR (b) described the issue in-PR following the
relevant issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge
---------
Co-authored-by: Paperclip <noreply@paperclip.ing>
## Thinking Path
> - Paperclip provides a control plane for companies that run AI agents.
> - Sandboxed agents need a safe execution path for persistent command
streams.
> - The existing callback transport does not provide a bounded, generic
duplex route.
> - The host must control capability access, route identity, protocol
limits, and close behavior.
> - This pull request adds an opt-in duplex command-stream foundation
across the sandbox layers.
> - The feature stays inert because no current provider declares the
capability.
## Linked Issues or Issue Description
**Subsystem affected**
Cross-cutting (multiple of the above)
**Problem or motivation**
Sandbox command execution needs a persistent host-to-sandbox stream. The
current callback bridge uses a file transport and does not provide this
generic route.
**Proposed solution**
Add a fail-closed provider capability, generic worker protocol messages,
a host-owned bounded route, cross-layer service mediation, and a
versioned newline-delimited frame codec.
**Alternatives considered**
Keep the file transport and add feature-specific commands. This does not
provide one reusable duplex contract or host-owned route bounds.
**Roadmap alignment**
This work supports the completed Cloud / Sandbox agents roadmap area and
the safe autonomy goal in the product definition.
**Additional context**
The change passed a two-stage security review. The final code review
verdict was approve after fixes for active-stream bounds and
service-layer capability mediation.
## What Changed
- Add the opt-in `duplexCommandStream` provider capability with
fail-closed narrowing.
- Add duplex open, write, stop, and close requests and data and exit
notifications to the plugin worker protocol.
- Add a host-owned route with bounds for chunk size, cumulative bytes,
lifetime, protocol errors, pending requests, and pre-bind buffering.
- Add close acknowledgement handling with worker retirement when the
close remains unconfirmed.
- Wire `openDuplexChannel` through the execution target, runtime
service, and plugin worker.
- Add a versioned frame codec with shared wire-compatibility vectors and
split UTF-8 handling.
## Verification
- `server/src/__tests__/plugin-worker-manager-duplex.test.ts` passes 18
tests.
- `server/src/__tests__/environment-execution-target-duplex.test.ts`
passes 11 tests.
- `packages/adapter-utils/src/duplex-frame-codec.test.ts` passes 38
tests.
- `server/src/__tests__/sandbox-capability-contract.test.ts` passes 15
tests.
- Setup-token pseudo-terminal regression tests pass 47 tests.
- Server TypeScript check passes.
- Continuous integration will run the full required test, typecheck,
build, and policy checks.
## Risks
- Providers that opt into the capability must implement the complete
worker protocol.
- Route limit defaults can close a stream when a workload exceeds the
configured bounds.
- The capability remains disabled for current providers, so current
production behavior does not change.
## Model Used
OpenAI GPT-5 (`gpt-5`), with tool use and code execution. The model
reviewed and prepared this pull request from the supplied implementation
and verification record.
## 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>
## Thinking Path
> - Paperclip runs AI agents through local and remote execution
adapters.
> - Sandbox providers move workspace and asset files before and after
agent runs.
> - Serial file transfers delay startup and teardown when several
operations do not depend on each other.
> - Providers need an opt-in contract so existing providers keep their
serial behavior.
> - This pull request adds a bounded scheduler and routes inbound and
outbound sync operations through it.
> - The benefit is shorter sandbox setup and teardown with stable
errors, clear telemetry, and a safe opt-in path.
## Linked Issues or Issue Description
**Subsystem affected**
Cross-cutting (multiple of the above): packages/shared,
packages/adapter-utils, packages/plugins, and server.
**Problem or motivation**
Sandbox sync processes the workspace, assets, and referenced projects in
series. This adds avoidable wait time to agent startup and teardown.
**Proposed solution**
Add a fail-closed provider capability named concurrentSyncOperations.
Use a bounded scheduler with a limit of four operations. Preserve
operation order for error reporting. Keep non-opted-in providers on the
serial path.
**Alternatives considered**
Increase the serial transfer speed or add provider-specific schedulers.
Those options do not provide one shared contract or stable behavior
across providers.
**Roadmap alignment**
ROADMAP.md lists cloud and sandbox agents as a product area. This change
improves sandbox execution without changing the control-plane contract.
**Additional context**
The Daytona provider opts in. Board trials on this commit showed overlap
for inbound sync and outbound restore, with no referenced-project
staging failures.
## What Changed
- Add the concurrentSyncOperations sandbox capability and fail-closed
parsing.
- Add a bounded settle-all scheduler with stable input-order errors.
- Parallelize inbound workspace, asset, and referenced-project sync
operations when the provider opts in.
- Parallelize outbound workspace and asset restore operations when the
provider opts in.
- Surface referenced-project failure text in run logs and server
telemetry.
- Add Daytona sync spans and the capability declaration.
- Preserve in-flight upload scratch tarballs during workspace wipe.
- Add unit and regression tests for the scheduler, coordinators,
provider behavior, telemetry, and wipe race.
## Verification
- Run the adapter-utils and server type checks.
- Run the targeted adapter-utils, server, and Daytona test suites.
- Run the full automated sweep.
- Review six cold Daytona trials, with three serial and three parallel
runs.
- Confirm that parallel trials show inbound overlap and outbound restore
overlap.
- Confirm that providers without the capability keep serial behavior.
## Risks
- Providers must opt in only when their file operations can run safely
at the same time.
- A provider that declares the capability incorrectly can expose
transfer races.
- The scheduler keeps a limit of four to bound resource use.
- Providers without the capability keep the prior serial behavior.
## Model Used
OpenAI GPT-5 in the Codex runtime. The model used tool calls, code
inspection, and GitHub workflow support. The model did not author the
implementation commits.
## 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>
## Thinking Path
> - Paperclip is the open source app people use to manage AI agents for
work
> - Sandbox agents need a safe login path for each supported adapter
> - Codex device login and Claude setup-token login used separate
session stores and route logic
> - Separate stores made session lookup, expiry, and login capability
checks harder to keep consistent
> - This pull request unifies both flows on one session table and one
capability contract
> - The benefit is one company-scoped login model with public session
identifiers and shared lifecycle rules
## Linked Issues or Issue Description
**Subsystem affected**
Cross-cutting (multiple of the above)
**Problem or motivation**
Codex and Claude sandbox login used separate session stores and
different route paths. This split increased the risk of inconsistent
company scoping, session lookup, and cleanup.
**Proposed solution**
Use `adapter_auth_sessions` for both login flows. Use public session
identifiers for API access. Select login behavior from projected adapter
capability data. Share the route spine, lease arguments, runner
lifecycle, and reaper rules.
**Alternatives considered**
Keep two session tables and add matching fixes to both routes. This
keeps duplicate logic and does not provide one capability contract, so
this pull request uses shared infrastructure.
**Roadmap alignment**
This change supports the shipped Cloud / Sandbox agents milestone in
`ROADMAP.md`.
## What Changed
- Unify Codex device login and Claude setup-token login on
`adapter_auth_sessions`.
- Return and look up sessions with company-scoped public session
identifiers.
- Enforce one active session for each company, owner, and adapter.
- Share the login route spine, sandbox lease arguments, runner
lifecycle, and missing-auth check.
- Add a standalone setup-token reaper with adapter-specific row
selection.
- Add optional login capability projection for adapters and drive route
and UI selection from that data.
- Rename the provider flag to `supportsLoginPty` and validate its
deprecated alias.
- Remove the old Claude setup-token session table and add the required
migrations.
## Verification
- Server typecheck passed with `tsc`.
- Database typecheck passed.
- UI typecheck passed with `tsc -b`.
- Codex login service and route suites passed.
- Setup-token session, route, and reaper suites passed.
- Adapter session schema, plugin validator, capability projection, UI
render, and Daytona suites passed.
- GitHub Actions must confirm the complete CI gate after pull request
creation.
## Risks
- The migrations remove short-lived in-flight login rows during
deployment. A login that spans the migration can continue until its
provider lease expires.
- The Codex credential store remains company-scoped. A cross-owner
credential race remains a documented, board-accepted risk.
- API clients that use internal session row identifiers no longer work.
The API accepts only public session identifiers.
## Model Used
Codex, GPT-5, exact runtime model ID not exposed in this handoff, large
context window, reasoning, and repository tool use. The implementing
engineer produced the code with AI assistance.
## 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>
## Thinking Path
> - Paperclip is the open source app people use to manage AI agents for
work
> - The Claude local adapter supports subscription login through a
sandbox
> - The new-agent page must show login before the user creates an agent
> - Test results must not expose raw sandbox diagnostics or secret
values
> - This pull request adds the login UI to both Test lanes and closes
the diagnostic boundary
> - The branch also adds durable cleanup recovery for failed sandbox
teardown
> - Reusable sandboxes must retain both their recorded teardown
configuration and a valid lifecycle path until destruction succeeds
> - The benefit is a usable login flow with fixed public checks,
redacted server logs, and recoverable sandbox cleanup
## Linked Issues or Issue Description
Related public work:
[#9488](https://github.com/paperclipai/paperclip/pull/9488) adds
first-class recognition for `CLAUDE_CODE_OAUTH_TOKEN` in headless and
remote runs. Related public issue:
[#2681](https://github.com/paperclipai/paperclip/issues/2681) requests
Claude Code subscription support. This pull request adds the login
transport and new-agent UI flow that those changes do not provide.
**Subsystem affected:** Claude local adapter, server login probes,
sandbox provider setup, cleanup recovery, and the new-agent UI.
**Problem or motivation:** The Test lanes did not show the sandbox login
panel in all supported cases. Test results also exposed raw probe
diagnostics, and JSON escapes could end secret redaction early.
**Proposed solution:** Surface the login capability through the bundled
provider manifest. Prepare the same probe runtime in the ACP lane. Send
diagnostics only to redacted server logs. Keep Test checks on fixed
public messages. Normalize login URL hints to allowlisted HTTPS Claude
and Anthropic hosts. Consume JSON escapes during redaction. Preserve
failed sandbox cleanup state across retries and restarts, and prevent
deletion from severing the lifecycle context of a live reusable sandbox.
**Alternatives considered:** Keep raw diagnostics in Test checks or
trust login URL text from the sandbox. Both choices increase information
exposure. Keep separate probe behavior in the ACP lane. That choice
would leave the two Test lanes inconsistent.
## What Changed
- Surface the sandbox login panel on both Test lanes.
- Reconcile the bundled Daytona plugin manifest so
`supportsSetupTokenLogin` reaches the UI capability gate.
- Prepare the ACP Test lane with the same probe runtime as the CLI Test
lane.
- Add the `claude_acp_login_probe_unavailable` warning when the ACP
probe cannot run.
- Send raw sandbox diagnostics only to redacted server logs.
- Keep Test checks on fixed public messages in the ACP, managed-config,
and CLI paths.
- Normalize login URL hints to allowlisted HTTPS Claude and Anthropic
hosts.
- Redact JSON and escaped-JSON secret values, including escaped quotes
and backslashes.
- Preserve orphan cleanup records across provider failures, restarts,
and unavailable plugins.
- Atomically block environment deletion while a live reusable sandbox
lease still depends on it.
- Verify pending cleanup destroys plugin sandboxes with the provider
configuration recorded on the lease, even after the current environment
configuration changes.
## Verification
- Head under review: `506b7fa2d83c36bfa5fd722ee9d95b0c7431c241`.
- Focused environment route/service/runtime coverage passes: 196 tests
across 3 files.
- `pnpm -r typecheck` passes.
- `pnpm build` passes.
- The full Vitest run completed with 4,754 passing and 28 failing tests.
All 23 source-test failures reproduce unchanged on parent head
`58cfe61a33191ce03d965d65085d26064b4888ba`; the other 5 are duplicate
executions from stale `server/dist` output. The failures are unrelated
macOS path/listener and scheduler-fixture failures, so there is no new
bad commit for bisect to localize.
- All required CI checks pass for the current head, including build,
typecheck/release registry, all server and workspace shards, serialized
server suites, canary, and e2e.
- A fresh Greptile review for `506b7fa2d83c36bfa5fd722ee9d95b0c7431c241`
reports 5/5, “safe to merge,” with no blocking failure remaining.
## Risks
- A probe or redaction change could hide useful server diagnostics.
- An allowlist change could reject a valid Claude login URL.
- Cleanup recovery changes could affect provider teardown ordering.
- An environment with a live reusable sandbox can no longer be deleted
until the owning issue or execution workspace completes teardown.
- The implementation keeps public Test messages fixed and sends detail
to redacted server logs.
## Model Used
OpenAI GPT-5 via Codex — exact model ID: GPT-5; tool use and code
execution enabled; extended reasoning enabled. The implementation author
used AI-assisted development.
## 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 documented the result
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation or confirmed no separate
documentation change is needed
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge
---------
Co-authored-by: Paperclip <noreply@paperclip.ing>
## Thinking Path
> - Paperclip is the open source app people use to manage AI agents for
work
> - Sandboxed agents use provider capabilities to select safe execution
paths
> - Session output still depends on three operator flags that duplicate
capability data
> - Duplicate flags can drift from the verified sandbox capability
snapshot
> - This pull request makes the capability snapshot the only streaming
decision and removes the obsolete flags
> - The benefit is default streaming with a poll fallback when a
capability or stream fails
## Linked Issues or Issue Description
**What existing behavior does this improve?**
ACP sandbox session-output streaming and sandbox execution
configuration.
**Subsystem affected**
Cross-cutting (multiple of the above): server/, packages/shared/,
packages/adapter-utils/, and packages/plugins/.
**Current behavior**
Session-output streaming requires operator flags in the server and
Daytona plugin configuration. Saved configurations can retain a removed
key.
**Proposed behavior**
The verified capability snapshot selects streaming. The Daytona plugin
uses persistent sessions by default, keeps bypass commands one-shot, and
falls back from the log stream to polling. Removed configuration keys
become inert.
**Reason and benefit**
One capability source prevents configuration drift. The fallback keeps
output available when capability resolution or log streaming fails.
**Breaking changes**
The three operator flags no longer control session-output streaming.
Existing saved keys load but have no effect.
## What Changed
- Remove `useSessions` and `useLogStream` from the Daytona plugin
configuration and manifest.
- Remove `streamAgentSessionOutput` from server configuration, shared
types, and execution-target plumbing.
- Select streaming from `persistentProcessSessions` and
`independentControlCommands`.
- Keep poll fallback on capability resolution failure and stream
failure.
- Strip removed keys from strict fake-sandbox and catchall plugin
configuration.
- Update the sandbox capability documentation and focused tests.
## Verification
- `tsc --noEmit` passed in `packages/shared`, `packages/adapter-utils`,
`server`, and the Daytona plugin.
- Daytona `plugin.test.ts` passed 139 tests.
- Server capability, configuration, route, and runtime suites passed 160
tests.
- `packages/adapter-utils` `execution-target-sandbox.test.ts` passed 44
tests.
- The capability matrix covers stream, poll, and resolution-failure
paths.
- Removed-key tests cover strict fake-sandbox and catchall plugin
schemas.
## Risks
- A capability snapshot that lacks either required session capability
uses polling.
- A log stream failure uses polling and can increase request count.
- Existing removed configuration keys no longer change behavior.
- The isolated-worktree Daytona Vitest run has a pre-existing missing
`packages/adapters/droid-local` reference. CI and standard checkouts use
the committed configuration.
## Model Used
OpenAI Codex, GPT-5, tool use and code review assistance. The exact
runtime context window is managed by the Codex platform.
## 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>
## Thinking Path
> - Paperclip is the open source app people use to manage AI agents for
work
> - Sandbox provider plugins run agent work in remote execution
environments
> - The Daytona sandbox liveness read can stay pending when the
connection stops responding
> - A pending read blocks the plugin until a broad host-to-worker limit
expires
> - This pull request adds bounded deadlines to Daytona liveness calls
and clears stale handles
> - The benefit is a fast and clear error when a Daytona connection
stops responding
## Linked Issues or Issue Description
Refs #11341
**What happened?**
The Daytona sandbox liveness read had no per-call timeout. A silent
connection failure left the read pending until the broad host-to-worker
RPC limit expired.
**Expected behavior**
The plugin should stop a liveness call within a defined limit and report
a clear timeout error.
**Steps to reproduce**
1. Create a Daytona sandbox handle.
2. Make the cached handle freshness read never resolve.
3. Run the next sandbox operation.
4. Observe that the operation waits for the outer RPC limit without a
liveness timeout.
**Paperclip version or commit**
`master` before this change.
**Deployment mode**
Any deployment mode that uses the Daytona sandbox provider.
## What Changed
- Add `withLivenessTimeout` with timer cleanup and
`SandboxLivenessTimeoutError`.
- Bound `refreshData` with configurable `livenessTimeoutMs`, which
defaults to 30000 milliseconds.
- Bound sandbox start and recovery calls with the SDK timeout plus a
5000 millisecond margin.
- Reject `livenessTimeoutMs` values above 86400000 milliseconds and
document the setting.
- Evict a cached handle after a failed freshness refresh so the next
operation fetches a new handle.
- Add a test for a never-resolving freshness refresh and the
cached-handle eviction.
## Verification
- Run the Daytona plugin test suite with its package Vitest
configuration.
- Confirm that 150 of 150 tests pass.
- Confirm that the new test reports a bounded timeout and a fresh handle
on the next operation.
- Confirm that GitHub Actions reports green status checks after the pull
request starts.
## Risks
This change adds an early timeout only to Daytona liveness calls. A
value of 0 or less disables the extra bound. The default leaves normal
SDK calls within their expected time limit. The main risk is a timeout
value that is too short for a slow but healthy connection.
## Model Used
OpenAI Codex, GPT-5. The model used tool calls and code execution. The
model supplied the PR handoff and did not author the code in this pull
request.
## 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>
## Thinking Path
> - Paperclip is the open source app people use to manage AI agents for
work
> - Paperclip provides CLI commands and guidance for operators and
agents
> - The `pnpm paperclipai` script can pass argument values through a
shell
> - Shell re-parsing can execute command substitutions inside quoted
values
> - This pull request routes guidance through inert-argv `npx
paperclipai` commands and adds regression coverage
> - The benefit is safer operator guidance across documentation and
runtime hints
## Linked Issues or Issue Description
This pull request fixes a command-injection-class defect in Paperclip
CLI guidance.
**What happened?**
The `pnpm paperclipai <sub> --flag "$VALUE"` form can re-parse argument
values through a shell. A command substitution inside a quoted value can
execute on the host.
**Expected behavior**
Paperclip guidance must pass CLI values as inert argument values.
Host-derived values must not appear in copyable commands.
**Steps to reproduce**
1. Run a Paperclip guidance command that uses the `pnpm paperclipai`
script.
2. Provide a quoted value that contains a command substitution.
3. Observe that the shell can evaluate the substitution before the CLI
starts.
4. Compare the result with the `npx paperclipai` form.
**Paperclip version or commit**
`5670984b75d109950c968542a0111ebb6967f4da`
**Deployment mode**
All deployment modes that show or use the affected CLI guidance.
**Installation method**
Built from source and installed CLI guidance.
**Agent adapter(s) involved**
Not adapter-specific (core bug).
**Database mode**
Not database-related.
**Access context**
Both.
**Additional context**
The earlier merged PR
[#11343](https://github.com/paperclipai/paperclip/pull/11343) used the
unsafe `pnpm exec paperclipai` form. This fresh PR replaces that
guidance with the safe `npx paperclipai` form.
## What Changed
- Standardize documentation and runtime hints on `npx paperclipai`.
- Remove the broken `pnpm exec paperclipai` guidance.
- Use a static `<host>` placeholder in private-hostname guidance.
- Add regression tests for unsafe forms, continued lines, static hosts,
and offline guidance.
## Verification
- `git diff --check
origin/master...origin/fix/paperclipai-cli-npx-safe-invocation` passes.
- The branch adds `server/src/__tests__/cli-invocation-safety.test.ts`
and updates private-hostname tests.
- CI must run the new tests, typecheck, lint, and build checks.
- Local Vitest execution was not available because this worktree has no
installed Vitest binary.
## Risks
- The change affects operator and agent documentation text.
- The runtime hints now show `<host>` instead of a request-derived host
value.
- No database schema or migration changes exist.
- CI will detect any missed unsafe invocation or type error.
## Model Used
OpenAI GPT-5, exact model ID `gpt-5`, with tool use and code-review
assistance. The model used repository inspection, Git operations, and PR
preparation.
## 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] CI ran the test suites and they pass; local test execution was
unavailable in this worktree
- [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 addressed all Greptile and reviewer comments before requesting
merge
---------
Co-authored-by: Paperclip <noreply@paperclip.ing>
Bumps [@codemirror/view](https://github.com/codemirror/view) from 6.43.1
to 6.43.8.
<details>
<summary>Commits</summary>
<ul>
<li>See full diff in <a
href="https://github.com/codemirror/view/commits">compare view</a></li>
</ul>
</details>
<br />
[](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)
Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.
[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)
---
<details>
<summary>Dependabot commands and options</summary>
<br />
You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)
</details>
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
## Thinking Path
> - Paperclip is the open source app people use to manage AI agents for
work
> - Claude agents that run in a remote sandbox need a safe in-product
login path
> - The existing host login route cannot open a pseudo-terminal inside
that sandbox
> - The login flow must protect the browser code, the login URL, and the
OAuth token at every step
> - This pull request adds the parser, the runner, a Daytona
pseudo-terminal transport, and a guarded, owner-bound session route
behind an injectable transport
> - The route stays inert in the default build and fails closed until a
sandbox provider binds the live transport
> - The benefit is a company-scoped setup-token flow with one-time
secret delivery, redaction, and fail-closed transport checks, ready for
a later staged production rollout
## Linked Issues or Issue Description
**Agent or provider**
Claude Code setup-token login for sandbox agents.
**Why this adapter is useful**
Sandbox agents need a supported way to sign in without host credentials.
An authorized owner completes the browser step and receives the token
one time.
**How the agent is invoked**
When a sandbox provider binds the injectable transport, the server
starts `claude setup-token` through a sandbox pseudo-terminal, sends the
browser code to the matched prompt, and returns the token through the
guarded session route. The default build does not bind the transport. In
that state the start route fails closed with a fixed no-secret `503`. It
does not start a process and it does not hold a sandbox lease.
**Additional context**
The transport is injectable, so each sandbox provider binds its own
pseudo-terminal. This pull request adds the Daytona transport but does
not bind it in the production server. A production wiring needs a lease
manager, a live pseudo-terminal factory, a durable token store, and its
own security review. The route keeps secrets out of logs, activity
details, errors, telemetry, and non-owner responses.
## What Changed
- Add strict parsers for the setup-token URL, the prompt, and the
success token.
- Add a login runner that drives the `claude setup-token` command
through a pseudo-terminal.
- Add the Daytona pseudo-terminal transport and the sandbox plugin
wiring.
- Add a company-scoped, owner-bound login session service with rate
limits, a reaper, cleanup, and one-time token delivery.
- Add the guarded session routes at
`/agents/:id/setup-token-login-sessions/*` behind an injectable
transport. The routes become the live login path only when a provider
binds the transport.
- Keep the start route fail-closed in the default build. It returns a
fixed no-secret `503` and it does not bind `setupTokenLogin`.
- Keep the existing host route `POST /agents/:id/claude-login` in place.
This pull request does not replace it.
- Keep confidential responses behind a fail-closed TLS transport guard
with `Cache-Control: no-store`, and extend redaction for the new fields.
- Export the parser and the runner from the Claude local server entry,
and document the new session routes in the OpenAPI spec.
## Verification
- `pnpm --filter @paperclipai/server exec vitest run setup-token-route
setup-token-session`
- `pnpm --filter @paperclipai/adapter-claude-local exec vitest run`
- `pnpm --filter @paperclipai/server run typecheck`
- Confirm that the pull request checks pass on GitHub.
## Risks
- Low user-facing risk on merge. The default build does not bind the
transport, so the production start route stays fail-closed with a `503`.
The merge does not change the production login behavior.
- When a provider later binds the transport, the flow starts a live
sandbox process and holds a short-lived in-memory secret. Cleanup must
stop the child before it releases the sandbox lease.
- The transport guard fails closed when the deployment does not provide
a trusted TLS path. A wrong proxy allowlist can block a valid request.
- The production wiring is out of scope. It needs a lease manager, a
live pseudo-terminal factory, a durable token store, and its own
security review before the server binds `setupTokenLogin`.
## Model Used
Anthropic Claude Opus 4.8 assisted the implementation. It used extended
reasoning, code execution, repository tool use, and a 200,000-token
context window.
## Checklist
- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` /
`Closes: #` / `Refs: #` OR (b) described the issue in-PR following the
relevant issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes (the
OpenAPI spec covers the new session routes; no user-facing documentation
needs 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>
## Thinking Path
> - Paperclip is the open source app people use to manage AI agents for
work
> - Sandbox providers (Daytona, Kubernetes) sync run results back to the
host with a sandbox-authored tarball
> - Before extraction, a confinement check parses the host `tar -tvf`
listing and fails closed on unparseable lines
> - The parser only understands the GNU tar listing dialect; macOS ships
bsdtar, whose ls-style listing never matches
> - Every sandbox syncOut on a macOS host therefore aborts with
"refusing tarball with an unparseable entry listing", and the run fails
at copy-back
> - This pull request teaches the parser both dialects while keeping the
fail-closed and traversal guarantees
> - The benefit is that Daytona and Kubernetes sandbox runs work on
macOS hosts, with no behavior change on Linux
## Linked Issues or Issue Description
No existing issue. Bug description:
**What happened?**
On a macOS host, every Daytona sandbox run fails at syncOut. The adapter
reports: `Daytona syncOut refusing tarball with an unparseable entry
listing: -rw-r--r-- 0 daytona daytona 7560 Aug 11 21:43 AGENTS.md`. The
Kubernetes provider has the same parser and fails the same way.
**Expected behavior**
The confinement check accepts a well-formed listing from the host tar,
whichever dialect the host tar emits. It still rejects members that
escape the extraction directory, and it still fails closed on lines it
cannot parse.
**Steps to reproduce**
1. Run Paperclip on macOS (system tar is bsdtar).
2. Configure an agent with the Daytona sandbox provider.
3. Trigger any run that syncs files back from the sandbox.
4. The run fails at syncOut with the unparseable-entry-listing error,
because bsdtar prints `<perms> <links> <user> <group> <size> <Mon> <day>
<time|year> <name>` while the parser expects the GNU `<perms>
<owner>/<group> <size> <date> <time> <name>` shape.
**Operating system**
macOS (bsdtar 3.5.3). Linux hosts with GNU tar are unaffected.
## What Changed
- Extracted the listing-line parse in both providers' `file-sync.ts`
into an exported `parseTarVerboseListingLine` that accepts the
GNU/busybox dialect and the bsdtar (libarchive) dialect.
- The GNU shape now requires the slash-joined `<owner>/<group>` field.
This keeps the two shapes mutually exclusive. Without it, a bsdtar line
with numeric uid/gid satisfies the loose GNU pattern shifted by one
field, which would hide a leading `../` from the traversal check.
- Unparseable lines still fail closed. This includes device-node
entries, whose size column is `major,minor` in both dialects.
- Made the path-traversal fixture in the Daytona suite portable: GNU
spells member renaming `--transform`, bsdtar spells it `-s`.
- Added a Daytona test that refuses a sandbox-authored tarball carrying
a symlink whose target escapes the extraction dir.
- Added parser unit tests for both dialects (file, dir, symlink,
hardlink, numeric owner, year-form dates, fail-closed lines) to both
providers' suites.
## Verification
- `pnpm test` in `packages/plugins/sandbox-providers/daytona`: 136/136
pass on a macOS host. On unpatched `master` the round-trip test fails
there with the unparseable-entry-listing error.
- `pnpm test` in `packages/plugins/sandbox-providers/kubernetes`: the
new parser tests pass; no new failures against the `master` baseline on
the same host.
- `pnpm typecheck` passes in both packages.
- CI runs the same suites on Linux/GNU tar and proves the GNU path is
unchanged.
## Risks
- Low risk. The GNU pattern is one token stricter (`<owner>/<group>`
must contain `/`). GNU and busybox tar always print the slash-joined
owner field, so accepted GNU listings are unchanged.
- The bsdtar branch only widens acceptance on hosts that were failing
100% of syncOuts before, so no working deployment changes behavior.
- The check still fails closed on anything neither pattern matches.
## Model Used
Claude Fable 5 (`claude-fable-5`, Claude Code CLI, extended thinking +
tool use).
## Checklist
- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [ ] 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
## Thinking Path
> - Paperclip is the open source app that manages AI agents for work
> - Sandbox providers let agents run in remote and isolated environments
> - Daytona session commands need a path that sends agent output to the
host without host polling
> - Host polling adds delay and repeats provider output work
> - This pull request adds typed execute.log notifications and a log
sink for incremental output
> - This pull request adds an optional ACP session stream with
final-result replay protection
> - The benefit is lower output delay while the default flags keep
current behavior unchanged
## Linked Issues or Issue Description
**Subsystem affected**
Cross-cutting. The change spans the plugin SDK, Daytona provider,
adapter utilities, and server execution services.
**Problem or motivation**
The Daytona ACP bridge polls a host output file while an agent command
runs. This adds delay and can repeat work. The host also needs a safe
route for provider output chunks.
**Proposed solution**
Add a typed `execute.log` notification with host-issued invocation
correlation. Add an ordered log sink to the environment execute path.
Add an optional ACP session-log path that parses newline-delimited JSON
frames and removes the host output poll for that path.
**Alternatives considered**
Keep the output-file poll as the only path. This keeps the current
behavior but does not provide timely output. The new path stays behind
flags, so the existing path remains the default fallback.
**Roadmap alignment**
This change supports the shipped Cloud / Sandbox agents milestone in
`ROADMAP.md`, including Daytona support.
## What Changed
- Add the typed `execute.log` worker-to-host notification and
company-scoped host route.
- Add ordered `stdout` and `stderr` chunk delivery before the final
execute result.
- Add the Daytona session log sink and the optional ACP streamed session
path.
- Add monotonic frame handling so live and final output reach the host
once.
- Keep `useLogStream` and `streamAgentSessionOutput` off by default.
- Add unit and integration coverage for the notification, execution
target, runtime, and Daytona paths.
## Verification
- Run adapter-utils tests: 445 tests pass locally.
- Run server environment tests: 73 tests pass locally.
- Run Daytona plugin tests: 131 tests pass locally.
- Run TypeScript checks for shared, adapter-utils, and server.
- Review the pull request checks after GitHub completes them.
- All required GitHub checks pass on the current head.
## Risks
The new paths change output delivery only when a feature flag enables
them. The final execute result remains available for parsing and
fallback. The main risk is a provider stream or frame-order error; the
final-result parser limits that risk.
## Model Used
OpenAI Codex, GPT-5, tool use and code execution. The runtime did not
supply 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
No operator documentation change applies because both new flags remain
disabled by default.
- [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>
## Thinking Path
> - Paperclip is the open source app people use to manage AI agents for
work.
> - Sandbox provider plugins let agents run commands in remote
environments.
> - The Daytona provider polls the exit code while it waits for command
logs.
> - Polling delays log delivery and does not support long-lived streamed
commands.
> - This pull request adds an opt-in Daytona log stream with one
reconnect and a poll fallback.
> - The benefit is faster log delivery while the existing default path
stays unchanged.
## Linked Issues or Issue Description
Refs: #10941
**Subsystem affected**
packages/plugins — sandbox provider plugins.
**Problem or motivation**
The Daytona provider polls the command exit code every 50 milliseconds
while it waits for logs. This delays output and does not support a
long-lived streamed command.
**Proposed solution**
Add the `useLogStream` provider option. Stream stdout and stderr from
the Daytona callback log form, read the exit code after the stream ends,
retry the read with bounded backoff, and fall back to the existing poll
path after a disconnect.
**Alternatives considered**
Keep polling for all commands. This keeps the current behavior but does
not provide timely logs or a path for long-lived commands.
**Roadmap alignment**
This supports the roadmap item for cloud and sandbox agents, including
Daytona.
## What Changed
- Add the opt-in `useLogStream` option with a default of `false`.
- Stream stdout and stderr from the Daytona callback log form.
- Drop replayed log prefixes by delivered byte offset after reconnect.
- Retry once after disconnect, then use the existing poll path.
- Read the exit code once after a successful stream and retry when the
code is not ready.
- Add tests for ordered output, exit-code reads, disconnect fallback,
and reconnect replay handling.
## Verification
- Run `node_modules/.bin/vitest run --config
packages/plugins/sandbox-providers/daytona/vitest.config.ts
packages/plugins/sandbox-providers/daytona/src/plugin.test.ts`.
- Confirm that the full Daytona plugin test project passes with 127
tests.
- Confirm that the changed files type-check against Daytona SDK 0.203.0
types.
- Review the PR against parent PR #10941 before it reaches `master`.
## Risks
- The stream path changes behavior only when `useLogStream` is `true`.
- A stream failure can add one reconnect attempt before the existing
poll fallback.
- The stream path has no command deadline because it supports long-lived
commands.
- No endpoint, stored data, telemetry shape, authentication rule, or
result shape changes.
## Model Used
OpenAI Codex, GPT-5, tool use and code execution. The context window and
reasoning mode are not exposed by this run.
## 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>
## Thinking Path
> - Paperclip is the open source app people use to manage AI agents for
work
> - Paperclip uses adapter and sandbox code to start agents and run
sandbox work
> - The current sandbox spans use mixed names and do not group related
run-time work
> - Mixed names make traces harder to read and compare across providers
> - This pull request renames provider spans, adds run-time wrapper
spans, and keeps the host allowlist closed
> - The benefit is clearer traces with the same sandbox behavior and
trust boundary
## Linked Issues or Issue Description
**What existing behavior does this improve?**
This improves OpenTelemetry span names and grouping for sandbox startup,
execution, callback relay, and agent session work.
**Subsystem affected**
Cross-cutting (multiple of the above): adapter utilities, sandbox
providers, shared telemetry documentation, and server instrumentation.
**Current behavior**
Sandbox provider spans use mixed names. Related run-time operations
expose inner `sandbox.exec` spans without a named wrapper span. The host
mapper uses a closed allowlist for provider span names.
**Proposed behavior**
Use descriptive provider-scoped span names. Add wrapper spans for agent
session input, agent session output polling, and callback relay. Keep
the host mapper allowlist closed and map unknown names to `other`.
**Reason and benefit**
Clear names make traces easier to read and reduce ambiguity during
sandbox operation analysis. Wrapper spans show the full operation while
preserving the inner execution spans.
**Breaking changes**
None. This change updates telemetry span names and grouping only. It
does not change sandbox behavior, endpoint behavior, or the host trust
boundary.
**Additional context**
Related prior work:
[#10758](https://github.com/paperclipai/paperclip/pull/10758).
## What Changed
- Rename Daytona provider sync and session spans with descriptive
provider-scoped names.
- Add three run-time wrapper spans for agent session input, output
polling, and callback relay.
- Add a shared span runner that preserves no-op behavior without a real
tracer.
- Keep the host mapper allowlist closed and map unknown names to
`other`.
- Update telemetry documentation and span-name tests.
## Verification
- Focused adapter-utils span tests pass for startup timing, callback
relay, and sandbox execution.
- Focused Daytona plugin span tests pass for renamed leaf spans and
session open or close spans.
- Focused server tests pass for host mapping and instrumentation.
- The stacked diff contains one commit on top of
`feat/daytona-persistent-session-model`.
## Risks
- Span names change for existing telemetry consumers.
- The wrapper spans add trace structure but do not change sandbox
execution.
- The host mapper keeps the existing closed allowlist and `other`
bucket.
> For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and
discuss it in `#dev` before opening the PR. Feature PRs that overlap
with planned core work may need to be redirected — check the roadmap
first. See `CONTRIBUTING.md`.
## Model Used
OpenAI GPT-5 (Codex agent); exact deployment revision and context window
are not exposed in this run; tool use and code execution enabled.
## 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] 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>
## Thinking Path
> - Paperclip is the control plane for autonomous AI companies
> - One core subsystem runs agent work inside sandboxes
> - The Daytona provider uses that path to run user commands
> - The current one-shot model does not keep a shell alive across
commands
> - This pull request adds an opt-in persistent session model for
Daytona
> - The benefit is faster command dispatch with the same sandbox
boundaries
## Linked Issues or Issue Description
### Subsystem affected
Cross-cutting. This change touches `packages/adapters`, provider tests,
span names, and sandbox command behavior.
### Problem or motivation
The Daytona provider needs a persistent shell for repeated command
dispatch.
The old advisory wrapper path does not reach that goal.
It also adds cost and removes the session speed gain.
### Proposed solution
Add a `useSessions` driver flag.
Keep it off by default.
Open one Daytona session per lease when the flag is on.
Send each user command into that session.
Read stdout and stderr from the session logs endpoint.
Run each command in a subshell so `exit` does not stop the shell.
Remove the advisory `bwrap` wrapper path and its lease metadata.
Add session setup and teardown spans.
Keep a hard delete on teardown.
### Alternatives considered
Keep the advisory `bwrap` wrapper.
That path does not give a real persistent session.
It also keeps extra command overhead.
Keep a one-shot fallback for user commands.
That would weaken the session model and hide a missing session case.
### Roadmap alignment
This work fits the `Cloud / Sandbox agents` milestone in `ROADMAP.md`.
It also supports the control plane goal of safe remote sandbox
execution.
### Additional context
The handoff verification reported `tsc --noEmit` clean and 119 Daytona
unit tests passing.
The handoff also reported a clean host span allowlist test and five
expected commits on the branch.
The security review gate remains required before merge.
## What Changed
- Added an opt-in persistent session model for the Daytona sandbox
provider.
- Routed user commands through `executeSessionCommand` when sessions are
enabled.
- Removed the advisory `bwrap` command wrapper path and the lease
metadata it used.
- Added session lifecycle spans and span allowlist coverage.
- Documented the leak bound in `DIRECTORY-CONSTRAINT-FINDINGS.md`.
## Verification
- `tsc --noEmit` clean for the Daytona plugin, per handoff verification.
- Daytona unit suite passes, with 119 tests, per handoff verification.
- Host span allowlist test passes, per handoff verification.
## Risks
- Persistent sessions can leak if teardown fails.
- Session logs must keep stdout and stderr separate.
- The flag stays off by default to limit rollout risk.
## Model Used
OpenAI GPT-5, Codex, tool use enabled.
## 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>
## Thinking Path
> - Paperclip is the open source app people use to manage AI agents for
work
> - Agent runs execute inside sandbox environments. Sandbox provider
plugins (Daytona, Modal, exe.dev, and others) declare a JSON-Schema
`configSchema`. The Environment configuration form renders from that
schema.
> - The sizing and image fields open empty. Users must guess working
values. The Modal form cannot submit at all until the user types an app
name and an image by hand.
> - The form renderer already pre-fills every field that declares a
JSON-Schema `default`. The manifests do not use this mechanism for
sizing or image fields.
> - This pull request adds optional `default` values to the Daytona,
Modal, and exe.dev manifest schemas.
> - The benefit is a form that opens with known-good values. Users can
create a working environment without provider research.
## Linked Issues or Issue Description
**Current behavior**
The Environment configuration form opens with empty sizing and image
fields for the Daytona, Modal, and exe.dev sandbox providers. Users must
find working values in provider documentation. Modal declares `appName`
and `image` as required with no default, so the form blocks submission
until the user invents both values.
**Proposed behavior**
The provider manifests declare JSON-Schema `default` values. The
existing form renderer pre-fills them:
- Daytona: CPU `4`, memory `4` GiB, disk `10` GiB, image
`daytonaio/sandbox:0.8.0`
- exe.dev: CPU `4`, memory `4GB`, disk `20GB`
- Modal: app name `paperclip`, image `node:22`
Secret-ref fields (API keys, tokens) get no defaults on purpose. The
form persists a raw string in a secret-ref field as a company secret on
save. A placeholder default would become a stored secret with a bogus
value. Each plugin test suite now guards this invariant.
**Reason and benefit**
New users can create a working sandbox environment without guessing. The
defaults stay optional: users can clear or change every value, and the
schema marks no new field as required. The Modal image default `node:22`
satisfies the sandbox runtime contract in `SANDBOX-REQUIREMENTS.md`
(`node`, `sh`, and `tar` on PATH).
**Subsystem affected**
Sandbox provider plugins (`packages/plugins/sandbox-providers/*`):
environment driver `configSchema` manifests.
**Breaking changes**
None. Defaults only seed the create-mode form. Saved environments keep
their stored config. E2B, Novita, Cloudflare, and Kubernetes manifests
do not change: E2B and Novita already default to their base templates,
and the Cloudflare bridge and Kubernetes cluster fields have no sensible
universal value.
## What Changed
- Add `default` values for `cpu`, `memory`, `disk`, and `image` in the
Daytona manifest. Trim the memory description to match.
- Add `default` values for `cpu`, `memory`, and `disk` in the exe.dev
manifest.
- Add `default` values for `appName` and `image` in the Modal manifest.
Extend the image description with the runtime-contract rationale.
- Add manifest tests in all three plugins: defaults match expected
values, defaults satisfy their own schema constraints, and no secret-ref
field declares a default.
- Bump plugin versions: daytona and modal `0.1.0` → `0.1.1`, exe-dev
`0.1.1` → `0.1.2`.
## Verification
- Run `pnpm test` in `packages/plugins/sandbox-providers/daytona`,
`.../modal`, and `.../exe-dev`. The new `* manifest form defaults`
suites pass.
- Run `./node_modules/.bin/tsc --noEmit` in each of the three packages.
Typecheck passes.
- Manual: rebuild the plugins (`pnpm build` in each package), let the
plugin dev-watcher refresh the manifest, then open Environments → New
environment. The Daytona form shows CPU 4, Memory 4, Disk 10, and image
`daytonaio/sandbox:0.8.0`. The Modal form shows `paperclip` and
`node:22`. The API key fields stay empty.
- Verified live on a local instance: the served `configSchema` in the
plugin registry carries the new defaults, and existing environments are
unchanged.
## Risks
- Low risk. The change touches only manifest schema metadata and tests.
No runtime code path changes.
- New environments created with untouched forms now request 4 CPU / 4
GiB / 10 GiB from Daytona instead of provider minimums. This can raise
cost per sandbox for users who previously saved empty fields.
- The Daytona image default pins `daytonaio/sandbox:0.8.0`. The default
needs a manual bump when Daytona ships new sandbox images.
> 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 Fable 5 (Anthropic, model ID `claude-fable-5`), via the Claude
Code CLI, with extended thinking and tool use.
## Checklist
- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [ ] 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
## Thinking Path
> - Paperclip is the open source app people use to manage AI agents for
work
> - Issues use `in_review` to request a final decision from an
authorized writer
> - The server rejected an assignee agent that tried to close its own
review, even when the issue had no independent-review rule
> - This rejection stopped the default agent workflow and did not
represent the configured execution-stage rules
> - Paperclip needs an open default and explicit issue-level constraints
for teams that require an independent or human verdict
> - This pull request removes the unconditional rejection and adds
`anyone`, `not_creator`, and `human_only` review policies
> - The benefit is a working default path with opt-in, authenticated
verdict controls
## Linked Issues or Issue Description
Refs #10635, #4429, and #10671.
The related public work covers execution-stage independence,
self-approval fallback behavior, and durable review paths. This change
is distinct. It controls who can resolve an issue review verdict. It
keeps configured execution stages active.
## What Changed
- Added a nullable `review_policy` issue column. Null has the same
meaning as `anyone`. The migration does not backfill existing issues.
- Added shared create, update, response, and compact issue contracts for
`anyone`, `not_creator`, and `human_only`.
- Removed the unconditional agent self-approval rejection for
`in_review` issues.
- Added one reusable verdict-actor check for terminal status changes and
pending interaction accept or reject actions.
- Used the authenticated principal type for `human_only`. Agent keys and
run tokens remain agent principals.
- Used the latest transition into `in_review` to identify the requester
for `not_creator`.
- Added actionable 403 responses that name the policy, the allowed
actor, and the next step.
- Kept the configured execution-stage transition and signoff behavior.
- Added focused contract, helper, status-route, interaction-route, and
execution-stage regression tests.
- Updated the implementation specification for the new issue field.
## Verification
- `pnpm exec vitest run packages/shared/src/validators/issue.test.ts
server/src/__tests__/issue-review-policy.test.ts
server/src/__tests__/issue-stalled-review-decision-routes.test.ts
--reporter=dot` passed: 42 tests.
- `pnpm --filter @paperclipai/shared typecheck` passed.
- `pnpm --filter @paperclipai/db typecheck` passed, including migration
numbering and safety checks.
- `pnpm --filter @paperclipai/server typecheck` passed.
- `pnpm run typecheck:build-gaps` passed across server, CLI, plugin
SDK/examples, plugin wiki, and UI.
- `git diff --check origin/master...HEAD` passed.
- SecurityEngineer review approved the authenticated-principal checks
and accepted policy-relaxation tradeoff with no required changes.
- Greptile reviewed the latest head at 5/5 with zero inline comments or
follow-ups.
- The latest-head GitHub rollup passed build, typecheck,
server/workspace tests, serialized suites, canary, e2e, and external
security checks.
## Risks
- The migration adds one nullable text column. It has no default and no
backfill.
- `not_creator` reads the latest recorded transition into `in_review`.
It denies the verdict when it cannot identify the requester.
- Agents can change or relax `reviewPolicy` when they have issue write
access. This is intentional for this issue-level control.
- Null and `anyone` do not add a database query to the verdict path.
- Configured execution-stage checks still run after the issue-level
policy check.
> This work aligns with the completed "Agent Reviews and Approvals" and
"Enforced Outcomes" roadmap items. It does not add a new roadmap
capability.
## Model Used
- OpenAI Codex, GPT-5. The exact deployment ID and context-window size
are not exposed to the agent. The run used reasoning, repository tools,
code execution, and GitHub CLI access.
## 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>