Commit Graph

399 Commits

Author SHA1 Message Date
Constantine 2f1c0e011e
fix(hermes): surface silent nonzero exit failures (#10107)
## Thinking Path

- Followed a silent nonzero Hermes exit from child-process result
parsing through heartbeat run, runtime, task-session, and agent
finalization.
- Found two gaps: the adapter could return `errorMessage: null` for a
numeric nonzero exit, and heartbeat later reused the nullable adapter
field instead of its normalized fallback.
- Kept timeout, signal-cancellation, and specific parsed diagnostics
authoritative.

## Linked Issue(s) / Bug Report

Related to #9751 (stderr classification) and #9519 (exit-zero
finalization), but this is a separate failure mode.

Reproduction: run Hermes with a child result equivalent to `exitCode:
1`, `timedOut: false`, and no parsed diagnostic. The heartbeat row
derives `Adapter failed`, while runtime/task-session/agent finalization
can persist null diagnostics.

## What Changed

- Give silent numeric nonzero Hermes exits a stable fallback such as
`Hermes exited with code 1`.
- Preserve specific parsed errors and timeout/signal semantics.
- Reuse the normalized persisted run error for recovered runtime state,
task-session `lastError`, and agent `errorReason`.
- Add adapter-level and embedded-Postgres regressions.

## Verification

- Hermes adapter `execute.onspawn.test.ts` — 7 passed.
- Focused heartbeat normalized-error regression — 1 passed (91 skipped).
- `pnpm --filter @paperclipai/hermes-paperclip-adapter typecheck` —
passed.
- `pnpm --filter @paperclipai/server typecheck` — passed.
- `git diff --check origin/master...HEAD` — passed.

Independent review also ran the full recovery file: the changed
regression passed; one unrelated pre-existing timing-sensitive test
timed out.

## Risks / Rollout Notes

Low risk. Fallback text is used only when a numeric nonzero exit has no
better diagnostic. Existing timeout, signal, and parsed-error precedence
remains unchanged.

## Model Used

OpenAI Codex `gpt-5.6-sol` with repository inspection, test execution,
and independent read-only review.

## Checklist

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

Co-authored-by: cucurigoo <cucurigoo@users.noreply.github.com>
2026-08-12 16:09:35 -07:00
Jannes Stubbemann 1f7959bc69
fix(codex-local): skip benign stderr warnings when deriving the fallback run error (#10003)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - Agents execute through adapters; the codex_local adapter runs the
Codex CLI and reports each run's outcome, including an error message
when the CLI exits nonzero
> - When no error can be parsed from the CLI's JSONL output, `toResult`
in `packages/adapters/codex-local/src/server/execute.ts` falls back to
the first non-empty stderr line as the run error
> - The adapter itself passes the approvals-bypass flag, so the CLI's
first stderr line is always the benign startup warning "YOLO mode is
enabled. All tool calls will be automatically approved."
> - Failed runs therefore record that warning as their error, hiding the
real cause (for example an OpenAI API error further down in stderr) and
making failures hard to diagnose from the run record
> - This pull request derives the fallback error from the first
meaningful stderr line, skipping a conservative set of known benign
lines, and keeps the existing behavior when every line is benign
> - The benefit is that failed Codex runs surface the actual failure
reason instead of a harmless startup warning, without ever producing an
emptier message than before

## Linked Issues or Issue Description

No public issue exists for the codex_local case. The same bug class was
fixed for gemini-local in Refs #5099 and Refs #3476; this PR applies the
equivalent fix to codex_local.

**What happened?**
On a multi-tenant cloud deployment of Paperclip, several codex_local
runs failed and their run records showed `error_code=adapter_failed`
with the error text "YOLO mode is enabled. All tool calls will be
automatically approved." That is a benign Codex CLI startup warning,
printed on every run because the adapter passes the approvals-bypass
flag itself. The real failure (an OpenAI API error printed later in
stderr) was never surfaced.

**Expected behavior**
When the Codex CLI exits nonzero and no error was parsed from its JSONL
output, the run error should be the first stderr line that actually
explains the failure, not a startup warning the adapter itself provoked.

**Steps to reproduce**
1. Configure a codex_local agent and make the underlying Codex CLI
invocation fail after startup (for example, configure a model id the
active credentials cannot use).
2. Run the agent so the CLI exits nonzero with no parsed JSONL error.
3. Inspect the run's error message: it shows the YOLO approvals warning
(the first stderr line) instead of the real error printed further down
in stderr.

## What Changed

- Added `firstMeaningfulStderrLine` next to `firstNonEmptyLine` in
`packages/adapters/codex-local/src/server/execute.ts`, with a
conservative benign-line predicate covering the YOLO approvals warning
and `[paperclip] ...` diagnostic lines the adapter injected (for example
ACP fallback notes).
- Used it only in the `toResult` fallback error derivation. If every
stderr line is benign, the existing chain still applies (first non-empty
line, then `Codex exited with code N`), so the message never gets
emptier than today. Logging is unchanged.
- Added
`packages/adapters/codex-local/src/server/execute.stderr-error.test.ts`:
four end-to-end cases through `execute()` with a mocked CLI process,
plus unit coverage for the new helper. Tests were written first and
confirmed failing before the fix.

## Verification

- `pnpm exec vitest run
packages/adapters/codex-local/src/server/execute.stderr-error.test.ts`
(7 tests pass; 5 failed before the fix as expected)
- `pnpm exec vitest run packages/adapters/codex-local` (21 files, 188
tests pass)
- `pnpm run typecheck` in `packages/adapters/codex-local` (clean)

## Risks

Low risk. Only the derived fallback `errorMessage` changes, and only
when a benign line would otherwise have been picked; parsed JSONL
errors, logging, retry/quota/auth classification inputs, and the
empty-stderr exit-code fallback are untouched. The benign-line list is
deliberately conservative (exact prefixes) so real errors are never
skipped.

## Model Used

Claude Fable 5 (claude-fable-5), extended thinking, via Claude Code

## Checklist

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

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

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-08-12 16:09:10 -07:00
LeeJ 5521d768b2
fix(claude-local): avoid root-only skip permissions failure (#9463)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Claude local is one of the adapter paths that lets operators run
Claude Code through a local Paperclip runtime.
> - Claude Code rejects `--dangerously-skip-permissions` when the
process is running as root or through sudo.
> - Local/self-hosted Paperclip deployments may run inside root-owned
Docker/runtime processes, so the Claude local adapter can fail before it
reaches the actual runtime/auth condition.
> - Paperclip already uses a curated `--allowedTools` list instead of
`--dangerously-skip-permissions` for remote Claude targets.
> - This pull request applies the same safer permission strategy to
local root processes while preserving existing local non-root and remote
behavior.
> - The benefit is clearer, safer Claude local diagnostics/execution in
containerized setups without widening permissions beyond the existing
explicit tool allowlist.

## Linked Issues or Issue Description

No directly matching public issue or PR found.

Bug description:

- **Problem:** `claude_local` can fail its local probe/execution path
when Paperclip runs from a root-owned local container/runtime because
Claude Code refuses `--dangerously-skip-permissions` under root/sudo.
- **Actual behavior:** The adapter may fail immediately with Claude's
root/sudo guard before validating the real Claude runtime/auth state.
- **Expected behavior:** Local root processes should use the same
explicit allowlist strategy Paperclip already uses for remote targets,
while local non-root behavior remains unchanged.
- **Environment:** Local/self-hosted Docker or container-style Paperclip
runtime where the app process UID is `0`.

Related but different: #4926 covers MCP config propagation for the
Claude local adapter, not the root/sudo permission flag behavior fixed
here.

## What Changed

- Added root-aware permission argument selection for the Claude local
adapter.
- Preserved current local non-root behavior:
`--dangerously-skip-permissions` is still used when allowed.
- Preserved current remote behavior: remote targets continue using
explicit `--allowedTools`.
- Changed local root behavior to use the explicit `--allowedTools` list
instead of `--dangerously-skip-permissions`.
- Threaded process UID awareness through Claude local probe and
execution paths.
- Added unit coverage for skip-disabled, remote, local non-root, local
root, and UID-unavailable behavior.

## Verification

```sh
./node_modules/.bin/vitest run --config g15-vitest-claude-local.config.mjs \
  packages/adapters/claude-local/src/server/permissions.test.ts
```

Result:

```text
1 file passed
8 tests passed
```

```sh
pnpm --filter @paperclipai/adapter-claude-local typecheck
```

Result:

```text
@paperclipai/adapter-claude-local typecheck passed
```

Additional local smoke:

- Ran a disposable root-container Claude adapter diagnostic against this
patch.
- The diagnostic no longer fails with Claude's root/sudo
`--dangerously-skip-permissions` error.
- It proceeds to the actual environment-specific Claude auth/runtime
result.
- No credentials, tokens, hostnames, private paths, or internal
Paperclip issue references are included in this PR.

Public duplicate checks performed:

```sh
gh pr list --repo paperclipai/paperclip --state open --search 'claude local root permissions dangerously skip permissions allowedTools'
gh issue list --repo paperclipai/paperclip --state open --search 'claude local root permissions dangerously skip permissions allowedTools'
```

## Risks

Low-to-medium risk adapter behavior change:

- Local root Claude runs will now use explicit `--allowedTools` rather
than broad skip-permissions behavior.
- That is intentionally safer, but an environment depending on broader
implicit tool access under root may now need the adapter allowlist to
include any required tools.
- Local non-root behavior is unchanged.
- Remote behavior is unchanged.
- No database migrations, API contract changes, or UI changes.

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

## Model Used

OpenAI Codex `gpt-5.5` via Hermes Agent, with shell/file/tool use for
repository inspection, patching, local verification, and GitHub CLI
operations.

## 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

Co-authored-by: LeeJ <elJayAdvisor@users.noreply.github.com>
2026-08-12 16:08:14 -07:00
Nicky Leach e31951a17d
feat: Claude agent setup-token login in a sandbox (#11286)
## 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>
2026-08-12 13:02:49 -07:00
Nicky Leach e5a7fd7038
Add sandbox device-login for the Codex adapter (#11237)
## Thinking Path

> - Paperclip helps people manage AI agents for work.
> - Agent adapters connect Paperclip to tools such as the Codex command
line tool.
> - A sandboxed Codex agent may start without a credential.
> - The operator needs a safe sign-in flow that does not expose
credentials to the shared package or the sandbox.
> - This pull request adds a company-scoped device-login flow with a
temporary Daytona sandbox.
> - The flow promotes the credential only after readiness checks pass
and removes the temporary sandbox after use.
> - The result lets an operator sign in to a sandboxed Codex agent from
the agent form.

## Linked Issues or Issue Description

**Subsystem affected**

Cross-cutting (multiple of the above)

**Problem or motivation**

A Codex adapter that runs in a sandbox cannot authenticate when the
company has no pre-provisioned Codex credential.

**Proposed solution**

Add a company-scoped device-login session. Start a temporary sandbox,
run `codex login --device-auth`, stream the code and URL, verify
readiness, promote the credential, and delete the sandbox.

**Alternatives considered**

Pre-provisioning a credential does not support first-time sandbox login.
Keeping the credential in the login sandbox does not provide a durable
company credential.

**Roadmap alignment**

This supports the roadmap item for cloud and sandbox agents.

**Additional context**

The flow uses a five-minute cleanup reaper, compare-and-set status
changes, and a PostgreSQL advisory lock to protect promotion and
cleanup.

## What Changed

- Add the adapter login-session contract, database table, and migration.
- Add company-scoped server routes and a service for sandbox device
login.
- Add credential promotion, readiness checks, and cleanup after login.
- Add restart-safe cleanup for abandoned login sandboxes.
- Add sandbox login controls to the agent creation and edit forms.
- Keep device-login and vendor identifiers out of public shared and
adapter UI symbols.

## Verification

- `pnpm --filter @paperclipai/adapter-codex-local exec vitest run`
passed with 310 tests at the submitted commit.
- The server login route, service, and reaper tests passed with 45 tests
at the submitted commit.
- The agent form render tests passed with 26 tests at the submitted
commit.
- The public-symbol leak check passed at the submitted commit.
- A live Daytona sign-in flow still requires confirmation by a user with
a live sandbox.

## Risks

The migration adds a new company-scoped table. A promotion or cleanup
race could remove a credential or leave a sandbox active, so the service
uses claims, compare-and-set transitions, and an advisory lock. The live
Daytona flow needs operator confirmation because local tests do not
provide a real browser sign-in.

## Model Used

OpenAI Codex, GPT-5, tool use and code execution, extended reasoning.

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-08-12 08:58:25 -07:00
Valentin Marchaud b5ebda1dca
fix(grok-local): report real token usage and cost instead of hardcoded zeros (#10433)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - Cost/usage tracking is core to that: the dashboard shows per-agent
spend so a team can see what their AI workforce is costing them
> - The `grok_local` adapter (xAI's Grok Build CLI) is a newer adapter
than `claude_local`/`codex_local`, and its usage/cost wiring was left
incomplete
> - Every `grok_local` run persists
`usage.inputTokens/outputTokens/cachedInputTokens = 0` and `costUsd =
null` in `heartbeat_runs`, unconditionally, even though the underlying
`grok` CLI reports real, non-zero token counts and cost per turn in its
own JSON stream
> - This pull request wires the parser to actually read
`usage`/`total_cost_usd` from the CLI's terminal `end` event, threads
those values into the adapter's execution result, and marks them
`usageBasis: "per_run"` so the heartbeat service doesn't incorrectly
delta them against a prior run on a resumed session (matching how
`claude_local`/`codex_local` already do this)
> - The benefit is accurate cost/usage visibility for any self-hosted
Paperclip instance running Grok Build agents, instead of a dashboard
that always reads zero

## Linked Issues or Issue Description

Fixes: #10432

## What Changed

- `packages/adapters/grok-local/src/server/parse.ts`: `parseGrokJsonl()`
now reads `usage.input_tokens` / `usage.output_tokens` /
`usage.cache_read_input_tokens` / `total_cost_usd` from the terminal
`end` event and returns them on `ParsedGrokJsonl` (previously discarded
entirely).
- `packages/adapters/grok-local/src/server/execute.ts`: `toResult()` now
populates `usage.inputTokens/outputTokens/cachedInputTokens` from the
parsed values instead of hardcoded `0`, sets `usageBasis: "per_run"`
(each `--single` invocation reports usage for just that process, not a
running session total), and surfaces `costUsd` only when `billingType
=== "api"` (metered) — subscription/OAuth billing has no marginal dollar
cost, so it stays `null` there, but token counts are populated for both
billing types since usage visibility is useful regardless of billing
model.
- `packages/adapters/grok-local/src/server/parse.test.ts`: added a test
asserting usage/cost extraction from a representative `end` event
payload, and updated the existing exact-equality test for the new
fields.
- `packages/adapters/grok-local/src/server/execute.test.ts`: added a
test covering both subscription billing (tokens populated, `costUsd:
null`) and API-key billing (tokens populated, real `costUsd`), and
asserting `usageBasis: "per_run"` in both cases.

## Verification

- `pnpm vitest run packages/adapters/grok-local/src/server/parse.test.ts
packages/adapters/grok-local/src/server/execute.test.ts` — 9/9 passed
- `tsc --noEmit` on the `grok-local` package — clean
- Verified against a real self-hosted Paperclip instance running `grok`
CLI `0.2.112` with SuperGrok subscription (OAuth) auth: confirmed the
raw CLI stream reports real `usage`/`total_cost_usd` (e.g.
`"usage":{"input_tokens":21560,...},"total_cost_usd":0.0564448`) that
was previously discarded before ever reaching
`heartbeat_runs.usage_json`, which always showed all-zero tokens
regardless of real usage.

## Risks

- Low risk, additive change scoped entirely to the `grok_local`
adapter's usage/cost reporting path — no change to control flow, session
handling, or process execution.
- `usageBasis: "per_run"` mirrors the existing, already-tested pattern
in `claude_local`/`codex_local` execute paths, so the heartbeat
service's per-run vs. session-cumulative delta logic is exercised the
same way.
- `costUsd` is intentionally left `null` for subscription/OAuth billing
(no behavior change there beyond now-populated token counts) to avoid
implying a dollar cost that doesn't exist for flat-rate billing.

## Model Used

Claude Sonnet 5 (`claude-sonnet-5`), via Claude Code, no extended
thinking. Root cause was found by comparing real `grok` CLI JSON stream
output (captured directly from a live invocation) against the persisted
`heartbeat_runs.usage_json` row for the same run on a self-hosted
instance, then reading `parse.ts`/`execute.ts` source to confirm the
hardcoded zero values.

## 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 (none found)
- [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
(`fix/grok-local-usage-cost-tracking`) and contains no internal
Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [ ] I have updated relevant documentation to reflect my changes (no
user-facing docs reference this internal usage-reporting behavior)
- [x] I have considered and documented any risks above
- [ ] All Paperclip CI gates are green (pending at time of writing)
- [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
(addressed the one P1 raised — `usageBasis: "per_run"`)
- [x] I will address all Greptile and reviewer comments before
requesting merge
2026-08-11 17:38:23 -07:00
scotttong 815e49bb7c
feat: make chat-style tasks the default experience (#11101) 2026-08-11 09:06:21 -07:00
Nicky Leach 459469638e
feat(adapter-codex-local): add secure device-login building blocks (#11097)
## Thinking Path

> - Paperclip connects AI agents to local and remote runtimes.
> - The Codex local adapter needs a safe device-login flow.
> - A future sandbox integration needs strict prompt validation, secret
protection, cleanup, and private credential storage.
> - This pull request adds tested building blocks for that flow.
> - The result gives a later Daytona integration a clear security
boundary.

## Linked Issues or Issue Description

No public issue covers this change.

**Problem or motivation**

The Codex local adapter has no safe, reusable flow to prove device login
inside an isolated sandbox.

**Proposed solution**

Add parser, runner, credential export, and proof helpers. Validate the
prompt, protect login data, store credentials in a private run-scoped
home, and dispose all sandbox resources.

**Alternatives considered**

Do not connect a production Daytona driver in this change. Use an
injected sandbox driver and focused tests first. This keeps the security
controls testable before live provider integration.

**Roadmap alignment**

The change extends the Codex local adapter. It does not add a core
Paperclip route or duplicate a planned core feature.

**Additional context**

The flow keeps the login URL, code, and token out of logs, results, and
errors. The proof home uses a company-scoped root and a run-scoped
private directory.

## What Changed

- Add a pure parser for the exact Codex device-login URL and one-time
code shape.
- Add a sandbox runner with prompt handling, timeout, cancellation, and
disposal.
- Add a credential export step with company scoping, path checks,
payload checks, private modes, locking, and cleanup.
- Add redacted device-login fixtures and focused tests for parsing,
secret redaction, runner outcomes, credential export, and cleanup.

## Verification

- Run `pnpm --filter @paperclipai/adapter-codex-local exec vitest run`.
- Run `pnpm --filter @paperclipai/adapter-codex-local exec tsc
--noEmit`.
- Review tests for strict URL and code validation, timeout,
cancellation, disposal, secret redaction, path safety, payload safety,
file modes, and cleanup.

## Risks

- This change provides building blocks, not a live Daytona proof.
- A later integration must connect the runner to a concrete sandbox
driver.
- Credential export depends on existing Codex authentication cache
helpers.
- Incorrect path or payload assumptions can reject valid credentials.

## Model Used

Codex, GPT-5, tool use, code execution, and repository review. The
Paperclip runtime controls the exact context window and reasoning mode.

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-08-10 16:12:30 -07:00
Nicky Leach f5e9ca3e89
fix(adapters): keep user-scoped env bindings on the agent Test action (#10926)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - The agent Test action builds adapter config from the form.
> - The build-config parser kept plain and secret_ref bindings.
> - It dropped user_secret_ref bindings on the create path.
> - This PR shares one parser that keeps every binding shape.
> - The test path now sends the same env binding set that a real run
sees.
> - The benefit is one fix across every adapter build-config path.

## Linked Issues or Issue Description

**What happened?**
The agent Test action dropped a user-scoped env binding in create mode.
The same agent config worked in a real run. Related public PRs: #10115,
#9321, #9921, #8825.

**Expected behavior**
The Test action should keep user-scoped env bindings and resolve them
like a real run.

**Steps to reproduce**
1. Set a user-scoped env binding on an agent config form.
2. Run Test in create mode.
3. The probe runs without the variable.

**Paperclip version or commit**
c09d2509e3

**Deployment mode**
Local dev (pnpm dev)

**Agent adapter(s) involved**
Not adapter-specific (core bug)

**Database mode**
Embedded PGlite (default — DATABASE_URL unset)

**Additional context**
This change is not Claude-specific.

## What Changed

- Added a shared env binding parser in `@paperclipai/adapter-utils`.
- Replaced the eight adapter build-config copies with the shared helper.
- Kept `plain`, `secret_ref`, and `user_secret_ref` bindings intact in
create mode and edit mode.
- Preserved the runtime merge behavior from the earlier env merge
change.

## Verification

- Author-recorded test run:
`packages/adapter-utils/src/env-bindings.test.ts`
- Author-recorded test run:
`packages/adapters/claude-local/src/ui/build-config.test.ts`
- Author-recorded test run: six adapter build-config test files
- Author-recorded typecheck: `tsc --noEmit` for adapter-utils and the
eight adapter packages
- GitHub checks: all required PR checks pass on PR #10926.
- Greptile review: 5/5 with no open comments.

## Risks

- The change touches adapter config assembly.
- A wrong binding shape would change test-time probe input.
- Tests cover the binding types and the create-mode path.

> 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, code execution and repo inspection.

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-08-05 17:18:41 -07:00
Devin Foley ffd62a4cbb
fix(adapter-utils): carry the workspace origin remote into transported git workspaces (#10873)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - When an agent runs on a different host (sandbox or SSH), the adapter
transport copies the local git execution workspace to that host and
syncs changes back after the run
> - The transport materializes the remote copy with `git init` plus a
depth-1 or bundle fetch, so the copy has no `origin` remote and its head
reads as a parentless snapshot commit
> - An agent asked to publish its branch (push it, open a pull request)
sees "no remote, root snapshot" and must hand the publish step back to a
human operator, even when the branch base is a commit the upstream
remote already holds
> - This pull request carries the workspace's `origin` URL
(credential-scrubbed) onto the transported copy as metadata
> - The benefit is that branches produced in transported workspaces stay
publishable by any actor with credentials, while the transport itself
still never fetches or pushes

## Linked Issues or Issue Description

No public issue exists. Description follows the enhancement template:

**What existing behavior does this improve?**

The workspace transport in `@paperclipai/adapter-utils` already copies a
git workspace to the execution host and back. This change improves the
fidelity of that copy: the transported repo keeps the workspace's
`origin` remote instead of losing it.

**Subsystem affected**

Adapter utilities — the sandbox transport
(`withShallowGitWorkspaceClone` in
`packages/adapter-utils/src/git-workspace-sync.ts`) and the SSH
transport (`importGitWorkspaceToSsh` in
`packages/adapter-utils/src/ssh.ts`).

**Current behavior**

The transported copy is built with `git init` plus a depth-1 (sandbox)
or bundle (SSH) fetch. It has no remotes. `git remote -v` is empty and
the head commit reads as a root snapshot with no visible ancestry.
Agents and operators inside the execution host cannot fetch real
ancestry or push a branch, even when the branch base is a commit the
upstream remote already holds.

**Proposed behavior**

The transport reads the source workspace's `origin` URL, scrubs
credentials from it, and configures it on the transported copy. The
sandbox path adds the remote to the fresh clone. The SSH path sets or
adds the remote in the remote setup script, which also covers reused
workspace directories. A workspace with no `origin` transports exactly
as before.

**Reason and benefit**

A branch committed in a transported workspace becomes publishable in
place: the shallow boundary commit already exists on the remote, so a
push pack closes without full local ancestry (a new test locks in this
property). Fetching real ancestry also becomes possible for whoever
holds credentials. Without this, agents must describe their change in a
handoff document and a human must reconstruct the branch by hand.

**Breaking changes**

None. The URL copy is best-effort and metadata-only. The transport never
fetches from or pushes to the remote. The no-remote-git contract holds:
sync-back through the local cwd stays the only cross-run persistence
path, and `packages/adapters/AUTHORING.md` gains a paragraph that makes
the carried-remote nuance explicit.

## What Changed

- `packages/adapter-utils/src/git-workspace-sync.ts`: new
`sanitizeGitRemoteUrl` (strips http(s) userinfo, where tokens can be
embedded; scp-like/ssh forms and filesystem paths pass through) and
`readSanitizedOriginRemoteUrl`; `withShallowGitWorkspaceClone`
configures the scrubbed `origin` on the fresh clone, best-effort.
- `packages/adapter-utils/src/ssh.ts`: `importGitWorkspaceToSsh` sets or
adds the scrubbed `origin` in the remote setup script, non-fatal under
`set -e`.
- `packages/adapter-utils/src/git-workspace-sync.test.ts`: four new
integration cases (remote copied, credentials scrubbed, no-origin
unchanged, push from the shallow clone to an origin that holds the base
commit) plus `sanitizeGitRemoteUrl` unit tests.
- `packages/adapters/AUTHORING.md`: documents that a transported copy
may carry a credential-scrubbed `origin` as metadata, and why this does
not weaken the no-remote-git contract.

## Verification

- `npx vitest run packages/adapter-utils/src/git-workspace-sync.test.ts`
— 12/12 pass (4 new integration cases + sanitizer unit tests).
- `npx vitest run
packages/adapter-utils/src/sandbox-managed-runtime.test.ts` — 24/24
pass.
- `npx vitest run packages/adapter-utils/src/ssh-fixture.test.ts` —
16/16 pass, including the `no-remote-git contract` case (a workspace
without `origin` still round-trips with no remote introduced at any
point).
- `node scripts/check-no-git-push.mjs` — passes; this change adds no
push or fetch to adapter/runtime code.
- `pnpm typecheck` in `packages/adapter-utils` — clean.

## Risks

- Low risk. The change is additive metadata on the transported copy
only; failure to record the remote never fails the transport.
- Credential exposure is the real hazard and is handled: http(s)
userinfo is stripped before the URL leaves the host. Non-http forms
(scp-like, `ssh://`) carry no secret in the URL and pass through.
- A reused SSH workspace whose project `origin` changed now gets the
current URL via `set-url` instead of keeping a stale one.

## Model Used

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

## Checklist

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

> - Paperclip is the open source app people use to manage AI agents for
work
> - The `openclaw-gateway` adapter wakes a remote agent over a WebSocket
gateway. It sends a wake prompt. That prompt tells the agent which
environment variables to set and which file holds its Paperclip API key.
> - Each agent stores its claimed key in its own JSON file. The adapter
already exposes a `claimedApiKeyPath` config field for this. The field
is documented in `src/index.ts`. It also has an input in the agent
settings UI.
> - `buildWakeText` ignored that field. It hardcoded the shared default
path into the wake prompt text.
> - Every agent therefore read the same key file at wake time. Agents
authenticated as the wrong identity. The first API call failed.
> - This pull request passes `ctx.config.claimedApiKeyPath` into
`buildWakeText`. It uses the existing `resolveClaimedApiKeyPath` helper.
That helper falls back to the documented default.
> - The benefit is that each agent reads its own claimed-key file. Each
agent authenticates as itself.

## Linked Issues or Issue Description

Fixes #10071
Fixes #4976
Fixes #3098
Fixes #8076

These four open issues report the same defect. Earlier duplicates are
already closed: Refs #2561, Refs #2592, Refs #930.

Related pull requests that address the same root problem (duplicate
search):

- #3396 — same core change, no tests
- #3370 — heavier approach, injects `PAPERCLIP_CLAIMED_API_KEY_PATH`
into the wake env and adds server onboarding defaults
- #5970 — renames the config field to `paperclipApiKeyPath`
- #8072 — same core change, bundled with an unrelated protocol-version
change
- #784 — adds shell quoting and preflight instructions
- #3296 — bundled with an unrelated Claude hello-probe fix

## What Changed

- `packages/adapters/openclaw-gateway/src/server/execute.ts`
- `buildWakeText` now accepts `claimedApiKeyPath` as a parameter. It no
longer hardcodes the path.
- The `execute` call site passes
`resolveClaimedApiKeyPath(ctx.config.claimedApiKeyPath)`. That helper
returns the documented default
`~/.openclaw/workspace/paperclip-claimed-api-key.json` when the agent
sets no override.
  - `resolveClaimedApiKeyPath` is now exported so tests can call it.
- `packages/adapters/openclaw-gateway/src/server/execute.test.ts` — adds
`resolveClaimedApiKeyPath` cases: a configured value, an empty string, a
whitespace-only string, `undefined`, `null`, and non-string input.
- `packages/adapters/openclaw-gateway/vitest.config.ts` (new) —
package-level vitest config. It matches the config used by sibling
adapters such as `opencode-local`.
- `vitest.config.ts` (root) — adds the adapter to the workspace project
list.
- `scripts/run-vitest-stable.mjs` — adds
`@paperclipai/adapter-openclaw-gateway` to `nonServerProjects`.
**Maintainer-added during rebase.** The CI test lanes do not run a bare
`vitest`. They call `run-vitest-stable.mjs`, which invokes vitest with
an explicit `--project` allowlist. Without this entry the CI lanes skip
this package, and the root project-list entry alone has no effect on CI.

## Verification

Run the package suite directly:

```
pnpm install --frozen-lockfile
pnpm exec vitest run --project @paperclipai/adapter-openclaw-gateway
```

The suite covers `resolveSessionKey`, `buildAgentParams`, and the new
`resolveClaimedApiKeyPath` cases. The first two already existed in this
file but never executed in CI before this change.

Typecheck the package:

```
pnpm --filter @paperclipai/adapter-openclaw-gateway typecheck
```

Behavioural check, which no automated test covers:

1. Set `claimedApiKeyPath` to a per-agent value such as
`~/.openclaw/workspace/paperclip-keys/<agent>.json` in the agent's
gateway adapter settings.
2. Trigger a wake for that agent.
3. Confirm the rendered wake text names that file. It must not name the
shared default.

Maintainer note: this branch was rebased onto current `master` by a
maintainer. The original branch was two months stale. Only two conflicts
occurred, both additive: the import line and the tail of
`execute.test.ts`, and the project list in the root `vitest.config.ts`.
The `execute.ts` change applied without conflict. CI and Greptile re-run
against the rebased head.

## Risks

- Low for existing deployments. `resolveClaimedApiKeyPath` preserves the
default path exactly. Any agent that never set `claimedApiKeyPath`
receives the same wake text as before.
- The behaviour changes only for agents that already set a per-agent
path. Those agents previously received the wrong instruction. They now
receive the correct one.
- No database, schema, or API surface changes.
- CI now runs this package's test file for the first time. That file
includes the pre-existing `resolveSessionKey` and `buildAgentParams`
tests, which were never executed before.
- Five other adapters (`cursor-cloud`, `cursor-local`, `gemini-local`,
`grok-local`, `pi-local`) sit in the root project list but remain absent
from the CI allowlist. This pull request does not change them. That gap
is tracked separately.

## Model Used

- Contributor's change: Anthropic Claude, model ID `claude-opus-4-7`,
approximately 200K context, extended thinking. Used for triage, patch
authoring, and the original description.
- Rebase, the `run-vitest-stable.mjs` entry, and this description:
Anthropic Claude, model ID `claude-opus-5`, tool use enabled. Run by a
Paperclip maintainer.

## 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
— the branch name carries an internal ticket id. A fork branch cannot be
renamed without opening a new pull request, so this is left as-is. The
internal reference has been removed from the description.
- [ ] I have run tests locally and they pass — the contributor verified
the pre-rebase branch. The rebased head is verified by CI on this pull
request.
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes —
`claimedApiKeyPath` is already documented in `src/index.ts` and exposed
in the agent settings UI, so no documentation change is needed
- [x] I have considered and documented any risks above
- [ ] All Paperclip CI gates are green — pending the post-rebase run
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups —
pending re-review of the rebased head
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Pieter (CTO) <pieter@openclaw.local>
Co-authored-by: Andrew Aymeloglu <aaymeloglu@gmail.com>
2026-08-05 00:53:43 -05:00
Nicky Leach 7e592c33fa
feat(codex): add identity-keyed host credential cache (#10853)
## Thinking Path

> - Paperclip manages agent work as issues and pull requests.
> - This change lives in the Codex local adapter path.
> - The host auth flow needs a stable cache per identity.
> - The cache must not change the copy-back path or the default store
overwrite.
> - This pull request adds that cache and keeps the existing flow
intact.
> - The benefit is repeatable host auth with safer identity scoping.

## Linked Issues or Issue Description

**Subsystem affected**
- packages/adapters: Codex local adapter and host auth flow

**Problem or motivation**
- The host auth flow needs one usable credential per identity.
- The current flow does not keep that identity state in a separate
cache.

**Proposed solution**
- Add an identity-keyed host credential cache.
- Keep the cache company scoped.
- Add an opt-in seed mode for the merge decision helper.
- Write the cache at copy-back time without changing the default store
overwrite.

**Alternatives considered**
- Store the cache in the instance-global root.
- Seed the host default store through an environment flag.
- Both choices weaken isolation or caller control, so I did not use
them.

**Roadmap alignment**
- I checked `ROADMAP.md`.
- I found no direct overlap with an active roadmap item.
- The change fits the core auth and secrets direction.

**Additional context**
- Local tests passed before I opened this pull request.
- I found no direct duplicate pull request for this branch.

## What Changed

- Added `codex-auth-cache.ts` for company scoped cache storage and
identity anchored vending.
- Added `codex-auth-merge-decision.cjs` support for a leading
`--seed-if-dest-absent` flag.
- Updated `codex-auth-copyback.ts` to write the cache at teardown under
the merge lock.
- Wired `execute.ts` to use the identity anchored vend before the
managed home seed step.
- Added `CODEX-AUTH-CACHE.md` for the cache rules, directions, state
matrix, off switch, and clear action.
- Added and updated tests for cache behavior, merge decision flow, and
copy-back flow.

## Verification

- `pnpm --filter @paperclipai/adapter-codex-local exec vitest run`.
- `node_modules/.bin/vitest run --project @paperclipai/adapter-utils
workspace-restore-merge`.
- `tsc --noEmit` in `packages/adapters/codex-local`.
- `git log --oneline
origin/master..origin/feat/codex-auth-identity-cache` shows the expected
commits.

## Risks

- This change touches credential storage.
- A mistake in the cache path could break host auth for one identity.
- The tests reduce this risk, but the surface stays sensitive.

## Model Used

- OpenAI Codex, GPT-5, 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 linked existing issues with `Fixes:` / `Closes:` /
`Refs:` or described the issue in the pull request body
- [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>
2026-08-04 16:33:54 -07:00
Devin Foley f0b06d2de9
feat(claude): environment-aware test-environment probe and claude-local CI coverage (#10833)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - The claude_local adapter runs Claude Code on sandbox execution
targets, and operators verify an agent's configuration with the
test-environment probe before running it
> - Real runs merge the selected environment's env vars (secret refs
included) under the agent's adapter config env, but the probe built its
config from the adapter config alone — so environment-level auth worked
in runs while the Test button reported missing auth, and a dropped
secret binding passed silently
> - The claude env-test hints also did not recognize
`CLAUDE_CODE_OAUTH_TOKEN` even though the CLI accepts it, and a hello
probe that hit the subscription usage limit reported a hard failure
although authentication worked
> - Separately, the claude-local package test suites were absent from
the CI project list, so two suites drifted broken without notice
> - This pull request makes the probe resolve the same layered env as a
real run, adds the missing auth hint, classifies usage-limit probe
results as a warning, repairs the drifted suites, and turns the
claude-local project on in CI
> - The benefit is a Test button that tells the truth about
environment-level configuration, and a test suite that actually gates
the claude-local adapter

## Linked Issues or Issue Description

No public issue exists; related open PRs: Refs #9488 (recognizes
CLAUDE_CODE_OAUTH_TOKEN in environment checks — overlaps with the
auth-hint portion of this PR via a differently named check; it does not
cover the environment-envVars probe merge, the usage-limit
classification, or the CI coverage), Refs #9933 (live credential
validation in environment checks — complementary, no file-level conflict
with the route change).

The underlying problem, following the enhancement template:

**Current behavior**

The test-environment route builds the probe config from the agent's
adapterConfig only. Real runs merge the selected environment's envVars
under the agent env, so environment-level env vars (including auth such
as `ANTHROPIC_API_KEY` or `CLAUDE_CODE_OAUTH_TOKEN` bound as environment
secrets) work in runs while "Test environment" cannot see them, and a
missing secret binding passes silently. The claude env-test hints do not
recognize `CLAUDE_CODE_OAUTH_TOKEN`. A hello probe that hits the
subscription usage limit reports a hard `claude_hello_probe_failed`. The
claude-local package test suites do not run in CI, and two of them are
stale.

**Proposed behavior**

The probe resolves the selected environment's envVars
(environment-consumer secret bindings included) and merges them under
the agent config env with the run-path precedence; missing bindings
surface as an explicit error check that fails the test. The env-test
emits a `claude_oauth_token_configured` info check when that variable is
set. Usage-limit probe results classify as a
`claude_hello_probe_usage_limited` warning because auth works and only
the usage window is spent. The claude-local suites run in CI. Docs state
the resulting facts.

**Reason and benefit**

The Test button should tell the truth: it previously contradicted run
behavior for environment-level configuration and hid broken secret
bindings. Enabling the package suites in CI prevents further silent
drift — two suites were already broken on master without anyone
noticing.

**Breaking changes**

None. Runs are unchanged. The probe route only adds env layers and
checks; setups without environment envVars behave exactly as before.

## What Changed

- `server/src/routes/agents.ts`: the test-environment route resolves the
selected environment's envVars (forbidden keys stripped,
environment-consumer secret context) and merges them under the agent
adapterConfig env, mirroring `resolveExecutionRunAdapterConfig`
precedence. Missing secret bindings are skipped, reported as an
`environment_env_binding_missing` error check, and fail the test —
matching the `ConfigurationIncompleteFailure` a real dispatch would
raise.
- `packages/adapters/claude-local/src/server/test.ts`: new
`claude_oauth_token_configured` info hint between the API-key warning
and the subscription fallback; hello-probe classification gains a
`claude_hello_probe_usage_limited` warning for provider-quota results
(previously a hard `claude_hello_probe_failed`).
- `scripts/run-vitest-stable.mjs`: add
`@paperclipai/adapter-claude-local` to `nonServerProjects` so CI runs
the package suites.
- `packages/adapters/claude-local/src/server/execute.remote.test.ts`:
assert both runtime asset syncs (skills and mcp-config); the suite
predated the mcp-config asset.
- `packages/adapters/claude-local/src/server/test.probe.test.ts`:
usage-limit fixture now expects the usage-limited warning; new fixture
covers the genuine transient path (529 overloaded); new tests cover the
token hint and API-key precedence.
- `server/src/__tests__/agent-test-environment-routes.test.ts`: new
tests for the env merge (agent wins on conflict, forbidden key
filtered), missing-binding reporting, and the no-execution-target
fallback path.
- `docs/adapters/claude-local.md`, `docs/adapters/overview.md`: state
the auth-input facts (API key or oauth token wins over stored logins;
snapshot-owns-auth applies when neither is configured) and describe the
environment-aware Test behavior.

## Verification

- `npx vitest run --project @paperclipai/adapter-claude-local` — 131
tests pass (both drifted suites repaired; they fail on master today).
- `npx vitest run
server/src/__tests__/agent-test-environment-routes.test.ts` — 7 tests
pass.
- `node --test ./scripts/__tests__/run-vitest-stable-shard.test.mjs` —
passes with the added project.
- `pnpm typecheck` in `server/` and `packages/adapters/claude-local/` —
clean.

## Risks

- Low risk. The run path is untouched; the probe route change is
additive and inert when the environment has no envVars.
- The probe now performs environment-consumer secret resolution at test
time; access is authorized per binding exactly as at run time, and the
audit consumer is the environment (as before for adapter-config
resolution).
- Enabling the claude-local project in CI adds about 2 seconds of vitest
wall time to the general workspaces group and could surface future
regressions in that package — which is the point.

## Model Used

Claude Fable 5 (`claude-fable-5`), extended thinking enabled, agentic
tool use via Claude Code (CLI).

## Checklist

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

> - Paperclip is the open source app people use to manage AI agents for
work
> - The codex-local adapter runs Codex agents through the ACP lane and
offers a "Test" button on the agent configuration page to validate the
environment
> - The environment test used its own ad-hoc credential probe, while
real dispatch uses the shared `evaluateCodexCredentialReadiness`
predicate in `codex-home.ts`
> - The two paths disagreed: a user with valid Codex subscription auth
in the shared, server-visible Codex home still saw "No Codex ACP
credentials were detected"
> - The old warning also suggested `codex login` without explaining that
a `/login` in a separate Codex or chat session does not authenticate the
Paperclip server process
> - This pull request makes `testCodexAcpEnvironment` use the same
shared readiness predicate as real dispatch and rewords the warning to
name the server credential boundary
> - The benefit is that the Test button now agrees with what dispatch
will actually do, and the warning tells the user exactly which process
needs the credentials

## Linked Issues or Issue Description

No public GitHub issue exists for this bug. Related credential-handling
work, not duplicates: Refs #10160 (classifies OpenAI invalid-key 401s at
dispatch time) and Refs #9598 (classifies Codex refresh auth failures).
Both cover dispatch-time failures; this PR fixes the pre-dispatch
environment test.

Description follows the bug report template:

**What happened?**

A user configured a Codex ACP agent and had already authenticated Codex
(subscription auth present in the shared Codex home visible to the
Paperclip server). Clicking "Test" on the agent configuration page still
reported:

`warn: No Codex ACP credentials were detected. Hint: Set OPENAI_API_KEY
or run codex login before starting a Codex ACP agent.`

**Expected behavior**

The environment test should detect the same credentials that real agent
dispatch would use. When shared managed Codex auth is available, the
test should pass with an informational check instead of warning. When
credentials really are missing, the warning should explain that the
Paperclip server process is the one that needs them.

**Steps to reproduce**

1. Run the Paperclip server as an OS user whose shared Codex home
contains valid subscription `auth.json` (no `OPENAI_API_KEY` in the
adapter env or server env).
2. Configure an agent with the codex-local adapter using the ACP engine.
3. Click "Test" on the agent configuration page.
4. Observe the `codex_acp_credentials_missing` warning even though
dispatch would succeed.

**Agent adapter(s) involved**

Codex

**Additional context**

The confusion was amplified by the hint: users had run `/login` in a
Codex chat session and assumed the server was authenticated. That login
lives in a different process and home directory, so the server never saw
it.

## What Changed

- `testCodexAcpEnvironment`
(packages/adapters/codex-local/src/server/acp.ts) now calls the shared
`evaluateCodexCredentialReadiness` predicate from `codex-home.ts`
instead of a local ad-hoc `hasCodexNativeCredentials` probe, so the Test
button and real dispatch agree.
- An explicit empty `OPENAI_API_KEY` in the adapter config env no longer
falls through to the server environment key.
- An externally managed `CODEX_HOME` override is now reported as its own
informational check (`codex_acp_external_home_configured`).
- The `codex_acp_credentials_missing` warning now says the credentials
must be visible to the Paperclip server, and the hint explains that a
`/login` in a separate Codex or chat session does not authenticate the
server.
- Removed the now-unused `hasCodexNativeCredentials` helper.
- Added two regression tests: shared managed Codex auth is detected (no
false warning), and the missing-credentials warning carries the new
server-boundary wording.

## Verification

- `pnpm --filter @paperclip/adapter-codex-local test --
src/server/acp.test.ts` — the two new tests cover the shared-home
detection branch and the new warning wording; the existing ACP lane
tests cover the API-key and remote-target branches.
- Manual: with subscription auth in the server-visible shared Codex home
and no `OPENAI_API_KEY`, the agent configuration Test now reports
`codex_acp_native_auth_detected` (info) instead of
`codex_acp_credentials_missing` (warn).

## Risks

- Low risk. The change only affects the environment test path, not
dispatch. The readiness predicate is the same one dispatch already uses,
so drift between the two paths is now structurally prevented.
- Behavioral shift: an explicit empty adapter `OPENAI_API_KEY` no longer
silently falls back to the server env key in the test result. This
matches dispatch behavior and is intentional.

## Model Used

- Implementation authored by OpenAI Codex (gpt-5.5) running through the
Codex ACP lane with tool use.
- PR preparation, rebase onto master, and review fix-up by Anthropic
Claude (Claude Code CLI agent, 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
- [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: Cody <noreply@paperclip.ing>
2026-08-02 16:55:53 -07:00
Devin Foley ee9d907d01
fix(codex): do not inject a duplicate --skip-git-repo-check for sandbox runs (#10595)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - A Codex agent runs `codex exec`, and the adapter assembles its
argument vector from the agent's config plus execution-context options
> - For sandbox execution the adapter injects `--skip-git-repo-check`,
because a headless remote workspace has no git trust prompt to answer
> - The adapter also appends the operator's `extraArgs` verbatim, so an
agent that already lists `--skip-git-repo-check` in its config gets the
flag twice on a sandbox run
> - `codex exec` rejects a repeated `--skip-git-repo-check` and exits
with code 2, which the adapter surfaces as `adapter_failed` before any
work runs
> - This pull request skips the sandbox injection when the operator's
args already carry the flag
> - The benefit is that a common, harmless-looking config no longer
crashes every sandbox run

## Linked Issues or Issue Description

**What happened?**

A `codex_local` agent configured with `extraArgs:
["--skip-git-repo-check"]` fails on every sandbox run:

```
error: the argument '--skip-git-repo-check' cannot be used multiple times

Usage: codex exec [OPTIONS] [PROMPT]
```

The adapter reports `stopReason: "adapter_failed"` (Codex exited with
code 2). The flag appears twice in the argv: once injected by the
adapter for sandbox execution, once from the operator's `extraArgs`.

**Steps to reproduce**

1. Configure a `codex_local` agent with `extraArgs:
["--skip-git-repo-check"]` (or the legacy `args` field).
2. Point it at a sandbox environment.
3. Start a run — `codex exec` aborts immediately on the duplicate flag.

**Expected behavior**

The run launches with a single `--skip-git-repo-check`. An operator
listing the flag the adapter already injects should be a no-op, not a
hard failure.

**Paperclip version**

Current `master`.

**Deployment mode**

Any deployment running Codex agents in sandbox environments.

## What Changed

- `buildCodexExecArgs` no longer pushes the sandbox
`--skip-git-repo-check` when the resolved args (`extraArgs`, or the
legacy `args` fallback) already contain it. The operator's copy stands;
the argv carries the flag exactly once. Non-sandbox runs and configs
without the flag are unchanged.

## Verification

- `cd packages/adapters/codex-local && pnpm vitest run
src/server/codex-args.test.ts` — new cases: `extraArgs` already carrying
the flag (single occurrence), the legacy `args` field carrying it
(single occurrence), and the operator's flag preserved when the sandbox
injection is not requested. Existing "adds --skip-git-repo-check when
requested" case unchanged.
- `cd packages/adapters/codex-local && pnpm vitest run` — full package
suite (218 tests).
- `pnpm run typecheck` in the package.

## Risks

- Low. The change only suppresses a duplicate of a single, idempotent
flag; it never removes an operator-supplied argument and never adds one
that was not already going to be present.

## Model Used

Claude Fable 5 (`claude-fable-5`, Anthropic) via Claude Code — extended
thinking, agentic tool use (file edits, vitest/tsc runs). No other
models involved.

## Checklist

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

> - Paperclip is the open source app people use to manage AI agents for
work
> - Codex agents can run inside sandbox environments, and operators can
bake a Codex login into the sandbox image during interactive image setup
> - Two credential gates (the control plane's pre-dispatch
configuration-incomplete gate and the adapter's execute-time fail-fast)
required host-side Codex credentials — a usable `auth.json` in the
managed home or a configured `OPENAI_API_KEY` — regardless of where the
run executes
> - On managed cloud hosts a local Codex login never exists, so every
sandbox run of a Codex agent failed immediately with "configuration
incomplete: no Codex credentials available for managed home …", even
though the adapter's inbound auth merge already supports the image-login
case end to end
> - This pull request makes the execute-time gate probe the sandbox for
its own `~/.codex/auth.json` before failing, and exempts
sandbox-destined runs from the pre-dispatch host check
> - The benefit is that a sandbox image signed in to Codex is a
first-class credential source, matching what the auth-merge,
precedence-warning, and copy-back machinery were already built for

## Linked Issues or Issue Description

**What happened?**

Running a `codex_local` agent in a sandbox environment whose image
carries a Codex login failed instantly with `configuration incomplete:
no Codex credentials available for managed home "…/codex-home". Sign in
to Codex on the host with a ChatGPT subscription, or bind a per-agent
OPENAI_API_KEY secret for this agent.` The host has no Codex login and
never will on a managed cloud deployment; the sandbox's own login was
never consulted.

**Steps to reproduce**

1. Configure a sandbox environment and capture a custom image after
signing in to Codex inside the interactive image setup.
2. Create a `codex_local` agent that uses that environment, on a host
with no Codex login and no `OPENAI_API_KEY` bound.
3. Start a run: it fails pre-dispatch with the configuration-incomplete
blocker above.

**Expected behavior**

The run launches and Codex authenticates with the sandbox image's own
login, the same way the adapter's host↔sandbox auth merge already keeps
the sandbox credential when the host ships none. A run should only fail
fast when neither the host, a bound `OPENAI_API_KEY`, nor the sandbox
has credentials.

**Paperclip version**

Current `master` (cloud image deployments).

**Deployment mode**

Managed cloud stacks (any deployment where the server host has no local
Codex login).

## What Changed

- Extracted the adapter's execute-time gate into
`assertCodexCredentialsLaunchable`: when host readiness fails and the
target is a sandbox, it probes `~/.codex/auth.json` in the sandbox (same
command the auth-precedence warning uses) and proceeds with a log line
naming the credential source; when the sandbox has no login either, the
error now names all three remediation options (sandbox image sign-in,
per-agent `OPENAI_API_KEY`, host sign-in). Non-sandbox targets keep
today's strict behavior byte-for-byte.
- The control plane's pre-dispatch gate in
`resolveExecutionRunAdapterConfig` now takes the selected environment's
driver and skips the host-credential check for sandbox-destined runs —
only the adapter can probe the sandbox once it is up, so the
execute-time gate is the authority there. Non-sandbox runs keep the
early, well-attributed configuration-incomplete blocker.
- The codex Test flow needed no change: it already seeds host
credentials only when they exist and otherwise leaves the sandbox's
`CODEX_HOME` alone; this aligns the run path with it.

## Verification

- `cd packages/adapters/codex-local && pnpm vitest run` — 210 tests,
including new gate cases: sandbox login present (proceeds + logs
source), sandbox and host both credential-less (fails with the extended
message), non-sandbox target (strict host requirement kept, no sandbox
probe), per-agent API key (no probe at all).
- `cd server && pnpm vitest run
src/__tests__/heartbeat-project-env.test.ts
src/__tests__/codex-local-adapter-environment.test.ts` — includes the
new sandbox-exemption case next to the existing blocker tests.
- `pnpm run typecheck` in `server` and `packages/adapters/codex-local`.

## Risks

- Sandbox-destined misconfigurations (no credentials anywhere) now
surface at adapter execute time instead of pre-dispatch, so they read as
an adapter failure with a precise message rather than a
configuration-incomplete blocker. The trade-off is deliberate: the
sandbox must be up to know whether credentials exist, and the failure
message names the exact remediations.
- The sandbox probe adds one short (5s-capped) shell command to sandbox
runs whose host has no credentials; runs with host credentials or a
bound key are untouched.
- Self-hosted behavior is unchanged for local and SSH targets.

## Model Used

Claude Fable 5 (`claude-fable-5`, Anthropic) via Claude Code — extended
thinking, agentic tool use (file edits, vitest/tsc runs). No other
models involved.

## Checklist

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

> - Paperclip is the open source app people use to manage AI agents for
work
> - Agents pick their model from a dropdown in agent config, populated
per-adapter by `listAdapterModels()` → each adapter's live provider
catalog merged over a static fallback list
> - For `claude_local`, newer model ids only reach the dropdown via the
live Anthropic `/v1/models` fetch, which needs a server
`ANTHROPIC_API_KEY`, a <5s round-trip, non-Bedrock mode, and account
entitlement; on any miss it silently falls back to the static `models`
array
> - Claude Sonnet 5 (`claude-sonnet-5`) is a current flagship but was
absent from that static fallback, so it appeared only when live
discovery happened to succeed — i.e. "the newest model doesn't
consistently show up"
> - This pull request adds `claude-sonnet-5` to the `claude_local`
static model list so it is selectable regardless of the live-discovery
path
> - The benefit is a consistent, reliable dropdown that no longer
depends on a flaky live fetch to surface a shipped flagship model

## Linked Issues or Issue Description

No public GitHub issue. The bug is described inline following the
bug-report template:

**What happened**
The `claude_local` agent-config model dropdown intermittently omitted
Claude Sonnet 5. `claude-sonnet-5` was missing from the adapter's static
fallback `models` array (`packages/adapters/claude-local/src/index.ts`),
so it only surfaced when the live Anthropic `/v1/models` discovery
happened to succeed.

**Expected behavior**
Claude Sonnet 5 is a shipped flagship model and should always be
selectable in the dropdown, independent of whether live discovery
succeeds.

**Steps to reproduce**
1. Run the server without a working live Anthropic `/v1/models` path (no
`ANTHROPIC_API_KEY`, Bedrock mode, a discovery timeout, or a cache
miss).
2. Open agent config for a `claude_local` agent and inspect the model
dropdown.
3. Observe that `claude-sonnet-5` is absent because the static fallback
list omitted it.

**Deployment mode**
Self-hosted / local adapter (`claude_local`); the server process reads
`ANTHROPIC_API_KEY` from its environment.

## What Changed

- Added `{ id: "claude-sonnet-5", label: "Claude Sonnet 5" }` to the
`claude_local` static `models` fallback, immediately after
`claude-opus-4-8` (so Opus 4.8 stays the default first option).
- Added an explicit regression assertion in
`server/src/__tests__/adapter-models.test.ts` that `claude-sonnet-5` is
present in the `claude_local` fallback when live discovery is
unavailable.

## Verification

- `pnpm -C server exec vitest run src/__tests__/adapter-models.test.ts
-t "claude fallback"` — **passes** (the new `claude-sonnet-5` assertion
included).
- Reviewed the consuming tests: the fallback test also asserts
`models[0]?.id === "claude-opus-4-8"` (still index 0 — Sonnet 5 is index
1, unaffected); `adapter-registry.test.ts` reads `builtIn?.models`
dynamically, so no exact-array snapshot breaks.
- Change is a single static-data addition plus a test assertion; no
control-flow change.

## Risks

- Low risk. Pure additive change to a fallback list; no control-flow
change. Worst case is an id that a given account isn't entitled to,
which the existing "current"/manual-model UI paths already tolerate.

## Model Used

Claude (Anthropic), model id `claude-opus-4-8` (Opus 4.8), extended
thinking + tool use, run as the Paperclip CTO agent.

## Checklist

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

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-07-31 13:15:42 -05:00
Noah Kellner bd53b99686
feat(gemini-local): export detectGeminiQuotaExhausted for plugin adapter reuse (#3416)
## Thinking Path

> - Paperclip orchestrates AI agents via pluggable server-side adapters,
one per provider / CLI backend
> - Each adapter package exposes a server entry point
(`@paperclipai/adapter-<name>/server`) that downstream consumers —
including plugin adapters that wrap or extend the stock behavior —
re-use for helper functions
> - `gemini-local`'s server entry re-exports a curated set of parse
helpers from `./parse.js` (`parseGeminiJsonl`,
`isGeminiUnknownSessionError`, `describeGeminiFailure`,
`detectGeminiAuthRequired`, `isGeminiTurnLimitResult`) so consumers can
classify provider output without reaching into the package's internals
> - `detectGeminiQuotaExhausted` lives in the same `parse.ts` file next
to `detectGeminiAuthRequired`, is defined with `export function`, and is
the package's single source of truth for "is this output a Gemini quota
hit?" — but it is missing from the entry-point re-export block
> - As a result, any consumer that wants to classify quota exhaustion
either has to deep-import from `./server/parse.js` (brittle against
future `exports`-field changes) or reimplement the regex locally (drift
risk against the authoritative heuristic)
> - This pull request adds `detectGeminiQuotaExhausted` to the existing
re-export block, placed next to its thematic sibling
`detectGeminiAuthRequired`, with no other changes
> - The benefit is one extra supported public symbol on
`@paperclipai/adapter-gemini-local/server` — a purely additive ergonomic
improvement with no behavior change and no existing consumer impact

## What Changed

- `packages/adapters/gemini-local/src/server/index.ts`: added
`detectGeminiQuotaExhausted` to the `export { ... } from "./parse.js"`
block, inserted between `detectGeminiAuthRequired` and
`isGeminiTurnLimitResult` (thematic grouping — both `detect*` helpers)

## Verification

Local verification against the branch commit (base: `upstream/master` at
`b649bd45`):

```
$ pnpm --filter @paperclipai/adapter-gemini-local typecheck
> @paperclipai/adapter-gemini-local@0.3.1 typecheck
> tsc --noEmit
(exit 0)

$ pnpm --filter @paperclipai/adapter-gemini-local build
> @paperclipai/adapter-gemini-local@0.3.1 build
> tsc
(exit 0)

$ cd server && pnpm exec vitest run src/__tests__/gemini-local-execute.test.ts
 RUN  v3.2.4

 ✓ src/__tests__/gemini-local-execute.test.ts (3 tests) 1487ms
   ✓ gemini execute > passes prompt via --prompt and injects paperclip env vars
   ✓ gemini execute > always passes --approval-mode yolo
   ✓ gemini execute > uses a compact wake delta instead of the full heartbeat prompt when resuming a session

 Test Files  1 passed (1)
      Tests  3 passed (3)
```

Existing-consumer check — all references to `detectGeminiQuotaExhausted`
anywhere in the tree:

```
packages/adapters/gemini-local/src/server/index.ts:9    (this PR's new re-export)
packages/adapters/gemini-local/src/server/parse.ts:253  (the definition)
packages/adapters/gemini-local/src/server/test.ts:19    (intra-package import from "./parse.js")
packages/adapters/gemini-local/src/server/test.ts:174   (intra-package usage)
```

No cross-package consumer references the symbol today, so the new
re-export cannot break any existing import. It is strictly additive to
the public surface of `@paperclipai/adapter-gemini-local/server`.

## Risks

None. Purely additive re-export of a symbol that is already a named
export on `./parse.ts`. The clean-success path, failure paths, and all
other adapter behavior are untouched. No existing consumer is affected.

## Model Used

- **Provider**: Anthropic
- **Model**: Claude Opus 4.6 (1M context)
- **Interface**: Claude Code CLI
- **Role**: Upstream state verification (grep + diff against current
master), PR drafting against the `CONTRIBUTING.md` template, local
typecheck / build / test execution
- **Reasoning Mode**: Extended thinking enabled
- **Human oversight**: Noah Kellner reviewed the one-line re-export
addition and approved submission

## 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 run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] If this change affects the UI, I have included before/after
screenshots
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] I will address all Greptile and reviewer comments before
requesting merge

Co-authored-by: Noah Kellner <noah.kellner@xenoscloud.com>
2026-07-31 13:00:26 -05:00
Dotta 170c1e5adb
fix(claude-local): trust Paperclip URLs in allowlist sandbox (#10438)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - Local adapters can confine agent processes with filesystem and
network sandbox policies
> - Allowlist confinement must still let an agent reach Paperclip's own
control plane and managed MCP servers
> - The Codex local adapter already marks those runtime-owned endpoints
as trusted, but the Claude local adapter did not
> - As a result, allowlisted Claude runs could not call their own
Paperclip API unless operators duplicated runtime URLs manually
> - This pull request mirrors the trusted-URL wiring in the Claude local
adapter and adds a regression test at the process-execution boundary
> - The benefit is that confined Claude agents retain their required
control-plane access without broadening the operator-managed network
allowlist

## Linked Issues or Issue Description

Refs #447

No exact public issue was found. The underlying bug is:

- **Observed:** with `claude_local` configured for local-process
`networkScope: "allowlist"`, the sandbox options omitted the
runtime-owned Paperclip API and MCP server URLs. Requests to those
endpoints could therefore be denied by confinement.
- **Expected:** Paperclip's own API URL and managed MCP server URLs are
passed as trusted sandbox targets, matching `codex_local` behavior.
- **Steps to reproduce:** configure a local Claude agent with allowlist
network confinement, omit the runtime Paperclip API URL from the
operator allowlist, and have the agent call its injected
`PAPERCLIP_API_URL`.
- **Version:** `ca92f727c5` (`origin/master` at branch creation).
- **Deployment mode:** local-process sandbox confinement in a local
deployment.

## What Changed

- Added the injected Paperclip API URL and runtime MCP server URLs to
`claude_local` sandbox `networkTrustedUrls`, filtering empty values.
- Added a unit test proving allowlist sandbox construction trusts
`PAPERCLIP_API_URL`.

## Verification

- `pnpm exec vitest run
packages/adapters/claude-local/src/server/execute.acp-fallback.test.ts`
- `pnpm --filter @paperclipai/adapter-claude-local typecheck`

## Risks

- Low risk. The change only affects confined local Claude processes and
trusts runtime-owned endpoints already injected by Paperclip.
- Operator-configured `networkAllowlist` behavior is unchanged; the
added URLs use the sandbox's separate trusted-target path.

> 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 (exact serving snapshot and context-window
size are not exposed), with reasoning, repository inspection, shell tool
use, code editing, and test execution.

## Checklist

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

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-07-29 13:23:09 -05:00
dependabot[bot] 5b34d265a4
build(deps): bump @agentclientprotocol/claude-agent-acp from 0.59.0 to 0.63.0 (#10302)
Bumps
[@agentclientprotocol/claude-agent-acp](https://github.com/agentclientprotocol/claude-agent-acp)
from 0.59.0 to 0.63.0.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/agentclientprotocol/claude-agent-acp/releases">@​agentclientprotocol/claude-agent-acp's
releases</a>.</em></p>
<blockquote>
<h2>v0.63.0</h2>
<h2><a
href="https://github.com/agentclientprotocol/claude-agent-acp/compare/v0.62.0...v0.63.0">0.63.0</a>
(2026-07-27)</h2>
<h3>Features</h3>
<ul>
<li>Update to claude agent sdk v0.3.220 (<a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/921">#921</a>)
(<a
href="4c7b897183">4c7b897</a>)</li>
</ul>
<h3>Bug Fixes</h3>
<ul>
<li>Only resolve a denied tool call the client was told about (<a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/923">#923</a>)
(<a
href="8f67b6a92b">8f67b6a</a>),
closes <a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/918">#918</a></li>
<li>Report tool_progress heartbeats against the tool call they describe
(<a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/916">#916</a>)
(<a
href="5559ba890c">5559ba8</a>)</li>
<li><strong>tools:</strong> key Bash terminal metas off the announced
tool_use id (<a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/917">#917</a>)
(<a
href="d0604140f9">d060414</a>)</li>
</ul>
<h2>v0.62.0</h2>
<h2><a
href="https://github.com/agentclientprotocol/claude-agent-acp/compare/v0.61.0...v0.62.0">0.62.0</a>
(2026-07-24)</h2>
<h3>Features</h3>
<ul>
<li><strong>deps:</strong> Bump <code>@​hono/node-server</code> from
1.19.14 to 1.19.15 (<a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/908">#908</a>)
(<a
href="51936049e1">5193604</a>)</li>
<li><strong>deps:</strong> Bump media-typer from 1.1.0 to 1.1.1 (<a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/909">#909</a>)
(<a
href="5d35001563">5d35001</a>)</li>
<li><strong>deps:</strong> Bump the minor group with 2 updates (<a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/900">#900</a>)
(<a
href="809d41c6b7">809d41c</a>)</li>
<li><strong>deps:</strong> Bump the minor group with 2 updates (<a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/907">#907</a>)
(<a
href="14d06273c0">14d0627</a>)</li>
<li>Update to claude-agent-sdk 0.3.218 (<a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/904">#904</a>)
(<a
href="8cbaf97254">8cbaf97</a>)</li>
</ul>
<h2>v0.61.0</h2>
<h2><a
href="https://github.com/agentclientprotocol/claude-agent-acp/compare/v0.60.0...v0.61.0">0.61.0</a>
(2026-07-22)</h2>
<h3>Features</h3>
<ul>
<li><strong>deps:</strong> Bump actions/setup-node from 6.4.0 to 7.0.0
(<a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/897">#897</a>)
(<a
href="d9bd36d8b0">d9bd36d</a>)</li>
<li><strong>deps:</strong> Update to
<code>@​anthropic-ai/claude-agent-sdk</code> 0.3.217 (<a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/899">#899</a>)
(<a
href="edf3af043b">edf3af0</a>)</li>
</ul>
<h2>v0.60.0</h2>
<h2><a
href="https://github.com/agentclientprotocol/claude-agent-acp/compare/v0.59.0...v0.60.0">0.60.0</a>
(2026-07-20)</h2>
<h3>Features</h3>
<ul>
<li><strong>deps:</strong> Update to claude-agent-sdk 0.3.215 (<a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/890">#890</a>)
(<a
href="92548f0435">92548f0</a>)</li>
<li>implement configurable LLM providers (<a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/853">#853</a>)
(<a
href="82cd692e50">82cd692</a>)</li>
</ul>
<h3>Bug Fixes</h3>
<ul>
<li>parse Agent/Task trailers without regex (<a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/879">#879</a>)
(<a
href="06c3d7bdbd">06c3d7b</a>)</li>
<li>remove ~15s stall on session/new and model switch by seeding the
context window synchronously (<a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/894">#894</a>)
(<a
href="ff9b96d462">ff9b96d</a>)</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/agentclientprotocol/claude-agent-acp/blob/main/CHANGELOG.md">@​agentclientprotocol/claude-agent-acp's
changelog</a>.</em></p>
<blockquote>
<h2><a
href="https://github.com/agentclientprotocol/claude-agent-acp/compare/v0.62.0...v0.63.0">0.63.0</a>
(2026-07-27)</h2>
<h3>Features</h3>
<ul>
<li>Update to claude agent sdk v0.3.220 (<a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/921">#921</a>)
(<a
href="4c7b897183">4c7b897</a>)</li>
</ul>
<h3>Bug Fixes</h3>
<ul>
<li>Only resolve a denied tool call the client was told about (<a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/923">#923</a>)
(<a
href="8f67b6a92b">8f67b6a</a>),
closes <a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/918">#918</a></li>
<li>Report tool_progress heartbeats against the tool call they describe
(<a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/916">#916</a>)
(<a
href="5559ba890c">5559ba8</a>)</li>
<li><strong>tools:</strong> key Bash terminal metas off the announced
tool_use id (<a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/917">#917</a>)
(<a
href="d0604140f9">d060414</a>)</li>
</ul>
<h2><a
href="https://github.com/agentclientprotocol/claude-agent-acp/compare/v0.61.0...v0.62.0">0.62.0</a>
(2026-07-24)</h2>
<h3>Features</h3>
<ul>
<li><strong>deps:</strong> Bump <code>@​hono/node-server</code> from
1.19.14 to 1.19.15 (<a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/908">#908</a>)
(<a
href="51936049e1">5193604</a>)</li>
<li><strong>deps:</strong> Bump media-typer from 1.1.0 to 1.1.1 (<a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/909">#909</a>)
(<a
href="5d35001563">5d35001</a>)</li>
<li><strong>deps:</strong> Bump the minor group with 2 updates (<a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/900">#900</a>)
(<a
href="809d41c6b7">809d41c</a>)</li>
<li><strong>deps:</strong> Bump the minor group with 2 updates (<a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/907">#907</a>)
(<a
href="14d06273c0">14d0627</a>)</li>
<li>Update to claude-agent-sdk 0.3.218 (<a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/904">#904</a>)
(<a
href="8cbaf97254">8cbaf97</a>)</li>
</ul>
<h2><a
href="https://github.com/agentclientprotocol/claude-agent-acp/compare/v0.60.0...v0.61.0">0.61.0</a>
(2026-07-22)</h2>
<h3>Features</h3>
<ul>
<li><strong>deps:</strong> Bump actions/setup-node from 6.4.0 to 7.0.0
(<a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/897">#897</a>)
(<a
href="d9bd36d8b0">d9bd36d</a>)</li>
<li><strong>deps:</strong> Update to
<code>@​anthropic-ai/claude-agent-sdk</code> 0.3.217 (<a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/899">#899</a>)
(<a
href="edf3af043b">edf3af0</a>)</li>
</ul>
<h2><a
href="https://github.com/agentclientprotocol/claude-agent-acp/compare/v0.59.0...v0.60.0">0.60.0</a>
(2026-07-20)</h2>
<h3>Features</h3>
<ul>
<li><strong>deps:</strong> Update to claude-agent-sdk 0.3.215 (<a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/890">#890</a>)
(<a
href="92548f0435">92548f0</a>)</li>
<li>implement configurable LLM providers (<a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/853">#853</a>)
(<a
href="82cd692e50">82cd692</a>)</li>
</ul>
<h3>Bug Fixes</h3>
<ul>
<li>parse Agent/Task trailers without regex (<a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/879">#879</a>)
(<a
href="06c3d7bdbd">06c3d7b</a>)</li>
<li>remove ~15s stall on session/new and model switch by seeding the
context window synchronously (<a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/894">#894</a>)
(<a
href="ff9b96d462">ff9b96d</a>)</li>
<li>Silence missing PostToolUse callbacks (<a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/895">#895</a>)
(<a
href="1887ada215">1887ada</a>),
closes <a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/889">#889</a></li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="15979bba79"><code>15979bb</code></a>
chore(main): release 0.63.0 (<a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/922">#922</a>)</li>
<li><a
href="8f67b6a92b"><code>8f67b6a</code></a>
fix: Only resolve a denied tool call the client was told about (<a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/923">#923</a>)</li>
<li><a
href="5559ba890c"><code>5559ba8</code></a>
fix: Report tool_progress heartbeats against the tool call they describe
(<a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/916">#916</a>)</li>
<li><a
href="d0604140f9"><code>d060414</code></a>
fix(tools): key Bash terminal metas off the announced tool_use id (<a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/917">#917</a>)</li>
<li><a
href="4c7b897183"><code>4c7b897</code></a>
feat: Update to claude agent sdk v0.3.220 (<a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/921">#921</a>)</li>
<li><a
href="8663170f18"><code>8663170</code></a>
Add structured Bash titles and nested subagent transcripts (<a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/881">#881</a>)</li>
<li><a
href="53a0c36ce3"><code>53a0c36</code></a>
chore(main): release 0.62.0 (<a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/901">#901</a>)</li>
<li><a
href="c91f943f86"><code>c91f943</code></a>
<code>@​anthropic-ai/claude-agent-sdk</code> 0.3.218 -&gt; 0.3.219 (<a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/912">#912</a>)</li>
<li><a
href="5d35001563"><code>5d35001</code></a>
feat(deps): Bump media-typer from 1.1.0 to 1.1.1 (<a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/909">#909</a>)</li>
<li><a
href="51936049e1"><code>5193604</code></a>
feat(deps): Bump <code>@​hono/node-server</code> from 1.19.14 to 1.19.15
(<a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/908">#908</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/agentclientprotocol/claude-agent-acp/compare/v0.59.0...v0.63.0">compare
view</a></li>
</ul>
</details>
<br />

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-29 09:33:08 -07:00
Michael Nguyen 4eace88f6b
feat(adapter-claude): add Claude Opus 5 to the static model fallback (#10327)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - Agents pick their model from a dropdown in agent config, populated
per-adapter by `listAdapterModels()` → each adapter's live provider
catalog merged over a static fallback list
> - For `claude_local`, newer model ids only reach the dropdown via the
live Anthropic `/v1/models` fetch, which needs a server
`ANTHROPIC_API_KEY`, a <5s round-trip, non-Bedrock mode, and account
entitlement; on any miss it silently falls back to the static `models`
array
> - Claude Opus 5 (`claude-opus-5`) is generally available — Anthropic
lists it as the recommended model for complex agentic coding and
enterprise work — but it was absent from that static fallback, so it
appeared only when live discovery happened to succeed
> - This pull request adds `claude-opus-5` to the `claude_local` static
model list so it is selectable regardless of the live-discovery path
> - The benefit is a consistent, reliable dropdown that surfaces the
current GA Opus flagship without depending on a flaky live fetch

## Linked Issues or Issue Description

No public GitHub issue. The bug is described inline following the
bug-report template:

**What happened**
The `claude_local` agent-config model dropdown omitted Claude Opus 5.
`claude-opus-5` was missing from the adapter's static fallback `models`
array (`packages/adapters/claude-local/src/index.ts`), so it only
surfaced when the live Anthropic `/v1/models` discovery happened to
succeed.

**Expected behavior**
Claude Opus 5 is a shipped, generally-available flagship (Anthropic's
recommended model for agentic coding) and should always be selectable in
the dropdown, independent of whether live discovery succeeds.

**Steps to reproduce**
1. Run the server without a working live Anthropic `/v1/models` path (no
`ANTHROPIC_API_KEY`, Bedrock mode, a discovery timeout, or a cache
miss).
2. Open agent config for a `claude_local` agent and inspect the model
dropdown.
3. Observe that `claude-opus-5` is absent because the static fallback
list omitted it.

**Deployment mode**
Self-hosted / local adapter (`claude_local`); the server process reads
`ANTHROPIC_API_KEY` from its environment.

## What Changed

- Added `{ id: "claude-opus-5", label: "Claude Opus 5" }` to the
`claude_local` static `models` fallback. Placed after the current
5-family entries and above the legacy `claude-opus-4-7`, so
`claude-opus-4-8` stays the default (index 0) option.
- Added an explicit regression assertion in
`server/src/__tests__/adapter-models.test.ts` that `claude-opus-5` is
present in the `claude_local` fallback when live discovery is
unavailable.

## Verification

- `pnpm -C server exec vitest run src/__tests__/adapter-models.test.ts`
— **17/17 pass**, including the new `claude-opus-5` assertion and the
existing `models[0] === "claude-opus-4-8"` default invariant (unaffected
— Opus 5 is inserted lower in the list).
- Change is a single static-data addition plus a test assertion; no
control-flow change.

## Risks

- Low risk. Pure additive change to a fallback list; no control-flow
change. Worst case is an id a given account isn't entitled to, which the
existing "current"/manual-model UI paths already tolerate.
- Note for reviewers: a sibling PR adds `claude-sonnet-5` to the same
static array (near `claude-opus-4-8`). Both are complementary "refresh
the static list to current GA" changes; whichever merges second may need
a one-line merge resolution in
`packages/adapters/claude-local/src/index.ts` and the matching test
assertion block.

## Model Used

Claude (Anthropic), model id `claude-opus-4-8` (Opus 4.8), extended
thinking + tool use, run as the Paperclip CTO agent.

## Checklist

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

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-07-28 16:25:25 -05:00
Dotta 487e33b8b6
fix(codex-local): resolve GPT-5.6 model metadata at source (#9780)
## Thinking Path

> - Paperclip is the open source control plane people use to manage AI
agents for work
> - The `codex_local` adapter runs OpenAI's Codex CLI through direct CLI
and ACP execution lanes
> - The adapter defaulted to the bare `gpt-5.6` alias while the bundled
ACP Codex version lacked GPT-5.6-family metadata
> - Default and legacy-configured runs therefore emitted
fallback-metadata warnings and could use generic context limits
> - This pull request upgrades the bundled Codex ACP dependency, selects
the concrete `gpt-5.6-sol` model, and normalizes the legacy alias in
both execution lanes
> - The benefit is correct model metadata without hiding genuine stderr
or transcript warnings

## Linked Issues or Issue Description

Related public PRs: Refs #9342, Refs #9352, and Refs #9382. This PR is
narrower: it upgrades bundled Codex metadata and normalizes the legacy
bare alias in both execution lanes.

**Bug report**

### What happened

Default `codex_local` runs, and agents still configured with the bare
`gpt-5.6` model, print a model-metadata fallback warning and use generic
context-window limits.

Root cause: the ACP lane bundled a Codex release predating
GPT-5.6-family metadata, while Paperclip's default and advertised model
used the bare `gpt-5.6` alias for which Codex publishes no metadata.

### Expected behavior

A default Codex run resolves to a concrete model slug with published
metadata and does not emit a fallback-metadata warning.

### Deployment mode

Self-hosted/local `codex_local` adapter.

## What Changed

- Upgraded `@agentclientprotocol/codex-acp` from `^1.1.0` to `^1.1.4`
- Changed `DEFAULT_CODEX_LOCAL_MODEL` from `gpt-5.6` to `gpt-5.6-sol`
- Removed the bare alias from advertised models and listed concrete
GPT-5.6 Fast-mode variants
- Added `normalizeCodexModel()` and applied it in both CLI and ACP
execution lanes
- Updated adapter docs, Storybook fixtures, and regression tests
- Preserved warning visibility; no stderr, transcript, or log filtering
changed

## Verification

- `pnpm --filter @paperclipai/adapter-codex-local typecheck`
- `pnpm check:token-gates`
- `cd packages/adapters/codex-local && pnpm exec vitest run` — 205 tests
passed
- `cd server && pnpm exec vitest run
src/__tests__/adapter-models.test.ts` — 17 tests passed
- Confirmed the PR diff excludes `pnpm-lock.yaml` and
`.github/workflows/**` as required by repository policy
- Confirmed `.github/workflows/pr.yml` regenerates and uploads the PR
lockfile artifact before downstream `pnpm install --frozen-lockfile`
steps

## Risks

Low risk. The behavior change is scoped to `codex_local` model
selection. Existing concrete model IDs pass through unchanged; only the
legacy bare `gpt-5.6` alias is rewritten. Dependency resolution may
select a newer compatible `codex-acp` release within the declared range,
so CI remains the final compatibility gate.

> 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

- Original implementation: Anthropic Claude Opus 4.8 (`claude-opus-4-8`,
1M context, tool use and code execution)
- Conflict resolution and PR preparation: OpenAI GPT-5.5 (`gpt-5.5`,
Codex CLI coding agent, high-reasoning tool use and code execution;
host-managed 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)
- [ ] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
— branch name is fixed by the assigned execution workspace and cannot be
renamed in-place
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-07-28 16:15:08 -05:00
dependabot[bot] f9034ab3ca
build(deps-dev): bump @types/node from 22.19.21 to 22.20.1 (#10304)
Bumps
[@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node)
from 22.19.21 to 22.20.1.
<details>
<summary>Commits</summary>
<ul>
<li>See full diff in <a
href="https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node">compare
view</a></li>
</ul>
</details>
<br />

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-28 10:48:45 -07:00
dependabot[bot] 4881f548be
build(deps): bump @cursor/sdk from 1.0.19 to 1.0.24 (#10298)
Bumps [@cursor/sdk](https://github.com/cursor/cursor) from 1.0.19 to
1.0.24.
<details>
<summary>Commits</summary>
<ul>
<li>See full diff in <a
href="https://github.com/cursor/cursor/commits">compare view</a></li>
</ul>
</details>
<details>
<summary>Maintainer changes</summary>
<p>This version was pushed to npm by <a
href="https://www.npmjs.com/~luist18">luist18</a>, a new releaser for
<code>@​cursor/sdk</code> since your current version.</p>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=@cursor/sdk&package-manager=npm_and_yarn&previous-version=1.0.19&new-version=1.0.24)](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>
2026-07-28 10:03:36 -07:00
Nicky Leach 341993ebae
feat(sandbox-runtime): route all inbound staging through client.syncIn (Codex home -> native uploadFiles; delete usesCustomProvision gate) (#10354) 2026-07-28 07:22:18 -07:00
Dotta 1426494ab8
fix(agents): disable cheap model profiles by default (#10019)
## Thinking Path

> - Paperclip is the control plane people use to create and govern
AI-agent companies
> - Agent creation persists runtime configuration that controls which
model profiles future runs may select
> - Adapters can expose a `cheap` profile, and existing creation paths
implicitly left that profile available when operators made no choice
> - That made a newly created agent eligible for a lower-cost model
without an explicit operator opt-in
> - The UI also dropped an explicit opt-in when the operator selected
the adapter's default cheap model rather than a custom model ID
> - Codex additionally hardcoded `gpt-5.3-codex-spark` into its cheap
profile and static fallback model list, making Paperclip choose an
auth-dependent model rather than requiring an operator choice
> - This pull request makes new-agent creation disable an available
cheap profile by default while preserving explicit opt-in from the UI or
API
> - The Codex cheap profile now remains available for explicit
configuration but supplies no model default, so an unconfigured cheap
request stays on the primary model
> - The benefit is predictable model quality for new agents and an
intentional, auditable choice before lower-cost routing is enabled

## Linked Issues or Issue Description

**Problem**

New agents created with an adapter that exposes a `cheap` model profile
can inherit that profile without the operator explicitly enabling it. In
the UI, enabling the adapter-default cheap model is also omitted because
runtime configuration is only written when a custom model ID is present.

**Expected behavior**

- New agents default an available `cheap` model profile to `{ enabled:
false }` when the caller does not specify it.
- Explicit API configuration remains authoritative.
- UI opt-in persists even when the adapter default model is used.
- Codex does not advertise or automatically select
`gpt-5.3-codex-spark`; operators must explicitly configure any
lower-cost Codex model.

**Related public work**

- Refs #4881, which introduced cheap model profiles for local adapters.
- Supersedes the default-selection portions of #8032 and #10004 by
removing the Codex model default instead of replacing it with another
hardcoded model.

## What Changed

- Detect whether the selected adapter exposes a `cheap` model profile
during agent creation and hiring.
- Persist `runtimeConfig.modelProfiles.cheap.enabled = false` only when
the caller did not explicitly configure the profile.
- Preserve UI cheap-profile opt-in when using the adapter's default
model by writing an empty adapter config.
- Remove `gpt-5.3-codex-spark` from the Codex static model list.
- Keep the Codex `cheap` profile explicitly configurable while giving it
an empty adapter config, so Paperclip never chooses a cheap Codex model
automatically.
- Verify that a Codex cheap request without an explicit model leaves the
primary model unchanged.
- Extend server route and UI runtime-config tests for default-disable
and explicit-opt-in behavior.

## Verification

- `env -u PAPERCLIP_IN_WORKTREE -u PAPERCLIP_WORKTREE_NAME -u
PAPERCLIP_CONFIG -u PAPERCLIP_HOME -u PAPERCLIP_INSTANCE_ID -u
PAPERCLIP_CONTEXT pnpm exec vitest run
packages/adapters/codex-local/src/index.test.ts
packages/adapters/codex-local/src/server/codex-args.test.ts
server/src/__tests__/adapter-models.test.ts
server/src/__tests__/adapter-registry.test.ts
server/src/__tests__/heartbeat-model-profile.test.ts
server/src/__tests__/agent-permissions-routes.test.ts
ui/src/lib/new-agent-runtime-config.test.ts`
- Result: 7 test files passed, 105 tests passed.
- GitHub `Typecheck + Release Registry` check passed on the final head.
- `git diff --check public-gh/master...HEAD`

## Risks

- Low behavioral risk: only newly created or hired agents are
normalized; existing agents are unchanged.
- Explicit `cheap` profile settings remain untouched, including explicit
opt-in.
- Codex users who explicitly opt into the cheap lane must choose a
model; requests without a configured override intentionally continue on
the primary model.
- Adapter profile discovery is now awaited during creation, adding a
small amount of adapter metadata lookup work.
- The source branch name is automation-provided and retained as required
by the task, so it does not satisfy the preferred public branch naming
convention.

> 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.4` via Codex CLI, with reasoning, repository editing,
terminal execution, and GitHub/Paperclip tool access. The runtime did
not expose a 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
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-07-27 19:11:51 -05:00
Dotta 4e00818574
fix(runtime): support in-place workspace realization (#10230)
## Thinking Path

> - Paperclip is the control plane people use to coordinate AI agents
and their execution environments.
> - Environment realization decides where an agent runs and which
filesystem and toolchain are authoritative.
> - Copy-based realization is unsafe for container-anchored tasks
because absolute paths such as `/app` can point outside the synchronized
tree and task-specific binaries may be absent.
> - That mismatch can let an agent successfully verify work in a phantom
writable path while sync-back silently discards the result.
> - Existing task environments already provide the authoritative
filesystem and toolchain, so they should be executed in place rather
than copied.
> - Copy mode still needs explicit confinement rules so aliases target
the synchronized workspace and unsynchronized writable paths fail
visibly.
> - This pull request adds typed realization metadata, propagates the
authoritative root through orchestration, and teaches Codex to honor it.
> - The benefit is that container-anchored tasks operate on
verifier-visible state with the intended tools, while copy mode remains
safe and backward compatible.

## Linked Issues or Issue Description

No public GitHub issue exists for this defect.

GitHub duplicate searches for in-place execution, workspace realization,
and authoritative workspace roots found no related pull request to link.

### What happened?

Environment-backed agent runs were always realized through a copied
workspace. Tasks anchored to absolute container paths could therefore
write outside the synchronized tree, and task-provided toolchains were
unavailable in the copy. A run could report success even though
sync-back discarded its output.

### Expected behavior

Existing task environments should run against their real authoritative
root and toolchain. Copy-mode runs should map declared absolute aliases
into the synchronized tree and reject writable paths that cannot be
restored.

### Steps to reproduce

1. Run a Codex task environment whose required files live under `/app`
or `/workspace` and whose required binary exists only in the task
container.
2. Observe that copy realization changes the effective
filesystem/toolchain or permits writes outside the synchronized root.
3. Complete and verify the task inside the agent sandbox.
4. Observe that the verifier cannot see out-of-tree artifacts or that
task-specific commands were unavailable.

### Reproduction context

- Paperclip commit: `3a16b91217483d2c233926de5b7f7bc3a1077924`
- Deployment: built from source in a task-container execution
environment
- Adapter: Codex local
- Database: not database-related
- Access context: agent execution

## What Changed

- Added typed `copy | in_place` workspace-realization metadata,
authoritative roots, confined aliases, and outbound restore paths to
shared execution-target contracts.
- Selected in-place realization for existing task environments and
skipped archive prepare/restore when the authoritative environment is
used directly.
- Propagated the authoritative root into adapter context so Codex uses
it for cwd and `PAPERCLIP_WORKSPACE_*` semantics, including ACP
execution.
- Bound copy-mode aliases such as `/app` to the synchronized workspace
and rejected writable out-of-tree paths without explicit restore
mappings.
- Added focused regression coverage while preserving existing copy-mode
archive restore behavior.

## Verification

- `pnpm --filter @paperclipai/shared typecheck` — passed.
- `pnpm exec vitest run
packages/adapter-utils/src/local-process-sandbox.test.ts
packages/adapters/codex-local/src/server/acp.test.ts
packages/adapters/codex-local/src/server/execute.remote.test.ts
server/src/__tests__/environment-run-orchestrator.test.ts` — 48 passed,
4 skipped.
- `pnpm -r typecheck` — passed.
- `env -u AWS_ACCESS_KEY_ID -u AWS_SECRET_ACCESS_KEY -u
AWS_SESSION_TOKEN pnpm test:run` — passed across all general and
serialized Vitest shards.
- `pnpm build` — passed.
- Codex `k=1` acceptance run completed July 24, 2026 at 23:54:30 UTC
with 4 completed, 0 exceptions, and mean reward 1.0: `build-cython-ext`,
`openssl-selfsigned-cert`, `prove-plus-comm`, and `sqlite-db-truncate`
each received terminal grade 1.0 against real task-environment paths and
toolchains.

## Risks

- In-place mode deliberately exposes the authoritative task root to the
adapter; incorrect environment metadata could point execution at the
wrong root. Typed metadata and focused orchestration tests cover
selection and propagation.
- Copy-mode writable-path validation is stricter and may reject
previously accepted unsafe configurations. The rejection is intentional
and produces a visible error instead of silently losing output.
- The acceptance run is focused on four Codex task-environment
workloads, not a broad cross-adapter benchmark. Existing copy-mode
archive tests and the full repository suite remain green.

> 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 CLI coding agent; exact model ID and context-window size
were not exposed to this runtime. Capabilities used: extended reasoning,
repository editing, shell execution, test/build execution, Git, GitHub
CLI, and Paperclip API tool use.

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-07-25 08:29:26 -05:00
Dotta 665408c6d0
fix(codex): classify mid-turn harness crashes structurally as retriable infra (#10210)
## Thinking Path

> - Paperclip is the open source control plane people use to manage AI
agents and their work
> - Heartbeat execution relies on adapters distinguishing agent failures
from failures in the harness running beneath the agent
> - Codex MCP transport crashes can kill the CLI after the JSONL
protocol has started but before it emits a protocol-terminal event
> - Those interrupted streams were left unclassified, so the control
plane terminalized the heartbeat as `heartbeat_failed` / `agent_failure`
with no continuation
> - Agent-level failure is already expressible through the JSONL
protocol via an `error` event, `turn.failed`, or `turn.completed`, so an
interrupted nonzero exit can be classified structurally without
inspecting unstable error strings
> - This pull request reports that shape as `codex_harness_crash` in the
`transient_upstream` family and routes it through Paperclip's existing
bounded retry and recovery-continuation paths
> - The benefit is that transient Codex harness failures recover safely
without misclassifying quoted agent output or depending on
transport-specific wording

## Linked Issues or Issue Description

- **What happened:** Codex MCP transport failures, including rmcp worker
death, could terminate the CLI mid-turn after protocol output began but
before any terminal JSONL event. The run then became an unclassified
terminal heartbeat failure with `continuationCount: 0`; this occurred in
3 of 44 L3 Codex-lane trials during the associated benchmark
investigation.
- **Expected behavior:** a nonzero Codex exit after the protocol starts
but before an `error`, `turn.failed`, or `turn.completed` event should
be treated as a harness/infrastructure crash and enter the existing
bounded retry policy.
- **Why structural classification:** transport error strings vary, and
stdout may quote agent output that merely discusses network failures.
The protocol boundary identifies whether the agent itself produced a
terminal result without regex matching.
- **Recovery behavior:** `codex_harness_crash` maps to `errorFamily:
transient_upstream`, using the existing `same_session` →
`safer_invocation` → `fresh_session` ladder plus the
recovery-continuation transient-infrastructure path.
- Supersedes the regex-based approach in #10150, which is closed.

## What Changed

- Added protocol-state tracking that identifies a nonzero exit after
protocol start and before any protocol-terminal event as
`codex_harness_crash`.
- Propagated the structural classification as `transient_upstream`
through the Codex adapter.
- Added parse unit coverage, including a faithful crash-shaped stream,
without matching stderr transport strings.
- Added adapter execution coverage using a fake Codex process that emits
a protocol prefix and then dies with the observed rmcp stderr line.
- Added heartbeat bounded-retry coverage, including the `errorCode`-only
fallback, and recovery-continuation classification coverage.

## Verification

- `parse.test.ts` — 16 passed.
- `codex-local-execute.test.ts` — 16 passed.
- `heartbeat-retry-scheduling.test.ts` — 30 passed.
- `service.pause-durability.test.ts` — 6 passed.
- Server and Codex adapter TypeScript checks passed.
- The branch commit is unchanged from the tested and pushed `88f5464d40`
handoff.

## Risks

- Low risk: the classification requires a nonzero exit after protocol
start and before any protocol-terminal event, so normal agent-declared
failures and completed turns keep their existing behavior.
- The change intentionally broadens recovery for structurally
interrupted Codex runs; bounded retry limits still prevent indefinite
continuation loops.
- No schema, migration, public API, UI, lockfile, or workflow changes.

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

## Model Used

- OpenAI Codex coding agent. The exact runtime model ID and
context-window size were not exposed by the execution environment;
capabilities used for the implementation included repository analysis,
reasoning, code editing, and terminal-based test execution.

## Checklist

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

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-07-24 16:40:47 -05:00
Dotta b996b71a38
Deduplicate wake-payload issue descriptions and compact resume deltas (#10216)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - Heartbeat wake payloads and the task-context markdown are the two
channels that deliver an issue's brief into an agent's prompt
> - #10151 fixed wake-prompt-only adapter lanes waking without the issue
description by adding it to the structured wake payload
> - That left the description delivered twice per prompt on lanes that
also inject the task-context markdown, and re-delivered in full on every
resume wake, permanently bloating persistent-session context
> - This pull request makes the task markdown the single description
carrier on lanes that use it, and omits the description from
non-assignment resume deltas on all lanes while keeping it for
assignment-shaped and recovery wakes
> - The benefit is that every lane receives the brief exactly once when
it needs it, and long-lived sessions stop re-paying the full brief in
tokens on every wake

## Linked Issues or Issue Description

Refs #10151

Related prior work: #2883, #8402 (earlier description-delivery attempts
referenced by #10151). I searched the PR list for open work on
wake-payload description handling and found none besides the merged
#10151.

**Bug:** After #10151, adapters that inject the `Paperclip task context`
markdown (ACPX engine lanes, claude-local CLI, hermes server and
gateway) receive the issue description twice in a single prompt — once
in the wake prompt's `Issue description:` block and once in the task
markdown. Separately, resume deltas re-send the full description (up to
12k characters) on every wake even though the persistent session already
received it.

**Expected behavior:** The description appears exactly once per prompt
on every lane, and resume deltas only carry it when the resuming session
may not have seen the brief (assignment-shaped or recovery wakes),
leaving an explicit fetch breadcrumb otherwise.

**Reproduction:** Wake a claude-local or ACPX agent on an issue with a
description and inspect the assembled prompt: the description text
appears in both the wake-payload block and the task-context block. Wake
the same session again via a comment: the full description is present
again in the resume delta.

**Affected version:** Current `master` (with #10151 merged).

**Deployment mode:** Adapter-backed heartbeat execution, local and
sandboxed lanes.

## What Changed

- `renderPaperclipWakePrompt` accepts `suppressIssueDescription`; the
four task-markdown lanes pass it so the task markdown stays the single,
uncapped description carrier there.
- Non-assignment resume deltas omit the description and emit `- issue
description: omitted from this resume delta; fetch the issue if you need
the latest brief`. Assignment-shaped reasons (`issue_assigned`,
`issue_reopened_via_comment`, `issue_recovery_action_restored`,
`issue_tree_restored`) and recovery wakes still deliver the full brief.
- `buildPaperclipTaskMarkdown` gains `includeDescription`; the server
now also publishes `context.paperclipTaskMarkdownCompact` (description
stripped, directives and wake comment kept), and the new
`selectPaperclipTaskMarkdown` helper picks the right variant under the
same resume rules, falling back to the full markdown when no compact
variant exists (version skew safety).
- The wake prompt's description block now carries the same user-authored
trust framing the task markdown already had.

## Verification

- `npx vitest run packages/adapter-utils/src/server-utils.test.ts
packages/adapters/claude-local/src/server/acp.test.ts
packages/adapters/codex-local/src/server/acp.test.ts
server/src/__tests__/heartbeat-context-summary.test.ts` — 137 tests
passed, including new coverage for suppression, resume omission plus
breadcrumb, assignment-shaped resume inclusion, compact-variant
building, variant selection, and an end-to-end ACPX prompt-assembly test
asserting the description appears exactly once on fresh wakes and not at
all on comment resumes.
- `npx vitest run` in `packages/adapters/hermes` — 59 tests passed,
including a gateway execute-level test asserting the brief is sent
exactly once on fresh runs and not re-sent on stable-session resumes.
- `tsc --noEmit` in `packages/adapter-utils`,
`packages/adapters/claude-local`, `packages/adapters/hermes` — clean;
`server` matches the `master` baseline exactly (pre-existing plugin-sdk
resolution errors only, none in touched files).
- Pre-existing failures confirmed identical on clean `master`:
claude-local `execute.remote.test.ts` / `test.probe.test.ts`,
adapter-utils `mcp-isolation.integration.test.ts` (requires a newer
local Claude CLI).

## Risks

- Behavioral shift, prompt-only: a resumed session woken by a comment on
an issue it never handled (rare — assignment wakes normally precede
comment wakes) would not get the inline description; the breadcrumb plus
the standard issue-fetch path covers it.
- Additive context key (`paperclipTaskMarkdownCompact`); older adapters
ignore it and newer adapters fall back to the full markdown when it is
absent, so mixed-version deployments degrade to current behavior.
- No schema, migration, or API changes; the structured wake-payload JSON
shape is unchanged.
- Known follow-up deliberately out of scope: openclaw embeds the raw
wake-payload JSON (which still contains the description) in prompt text
for machine parsing. The hermes-gateway lane is handled: it detects
stable-session resumes (issue/agent session-key strategy plus a stored
prior session id), compacts the task markdown, and omits the description
from its prompt-embedded JSON copy.

> This is a focused correctness/efficiency fix to existing wake plumbing
and does not overlap with planned roadmap feature work.

## Model Used

- Anthropic Claude Fable 5 (`claude-fable-5`), extended thinking
enabled, with repository tool use, shell execution, and local test
execution via Claude Code.

## 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
(execution-workspace branch, same convention as merged #10202)
- [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
(code-level docs; no user-facing docs affected)
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

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

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-24 16:35:07 -05:00
Dotta b3b07ae44e
fix(codex): preserve silent active builds (#10153)
## Thinking Path

> - Paperclip is the open source control plane people use to coordinate
AI agents and their work.
> - Local adapters are responsible for observing agent subprocesses and
terminating runs that are genuinely stuck.
> - The Codex local adapter currently treats output bytes as its only
liveness signal for the 30-minute inactivity monitor.
> - Healthy compile and test loops can consume CPU and perform disk I/O
for longer than that without producing terminal output.
> - Terminating those runs loses valid work, while removing the monitor
entirely would allow truly wedged processes to run indefinitely.
> - This pull request adds a Linux process-group activity probe that
recognizes meaningful CPU, disk I/O, and child-process churn while
retaining the existing timeout for idle processes.
> - The benefit is that long silent builds can finish without weakening
the adapter's hung-run safety net.

## Linked Issues or Issue Description

No public GitHub issue was found in the duplicate/related search.

**What happened**

A healthy Codex local run executing a long compile/test loop could be
terminated at the default 30-minute output-inactivity threshold when the
child process emitted no stdout or stderr.

**Expected behavior**

The inactivity monitor should keep a silent run alive while its process
group is doing meaningful work, but should still terminate a process
group that is alive and idle.

**Steps to reproduce**

1. Run Codex local with the default `outputInactivityTimeoutMs`.
2. Have the agent start a compile or test command that consumes CPU or
disk I/O without terminal output for longer than the threshold.
3. Observe the adapter terminate the otherwise healthy process group as
output-inactive.

**Affected version / deployment mode**

Observed on a local-process Paperclip deployment using the Codex local
adapter with the 30-minute default inactivity monitor.

## What Changed

- Added a Linux `/proc` process-group sampler that tracks meaningful CPU
tick growth, disk I/O growth, and child-process membership changes.
- Reset the existing Codex inactivity timer when that sampler observes
real process work, while leaving remote and non-Linux behavior
unchanged.
- Added diagnostics for the number of process-activity resets and
documented the expanded liveness semantics.
- Added unit coverage for process-activity timer resets and subprocess
regressions for both a long silent CPU build and a genuinely wedged
child.

## Verification

- `pnpm --filter @paperclipai/adapter-codex-local typecheck`
- `pnpm exec vitest run
packages/adapters/codex-local/src/server/process-activity-monitor.test.ts
packages/adapters/codex-local/src/server/output-inactivity-monitor.test.ts
packages/adapters/codex-local/src/server/output-inactivity-monitor.integration.test.ts`
- Focused result: 23 tests passed, including a silent CPU-bound
subprocess that runs four times beyond the simulated inactivity window
and an idle subprocess that is still terminated.

## Risks

- Low risk and Linux-scoped: the new probe reads `/proc` every 15
seconds only while a monitored local Codex child is running.
- The CPU threshold requires sustained work rather than any single
scheduler tick, reducing the risk that a nearly idle event loop is
treated as productive.
- If `/proc` sampling is unavailable or fails, the adapter falls back to
the existing output-only behavior.

> 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 model `gpt-5.6-sol`, high reasoning effort,
terminal/tool execution, code editing, and test execution. The runtime
did not expose a context-window size.

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-07-24 15:27:24 -05:00
Dotta e4662b1f9d
fix: preserve control plane access in Codex sandbox (#10152)
## Thinking Path

> - Paperclip is the open source control plane people use to manage AI
agents for work
> - Local coding adapters can be confined with filesystem and network
sandbox policies
> - Codex confinement proxied only user-allowlisted hosts, so it denied
Paperclip's own run API and managed MCP endpoints
> - The same proxy returned untyped plaintext denials, which MCP clients
could treat as a fatal unexpected content type
> - Host-only `PAPERCLIPAI_CMD` values could also leak into agents even
when the referenced checkout module did not exist
> - This pull request gives the sandbox an explicit trusted-URL channel
for Paperclip endpoints, returns structured JSON errors, and removes the
inherited host CLI pointer
> - The benefit is confined Codex agents retain control-plane access
without broadening the operator's external network allowlist or crashing
on policy denials

## Linked Issues or Issue Description

Refs #3802

Related foundation: #9504

### What happened?

A `codex_local` agent configured with `networkScope: "allowlist"` and an
external-only allowlist could not reach its own Paperclip API or
Paperclip-managed MCP endpoints. The sandbox proxy returned a `403`
plaintext response without `Content-Type`, and an inherited
`PAPERCLIPAI_CMD` could point at a missing checkout-local CLI module.

### Expected behavior

Paperclip's run-scoped API and managed MCP endpoints remain reachable
regardless of the user external allowlist. Policy denials are valid
structured JSON responses with an explicit media type, and host-only CLI
pointers are not inherited by agent processes.

### Steps to reproduce

1. Configure a `codex_local` agent with `networkScope: "allowlist"` and
`networkAllowlist: ["api.openai.com"]`.
2. Run the agent and request its Paperclip issue API or a
Paperclip-managed MCP endpoint.
3. Observe the sandbox proxy deny the request with an untyped plaintext
`403` response.

### Environment

- Paperclip commit: `f49a3f99` originally exhibited the defect; fix is
based on current `master`.
- Deployment: local source build on Linux.
- Adapter: Codex.
- Database: not database-related.
- Access context: agent bearer/run-scoped credentials.

## What Changed

- Added internal trusted URL rules to the local network allowlist proxy
and supplied the Codex run API plus managed MCP endpoints.
- Returned JSON error envelopes with `Content-Type` and `Content-Length`
for HTTP and CONNECT policy denials.
- Removed inherited `PAPERCLIPAI_CMD` from child process environments
while preserving explicitly constructed runtime variables.
- Added focused proxy and environment sanitizer regression tests.

## Verification

- `pnpm exec vitest run
packages/adapter-utils/src/local-process-sandbox.test.ts
packages/adapter-utils/src/server-utils-env.test.ts --reporter=verbose`
- 2 test files passed; 8 tests passed; 4 platform-dependent tests
skipped.
- `git diff --check`
- Package typecheck was attempted; it reaches unrelated current-`master`
type drift in untouched files (`spawnCwd` in `adapter-utils`, and
staged-runtime ACP types in `codex-local`).

## Risks

- Low risk: trusted access is restricted to exact HTTP(S) hostname and
port pairs derived from Paperclip-provided URLs.
- Invalid or non-HTTP trusted URL values are ignored rather than
broadening access.
- Denial response bodies change from plaintext to structured JSON;
status codes remain unchanged.

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

## Model Used

- OpenAI Codex coding agent (exact model ID and context window are not
exposed to this runtime), reasoning and terminal/tool 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] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-07-24 15:25:59 -05:00
Dotta ee3ed0117e
fix(opencode): register configured model in runtime config (#10178)
## Thinking Path

> - Paperclip is the open source control plane people use to manage AI
agents for work
> - Agent runs depend on adapters translating Paperclip configuration
into each agent runtime's native configuration
> - The OpenCode local adapter passes configured models through the
`--model provider/model` argument
> - OpenCode only resolves that argument when the model id exists in the
provider's runtime `models` map
> - Valid provider-served model ids missing from OpenCode's bundled
catalog therefore fail locally with `Model not found`
> - This pull request registers the configured model in the injected
runtime configuration without overwriting explicit provider definitions
> - The benefit is that uncataloged routing variants and newly released
models resolve while cataloged models retain their metadata

## Linked Issues or Issue Description

### Pre-submission checklist

- [x] I have searched existing open and closed issues and this is not a
duplicate.
- [x] I can reproduce this on current `master`.
- [x] I have confirmed the error originates in Paperclip's OpenCode
adapter rather than the provider or local configuration.

### What happened?

OpenCode local runs failed with `Model not found` when a configured
`provider/model` id was valid at the provider but absent from OpenCode's
bundled model catalog. OpenRouter routing variants such as model ids
ending in `:nitro` are one example.

### Expected behavior

Any configured provider-served model id should resolve when Paperclip
starts OpenCode, including ids not yet present in the bundled catalog.

### Steps to reproduce

1. Configure the OpenCode local adapter with a valid provider/model id
that is absent from OpenCode's bundled catalog.
2. Start an agent run.
3. Observe that OpenCode rejects the `--model` value with `Model not
found` before the session starts.

### Paperclip version or commit

Current `master` before this change.

### Deployment mode

Local dev using the OpenCode local adapter and an existing provider API
key.

### Installation method

Built from source.

### Agent adapter(s) involved

OpenCode local.

### Database mode

Not database-related.

### Relevant logs or output

`Model not found`

### Additional context

Reproduced with OpenCode 1.15.5. No duplicate or related public GitHub
issues or pull requests were found.

### Privacy checklist

- [x] I have reviewed all pasted output for sensitive information and no
secrets or PII are included.

## What Changed

- Register the configured `provider/model` id as an empty custom model
entry in the injected `opencode.json` provider configuration.
- Preserve explicit model definitions from user configuration and
`PAPERCLIP_OPENCODE_PROVIDERS`.
- Skip registration for model strings that do not use the
`provider/model` form.
- Add focused coverage for uncataloged models, explicit definitions, and
invalid model strings.

## Verification

- `cd packages/adapters/opencode-local && pnpm exec vitest run
src/server/runtime-config.test.ts` — 14 tests passed.
- `cd packages/adapters/opencode-local && pnpm exec tsc --noEmit` —
passed.
- Manual reproduction with OpenCode 1.15.5: the uncataloged OpenRouter
routing variant fails without the injected model entry and resolves with
it.

## Risks

- Low risk: the empty entry deep-merges with catalog metadata for known
models, and existing explicit model definitions take precedence.
- The behavior is limited to syntactically valid `provider/model`
configuration values in the OpenCode local adapter.

> 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, exact runtime model `gpt-5.6-sol` (context-window size
not exposed by the runtime), with reasoning, tool use, terminal
execution, and code-editing capabilities.

## Checklist

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

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-07-24 10:22:07 -05:00
Nicky Leach d36ea13e08
feat(acpx): stage once per remote ACP session - compatible resume reuses staged runtime, no cross-session credential reuse (#10089)
## Thinking Path

> - Paperclip coordinates autonomous agent work across isolated
company-scoped sessions
> - The ACP remote lane stages workspaces and managed home state inside
the sandbox so sessions can resume safely
> - If a compatible resume re-staged everything every time, it would
waste work and risk inconsistent session reuse behavior
> - If an incompatible resume reused the wrong staged runtime, it could
cross session boundaries or leak credentials
> - This pull request keeps the session fingerprint as the scoping key
and adds a staged-runtime cache keyed to that fingerprint
> - Compatible resumes now reuse the already staged runtime while
incompatible fingerprints stage fresh
> - The benefit is faster safe resumes without weakening session
isolation or credential separation

## Linked Issues or Issue Description

### Problem or motivation
The ACP remote lane currently needs to preserve safe resume behavior
without repeatedly re-staging work that is already valid for the same
session. The failure mode to avoid is letting one session reuse another
session's staged workspace or credentials.

### Proposed solution
Keep the session fingerprint as the scoping key and add a staged-runtime
cache keyed to that fingerprint. When the fingerprint matches, reuse the
already staged workspace and managed home. When the fingerprint changes,
stage fresh.

### Alternatives considered
- Always restage on resume: safest mechanically, but wastes work and
breaks the compatible-resume optimization.
- Reuse without fingerprint scoping: too risky because it could cross
session boundaries.

### Roadmap alignment
This is a narrow implementation change for the ACP remote lane and does
not duplicate any broader roadmap item I could find in `ROADMAP.md`.

### Additional context
The change preserves the existing session fingerprint contents and codex
auth copy-back cadence while adding tests for compatible reuse,
incompatible fresh staging, no cross-session credential reuse, and
failed-turn eviction.

## What Changed

- Added a staged-runtime cache in the ACP remote execution path keyed by
the session fingerprint.
- Reused the existing staged workspace and managed home for compatible
resumes.
- Kept incompatible fingerprints on the fresh staging path.
- Preserved the existing session fingerprint contents and codex auth
copy-back cadence.
- Added tests for compatible reuse, incompatible fresh staging, no
cross-session credential reuse, and failed-turn eviction.

## Verification

- `pnpm exec vitest run
packages/adapter-utils/src/acpx-engine/execute.test.ts` (74/74 pass,
including the active-turn lease regression)
- `pnpm exec tsc -p packages/adapter-utils/tsconfig.json --noEmit`
- Verified the PR touches only
`packages/adapter-utils/src/acpx-engine/execute.ts` and
`packages/adapter-utils/src/acpx-engine/execute.test.ts`

## Risks

- A cache eviction bug could cause an unavailable or partially staged
runtime to be reused.
- If the fingerprint scoping regressed, a session could incorrectly
reuse another session's state.
- The change is isolated to the ACP remote lane, but it still affects
resume behavior for that path.

## Model Used

OpenAI Codex, GPT-5, reasoning-capable coding agent, tool-enabled
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
- [ ] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-07-23 10:13:44 -07:00
Nicky Leach e1cc63328a
feat(acpx): per-adapter managed-home seed (x3) + Codex auth copy-back for remote ACP lane (#10073)
## Thinking Path

> - Paperclip is a control plane that orchestrates AI agents and adapter
execution for human operators.
> - Agents run across local and remote execution contexts, and
reliability in remote sessions depends on consistent adapter
bootstrapping.
> - The ACP path must prepare per-adapter runtime homes so managed
credentials and config are available in sandboxed runner environments.
> - Before this change, the new remote ACP lane did not yet consistently
stage managed-home paths for all affected adapters or restore Codex auth
state on teardown.
> - We added a shared per-adapter seam in the ACP engine, then wired
Codex, Claude, and Gemini remote lanes to seed managed homes and remap
to in-sandbox locations.
> - Codex additionally reuses the existing atomic auth restore flow to
copy auth back on teardown, matching CLI behavior.
> - This improves remote runner parity with existing CLI behavior and
avoids credential drift in shared-code-path executions.

## Linked Issues or Issue Description

- This change continues the ACP remote managed-home work by completing
per-adapter remote bootstrapping and Codex auth restore behavior for the
remote ACP lane.
- It specifically covers: `acpx-engine`, `codex-local`, `claude-local`,
and `gemini-local`.
- Related prior work in this repo: PR #10070.

## What Changed

- Add a per-adapter remote managed-home seam
(`prepareRemoteManagedHome`) in `acpx-engine` and thread it through ACP
execution options.
- Implement Codex ACP preparation to:
- stage `CODEX_HOME` (auth/config/skills) into a sandboxed remote home,
  - repoint `CODEX_HOME` to the in-sandbox path,
- and wire teardown copy-back through the existing managed-auth restore
path.
- Implement Claude ACP preparation to seed a sanitized `config-seed`
into `CLAUDE_CONFIG_DIR` and remap that directory to the sandbox root.
- Implement Gemini ACP preparation to seed `~/.gemini/skills`, set
`HOME` to managed runtime root, and preselect API-key auth in
`settings.json`.
- Keep local and runner-less ACP→CLI behavior unchanged by only invoking
the remote managed-home seam when running in remote ACP mode.
- Preserve existing authorization and activity boundaries in the shared
engine and adapter layers.

## Verification

- `git log --oneline
origin/master..origin/feat/acp-remote-managed-home-seed` confirms only
the expected 4 commits.
- `tsc --noEmit` is clean in `adapter-utils`, `codex-local`,
`claude-local`, and `gemini-local`.
- Vitest selection used during validation passed (120 tests across the
ACP-related suites).

## Risks

- If remote sandbox teardown occurs after token rotation but before
restore timing, Codex credentials can become stale and require re-auth
on next startup.
- Partial provisioning of managed-home assets would cause adapter
bootstrap failures in runner-backed ACP sessions.
- This change is scoped to execution-path behavior; it should not affect
CLI behavior.

## Model Used

None — human-authored.

## 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: Harold Kim <harold@paperclip.ing>
Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-07-23 06:42:52 -07:00
Nicky Leach 8a3cc86531
feat(acpx): stage workspace + route in-sandbox cwd for remote ACP lane (#10070)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - The shared ACP engine
(`packages/adapter-utils/src/acpx-engine/execute.ts`) is responsible for
launching local and remote agent processes via the ACP protocol
> - On runner-backed remote sandbox (Daytona) targets, `buildRuntime`
never crossed the CLI's staging seam: it never called
`prepareAdapterExecutionTargetRuntime`, left `runtimeRootDir: null` in
both the paperclip and process-session bridges, and handed the agent the
**HOST filesystem path** as the `session/new` cwd — meaning
Claude/Gemini silently operated on a path that does not exist inside the
sandbox (Codex additionally crashes on its HOST home path, addressed in
a follow-up PR)
> - The fix must cross the staging seam for remote sandboxes, thread the
real `runtimeRootDir` through both bridges, and bind the in-sandbox
workspace path as the session cwd — without touching local ACP runs or
the runner-less ACP→CLI fallback
> - This pull request introduces a `stageAcpRemoteRuntime` helper that
calls `prepareAdapterExecutionTargetRuntime` for runner-backed remote
runs, captures `{ workspaceRemoteDir, runtimeRootDir, assetDirs,
restoreWorkspace }`, and reuses the in-sandbox `workspaceRemoteDir` as
the single `sessionCwd` across `session/new`, the fingerprint,
compatibility check, persistence, `ensureSession`, the process-session
bridge cwd, and the error path
> - The benefit is that remote ACP runs now operate in the correct
in-sandbox cwd and receive a non-null `runtimeRootDir` in both bridges —
fixing silent wrong-cwd degradation for Claude/Gemini on Daytona
targets; this is PR 1 of 3 and seeds no credential material

## Linked Issues or Issue Description

No public GitHub issue exists for this change. Inline description
follows the feature request template:

### Subsystem affected

packages/adapters — agent adapter implementations

### Problem or motivation

The shared ACP engine
(`packages/adapter-utils/src/acpx-engine/execute.ts`) never crossed the
CLI's staging seam on runner-backed remote sandbox targets. It never
called `prepareAdapterExecutionTargetRuntime`, always passed
`runtimeRootDir: null` to both the paperclip and process-session
bridges, and handed the agent the **HOST filesystem path** as the ACP
`session/new` cwd. As a result, Claude and Gemini silently operated on a
cwd that does not exist inside the sandbox; Codex crashed with a fatal
error on the HOST `CODEX_HOME` path (that crash is in a follow-up PR).

### Proposed solution

Gate on `usesRunnerBackedSandbox` (`kind === "remote" && transport ===
"sandbox" && runner`). For runs that pass the gate, call
`prepareAdapterExecutionTargetRuntime` via a new `stageAcpRemoteRuntime`
helper that ships the workspace into the sandbox and captures `{
workspaceRemoteDir, runtimeRootDir, assetDirs, restoreWorkspace }`.
Thread the real `runtimeRootDir` into both bridges. Bind a single
`sessionCwd` (the in-sandbox `workspaceRemoteDir`) and use it at every
cwd-keyed session site (`session/new`, fingerprint, compat, persist,
`ensureSession`, process-session bridge, error path) so a warm/resumable
session is reused rather than invalidated. For local runs and the
runner-less ACP→CLI fallback, `sessionCwd` resolves to the HOST cwd —
byte-identical to the previous behavior.

### Alternatives considered

Patching each per-adapter bridge individually — rejected because the bug
is in the shared engine layer and the fix belongs there so all three
adapters (Codex, Claude, Gemini) benefit without per-adapter
duplication.

### Roadmap alignment

Internal correctness fix enabling remote ACP to work as designed; no new
user-facing features. This is PR 1 of 3 in a sequential chain: PR 1
(this PR) stages the workspace and routes the cwd; PR 2 adds per-adapter
home seeding and copy-back; PR 3 wires session-lifecycle restore.

## What Changed

- **`packages/adapter-utils/src/acpx-engine/execute.ts`** — added
`stageAcpRemoteRuntime` helper that calls
`prepareAdapterExecutionTargetRuntime` for runner-backed remote
sandboxes and returns `{ sessionCwd, runtimeRootDir, stagedRuntime }`;
`buildRuntime` now uses this helper to derive `sessionCwd` (in-sandbox
`workspaceRemoteDir` for remote; HOST cwd unchanged for
local/runner-less) and threads the real `runtimeRootDir` to both the
paperclip bridge and process-session bridge; `stagedRuntime` is stashed
for the follow-up credential PR
- **`packages/adapter-utils/src/acpx-engine/execute.test.ts`** — new
engine-level unit tests: staging seam crossed with no credential asset,
non-null `runtimeRootDir` in both bridges, in-sandbox `session/new` cwd,
warm-handle reuse after the cwd change, local-unchanged; 60 tests green
- **`packages/adapters/codex-local/src/server/acp.test.ts`** — new
per-adapter test: runner-backed remote asserts `ensureSession` cwd ==
`workspaceRemoteDir`; runner-less sandbox falls back to CLI
- **`packages/adapters/claude-local/src/server/acp.test.ts`** — same
per-adapter coverage for Claude
- **`packages/adapters/gemini-local/src/server/acp.test.ts`** — same
per-adapter coverage for Gemini

## Verification

- `adapter-utils` typecheck clean; `codex/claude/gemini-local` typecheck
clean
- Engine units (`acpx-engine/execute.test.ts`): 60/60 green — staging
seam crossed with no credential asset, non-null `runtimeRootDir` to both
bridges, in-sandbox `session/new` cwd, warm-handle reuse after cwd
change, local unchanged
- Per-adapter ACP test suites (`codex/claude/gemini-local`
`acp.test.ts`): 103 tests green — runner-backed remote asserts
`ensureSession` cwd == `workspaceRemoteDir`; runner-less sandbox falls
back to CLI
- CI green on PR (in progress)

## Risks

This is PR 1 of 3 in a strictly sequential chain; it seeds **no
credential material** (no `assets`, no `installCommand`). The
per-adapter home seeding is deferred to PR 2, which consumes the
`stagedRuntime` object stashed here. The `restoreWorkspace` callback is
carried on `stagedRuntime` for PR 3's session-lifecycle wiring (see the
`stageAcpRemoteRuntime` function comment). Local ACP runs and the
runner-less ACP→CLI fallback are untouched — `sessionCwd` resolves to
the HOST cwd for those paths, preserving existing behavior. The
`stageAcpRemoteRuntime` helper is gated on `usesRunnerBackedSandbox`, so
there is no regression risk for local or CLI-lane runs.

## Model Used

Claude Sonnet 4.6 (`claude-sonnet-4-6`) via Paperclip ACPX engine —
extended context, tool use enabled, co-authored with Paperclip agent
orchestration.

## 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/...`,
`feat/...`) and contains no internal Paperclip ticket id or
instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [ ] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [ ] All Paperclip CI gates are green
- [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Harold Kim <harold@paperclip.ing>
Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-07-22 22:24:30 -07:00
Dotta 5ed0b74b34
fix(runtime): scope PAPERCLIP_ env-binding strip to reserved keys (#9974)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - Agent runs get their environment from user/adapter/project/routine
env bindings resolved by the server heartbeat, plus `PAPERCLIP_*`
runtime vars (identity, wake, workspace, API access) injected by the
harness
> - The heartbeat stripped **every** `PAPERCLIP_`-prefixed binding
before resolution, so legitimately user-named keys (e.g. cloud provider
token bindings like `PAPERCLIP_CLOUD_PROD_PROVIDER_RAILWAY_*`) were
silently dropped and never reached the run env
> - At the same time, several adapters honored an explicitly configured
`PAPERCLIP_API_KEY` over the harness-minted run token, which is exactly
the one key config must never control
> - This pull request replaces the blanket prefix strip with a precise
three-rule policy: never accept `PAPERCLIP_API_KEY` from config, always
let harness-assigned runtime vars win, and let every other
`PAPERCLIP_*`-named user binding flow through
> - The benefit is that user secrets with a `PAPERCLIP_`-style name work
like any other binding, while runtime identity and API credentials stay
fully harness-controlled

## Linked Issues or Issue Description

**Bug description** (no public issue exists):

- **What happened:** Env bindings whose key starts with `PAPERCLIP_`
(e.g. a cloud provider token a user deliberately named
`PAPERCLIP_CLOUD_PROD_PROVIDER_RAILWAY_TOKEN`) were silently stripped by
the server before secret resolution, so the spawned agent never received
them. No error, no access event — the variable just never appeared.
- **Expected behavior:** A user-named `PAPERCLIP_*` binding should reach
the run env unless the harness itself uses that key. Only
`PAPERCLIP_API_KEY` should be categorically rejected, and
harness-assigned runtime vars (`PAPERCLIP_RUN_ID`, `PAPERCLIP_AGENT_ID`,
wake/workspace vars, …) should always win over config.
- **Steps to reproduce:** Configure an agent/project env binding named
`PAPERCLIP_<ANYTHING>` (plain or secret_ref), run a heartbeat, and
inspect the spawned process env — the key is absent.
- **Deployment mode:** local server, any local adapter.

Related prior PRs (different, save-time/API-layer blanket-ban approach;
this PR supersedes that direction with a runtime allow-except-reserved
policy): Refs #8239, Refs #8439.

## What Changed

- `server/src/services/heartbeat.ts`: the pre-resolution strip now
removes only `PAPERCLIP_API_KEY` (hard denylist) instead of every
`PAPERCLIP_`-prefixed binding; other `PAPERCLIP_*` keys flow into
binding resolution. Low-trust inline-sensitive-env checks now also cover
those keys.
- `packages/adapter-utils/src/server-utils.ts`: new
`isForbiddenConfigEnvKey()` helper; the shared
`refreshPaperclipWorkspaceEnvForExecution` merge drops
`PAPERCLIP_API_KEY` from config and keeps harness-assigned `PAPERCLIP_*`
keys authoritative.
- `packages/adapter-utils/src/acpx-engine/execute.ts`: removed the
explicit-`PAPERCLIP_API_KEY`-from-config allowance; the run token
(`authToken`) is now always applied; config `PAPERCLIP_API_KEY` is
ignored.
- All local adapters (`claude-local`, `codex-local`, `cursor-local`,
`gemini-local`, `grok-local`, `opencode-local`, `pi-local`) plus
`cursor-cloud`, `hermes`, and the server `process` adapter: removed
`hasExplicitApiKey`-style allowances so the harness token always wins,
and guarded the remaining unguarded env-merge loops (claude-local inline
loop, process adapter) with the same policy.
- Tests updated/added: heartbeat binding-strip test now asserts the
three-rule policy; adapter-utils merge tests assert the
`PAPERCLIP_API_KEY` ban and `PAPERCLIP_*` pass-through; acpx engine
tests moved credential fixtures to `authToken` and assert config
`PAPERCLIP_API_KEY` is ignored while other `PAPERCLIP_*` config keys
forward and still bust the session fingerprint on rotation.

## Verification

- `pnpm vitest run packages/adapter-utils/src/server-utils.test.ts
packages/adapter-utils/src/acpx-engine/execute.test.ts` — 127 passed
- `pnpm vitest run server/src/__tests__/heartbeat-project-env.test.ts
server/src/__tests__/heartbeat-local-environment.test.ts
server/src/__tests__/claude-local-execute.test.ts
server/src/__tests__/codex-local-execute.test.ts
server/src/__tests__/cursor-local-execute.test.ts
server/src/__tests__/gemini-local-execute.test.ts` — 68 passed
- Adapter package execute suites and the server tests touching API-key
fixtures (`heartbeat-run-log`, `redaction`,
`effective-run-config-fingerprints`, `agent-permissions-routes`) —
green. Three pre-existing sandbox/SSH fixture failures reproduce
identically on clean `master` on this host and are unrelated.
- `pnpm --filter <pkg> typecheck` for server, adapter-utils, and all
nine touched adapter packages — all pass.

## Risks

- Behavioral change: a deployment that relied on configuring a static
`PAPERCLIP_API_KEY` in adapter config env loses that override — by
design; the harness-minted run token is now the only source. When no run
token exists, no API key is injected at all.
- `PAPERCLIP_*`-named user bindings now reach binding resolution and run
envs; a key that collides with a harness runtime var is still discarded
at merge time, so runtime identity/wake/workspace vars cannot be
spoofed.
- Low risk otherwise: no migrations, no API surface changes.

## Model Used

- Claude Fable 5 (`claude-fable-5`, Anthropic Claude 5 family,
Mythos-class tier), extended thinking enabled, agentic tool use (file
edits, shell, test runner) via Claude Agent SDK.

## Checklist

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

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-22 07:01:57 -05:00
Nicky Leach 7985c1e000
refactor(codex-local): stage an allowlist for sandbox CODEX_HOME sync (#9972)
## Thinking Path

> - Paperclip manages AI agents for work; agents can run in remote
sandboxes via the codex-local adapter
> - When a remote sandbox run starts, the codex-local adapter syncs the
host CODEX_HOME directory into the sandbox so Codex can authenticate and
load its configuration
> - The old approach staged the entire CODEX_HOME and relied on a 4-name
denylist (`tmp`, `.tmp`, `sessions`, `shell_snapshots`) to exclude
unnecessary state
> - The denylist was too narrow: large host-local runtime files
(`logs_2.sqlite`, `plugins/`, etc.) still uploaded on every remote run —
state the sandbox never uses
> - Additionally, `config.toml` (which embeds the managed MCP
`Authorization: Bearer …` header) was staged at 0644, relying solely on
the staging directory's 0700 permission for protection — a
credential-bearing file without per-file least-privilege
> - This pull request replaces the denylist with an explicit allowlist:
only `{auth.json, config.toml, config.json, instructions.md, skills/}`
are staged into a private `0700` temp dir; all staged regular files are
written `0600` (fail-closed on any staging error)
> - The fix is adapter-local to `packages/adapters/codex-local` with
zero changes to the shared `packages/adapter-utils` seam; inbound
auth-merge and outbound copy-back are preserved unchanged

## Linked Issues or Issue Description

No public GitHub issue for this specific bug. Describing the problem
directly:

**Bug:** The codex-local remote sandbox sync uploads more CODEX_HOME
content than the sandbox uses, and stages a credential-bearing file with
an over-permissive mode.

- **What happened:** The codex-local adapter synced the entire
CODEX_HOME directory minus four directory names (`tmp`, `.tmp`,
`sessions`, `shell_snapshots`). Large host-local runtime artifacts — a
SQLite write-ahead log that can reach 420 MB, plugin directories, crash
logs — uploaded on every remote run. `config.toml` (which embeds the
managed MCP `Authorization: Bearer …` header) was staged at `0644`; only
the staging temp dir's `0700` mode prevented broader exposure.
- **Expected behavior:** Only the files Codex needs inside the sandbox
should sync: `auth.json`, `config.toml`, `config.json`,
`instructions.md`, and `skills/`. All staged regular files should use
mode `0600` (single-layer credential protection is insufficient for
secret-bearing files).
- **Steps to reproduce:** Run a remote codex sandbox from a host with a
mature CODEX_HOME. Observe the sync payload includes `sessions/`,
`*.sqlite`, `plugins/`, etc.

Related work: Refs #9621 (outbound auth sync-back in the same
codex-local adapter area; this PR covers the inbound staging direction)

## What Changed

- New `stageCodexHomeForSync(codexHomeDir)` helper in
`packages/adapters/codex-local/src/server/codex-home.ts` stages only
allowlisted files into a fresh `fs.mkdtemp`-created `0700` temp dir,
then registers that dir as the `home` asset (dropping the old `exclude`
field entirely)
- All staged regular files written with mode `0600` — auth.json holds
single-use OAuth tokens; config.toml embeds MCP bearer headers; least
privilege applies throughout
- Symlinks dereferenced to resolved file bytes (`auth.json` single-use
token, each `skills/` entry land as real files)
- Missing-but-optional allowlist entries skipped silently (keyring-only
mode with no `auth.json`; absent `config.json`)
- Staged temp dir removed on teardown AND on error; staging is
fail-closed — a staging error aborts the run rather than shipping a
partial CODEX_HOME
- `execute.ts` updated to call `stageCodexHomeForSync` instead of the
old whole-dir + denylist path; the `exclude` field is removed from the
`home` asset
- Adapter-local fix: zero diff to `packages/adapter-utils` (shared
managed-runtime seam untouched); inbound auth-merge (`provision`) and
outbound copy-back (`restore`) preserved unchanged

## Verification

```sh
# Full codex-local test suite
npx vitest run packages/adapters/codex-local
# 174/174 pass

# Shared seam regression — must be zero diff to packages/adapter-utils
npx vitest run packages/adapter-utils
# 14/14 pass; zero changes to packages/adapter-utils source

# TypeScript (both packages)
npx tsc --noEmit -p packages/adapters/codex-local/tsconfig.json
npx tsc --noEmit -p packages/adapter-utils/tsconfig.json
# Both clean
```

Key new test coverage
(`packages/adapters/codex-local/src/server/codex-home.test.ts`):

- Stager copies exactly the allowlisted entries and nothing else
- Staged `auth.json` dereferenced from symlink and written mode `0600`
- Staged temp dir created with mode `0700`
- ALL staged regular files mode `0600`, including `config.toml` carrying
an MCP bearer token (regression test fails against the pre-fix `0644`
path)
- Fail-closed: I/O error during staging removes the temp dir and
re-throws
- Missing-but-optional entries (`config.json`) skipped without error
- Dangling symlink entries skipped without error

Execute-path integration test (`execute.remote.test.ts`): home asset
uses staged dir; staged config preserves provider block; skills survive;
staged temp dir removed after run teardown.

## Risks

- **Allowlist narrower than denylist:** Any CODEX_HOME file not in
`{auth.json, config.toml, config.json, instructions.md, skills/}` is now
excluded. If a codex-local configuration stores additional files in
CODEX_HOME that the sandbox requires, those runs will miss that state.
This tradeoff is intentional — only known-necessary files sync.
- **Permission change:** `config.toml` previously staged at `0644`, now
staged at `0600`. Strictly more restrictive; no known behavioral impact
(the sandbox reads as the file owner). This was the security gap that
motivated the fix.
- **Fail-closed staging:** A staging error (disk full, temp dir creation
failed) now aborts the run rather than falling back to the raw
CODEX_HOME. This is the safer behavior, but it changes the failure mode
from "run with potentially wrong state" to "run aborted cleanly."

## Model Used

Claude Opus 4.8 (claude-opus-4-8), Anthropic. Reasoning/agentic tool-use
mode (extended thinking, multi-step tool calls).

## 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
- [ ] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Harold Kim <harold@paperclip.ing>
Co-authored-by: Paperclip <noreply@paperclip.ing>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-21 19:50:21 -07:00
dependabot[bot] dc7f09be0d
build(deps-dev): bump vitest from 4.1.8 to 4.1.10 (#9886)
Bumps
[vitest](https://github.com/vitest-dev/vitest/tree/HEAD/packages/vitest)
from 4.1.8 to 4.1.10.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/vitest-dev/vitest/releases">vitest's
releases</a>.</em></p>
<blockquote>
<h2>v4.1.10</h2>
<h3>   🐞 Bug Fixes</h3>
<ul>
<li><strong>browser</strong>: Check fs access in builtin commands
[backport to v4]  -  by <a
href="https://github.com/hi-ogawa"><code>@​hi-ogawa</code></a>,
<strong>Hiroshi Ogawa</strong> and <strong>OpenCode
(claude-opus-4-8)</strong> in <a
href="https://redirect.github.com/vitest-dev/vitest/issues/10680">vitest-dev/vitest#10680</a>
<a href="https://github.com/vitest-dev/vitest/commit/5c18dd267"><!-- raw
HTML omitted -->(5c18d)<!-- raw HTML omitted --></a></li>
<li><strong>vm</strong>: Fix external module resolve error with deps
optimizer query for encoded URI [backport to v4]  -  by <a
href="https://github.com/SveLil"><code>@​SveLil</code></a> and <a
href="https://github.com/hi-ogawa"><code>@​hi-ogawa</code></a> in <a
href="https://redirect.github.com/vitest-dev/vitest/issues/10661">vitest-dev/vitest#10661</a>
<a href="https://github.com/vitest-dev/vitest/commit/bae52b511"><!-- raw
HTML omitted -->(bae52)<!-- raw HTML omitted --></a></li>
</ul>
<h5>    <a
href="https://github.com/vitest-dev/vitest/compare/v4.1.9...v4.1.10">View
changes on GitHub</a></h5>
<h2>v4.1.9</h2>
<h3>🐞 Bug Fixes</h3>
<ul>
<li>Fix <code>importOriginal</code> with optimizer and query import
[backport to v4] - by <strong>Hiroshi Ogawa</strong>, <strong>David
Harris</strong>, <strong>Codex</strong>and <strong>Vladimir</strong> in
<a
href="https://redirect.github.com/vitest-dev/vitest/issues/10546">vitest-dev/vitest#10546</a>
<a href="https://github.com/vitest-dev/vitest/commit/a5180190c"><!-- raw
HTML omitted -->(a5180)<!-- raw HTML omitted --></a></li>
<li><strong>browser</strong>:
<ul>
<li>Wait for orchestrator readiness before resolving browser sessions
[backport to v4] - by <strong>Vladimir</strong> and <strong>Séamus
O'Connor</strong> in <a
href="https://redirect.github.com/vitest-dev/vitest/issues/10555">vitest-dev/vitest#10555</a>
<a href="https://github.com/vitest-dev/vitest/commit/7fb29651a"><!-- raw
HTML omitted -->(7fb29)<!-- raw HTML omitted --></a></li>
<li>Wait for iframe tester readiness before preparing [backport to v4] -
by <strong>Vladimir</strong> and <strong>Séamus O'Connor</strong> in <a
href="https://redirect.github.com/vitest-dev/vitest/issues/10497">vitest-dev/vitest#10497</a>
and <a
href="https://redirect.github.com/vitest-dev/vitest/issues/10556">vitest-dev/vitest#10556</a>
<a href="https://github.com/vitest-dev/vitest/commit/fbc626c40"><!-- raw
HTML omitted -->(fbc62)<!-- raw HTML omitted --></a></li>
</ul>
</li>
<li><strong>mocker</strong>:
<ul>
<li>Hoist vi.mock() for vite-plus/test imports [backport to v4] - by
<strong>Hiroshi Ogawa</strong>, <strong>LongYinan</strong>,
<strong>Claude Opus 4.8</strong> and <strong>Vladimir</strong> in <a
href="https://redirect.github.com/vitest-dev/vitest/issues/10548">vitest-dev/vitest#10548</a>
<a href="https://github.com/vitest-dev/vitest/commit/2c9559c02"><!-- raw
HTML omitted -->(2c955)<!-- raw HTML omitted --></a></li>
</ul>
</li>
<li><strong>pool</strong>:
<ul>
<li>Prevent test run hang on worker crash [backport to v4] - by
<strong>Ari Perkkiö</strong> and <strong>Jattioui Ismail</strong> in <a
href="https://redirect.github.com/vitest-dev/vitest/issues/10543">vitest-dev/vitest#10543</a>
and <a
href="https://redirect.github.com/vitest-dev/vitest/issues/10564">vitest-dev/vitest#10564</a>
<a href="https://github.com/vitest-dev/vitest/commit/934b0f587"><!-- raw
HTML omitted -->(934b0)<!-- raw HTML omitted --></a></li>
</ul>
</li>
</ul>
<h5><a
href="https://github.com/vitest-dev/vitest/compare/v4.1.8...v4.1.9">View
changes on GitHub</a></h5>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="db616d227b"><code>db616d2</code></a>
chore: release v4.1.10 (<a
href="https://github.com/vitest-dev/vitest/tree/HEAD/packages/vitest/issues/10718">#10718</a>)</li>
<li><a
href="bae52b5112"><code>bae52b5</code></a>
fix(vm): fix external module resolve error with deps optimizer query for
enco...</li>
<li><a
href="a7a61e78c7"><code>a7a61e7</code></a>
chore: release v4.1.9 (<a
href="https://github.com/vitest-dev/vitest/tree/HEAD/packages/vitest/issues/10598">#10598</a>)</li>
<li><a
href="934b0f587c"><code>934b0f5</code></a>
fix(pool): prevent test run hang on worker crash (<a
href="https://github.com/vitest-dev/vitest/tree/HEAD/packages/vitest/issues/10543">#10543</a>)
[backport to v4] (#...</li>
<li><a
href="7fb29651af"><code>7fb2965</code></a>
fix(browser): wait for orchestrator readiness before resolving browser
sessio...</li>
<li><a
href="a5180190c1"><code>a518019</code></a>
fix: fix <code>importOriginal</code> with optimizer and query import
[backport to v4] (#...</li>
<li>See full diff in <a
href="https://github.com/vitest-dev/vitest/commits/v4.1.10/packages/vitest">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=vitest&package-manager=npm_and_yarn&previous-version=4.1.8&new-version=4.1.10)](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>
2026-07-21 12:04:11 -05:00
dependabot[bot] 4d736b681d
build(deps): bump ws from 8.19.0 to 8.21.1 (#9891)
Bumps [ws](https://github.com/websockets/ws) from 8.19.0 to 8.21.1.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/websockets/ws/releases">ws's
releases</a>.</em></p>
<blockquote>
<h2>8.21.1</h2>
<h1>Bug fixes</h1>
<ul>
<li>Empty fragments are now counted toward the limit (a2f4e7c0).</li>
<li>The default values of the <code>maxBufferedChunks</code> and
<code>maxFragments</code> options have
been reduced (f197ac65).</li>
</ul>
<h2>8.21.0</h2>
<h1>Features</h1>
<ul>
<li>Introduced the <code>maxBufferedChunks</code> and
<code>maxFragments</code> options (2b2abd45).</li>
</ul>
<h1>Bug fixes</h1>
<ul>
<li>Fixed a remote memory exhaustion DoS vulnerability (2b2abd45).</li>
</ul>
<p>A high volume of tiny fragments and data chunks could be sent by a
peer, using
modest network traffic, to crash a <code>ws</code> server or client due
to OOM.</p>
<pre lang="js"><code>import { WebSocket, WebSocketServer } from 'ws';
<p>const wss = new WebSocketServer({ port: 0 }, function () {
const data = Buffer.alloc(1);
const options = { fin: false };
const { port } = wss.address();
const ws = new WebSocket(<code>ws://localhost:${port}</code>);</p>
<p>ws.on('open', function () {
(function send() {
ws.send(data, options, function (err) {
if (err) return;
send();
});
})();
});</p>
<p>ws.on('error', console.error);
ws.on('close', function (code, reason) {
console.log(<code>client close - code: ${code} reason:
${reason.toString()}</code>);
});
});</p>
<p>wss.on('connection', function (ws) {
ws.on('error', console.error);
ws.on('close', function (code, reason) {
console.log(<code>server close - code: ${code} reason:
${reason.toString()}</code>);
});
});
</code></pre></p>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="ae1de54330"><code>ae1de54</code></a>
[dist] 8.21.1</li>
<li><a
href="8e9511b86b"><code>8e9511b</code></a>
[ci] Trust Coveralls Homebrew tap</li>
<li><a
href="f197ac6514"><code>f197ac6</code></a>
[fix] Lower default values of <code>maxBufferedChunks</code> and
<code>maxFragments</code></li>
<li><a
href="8df8265c2f"><code>8df8265</code></a>
[ci] Update actions/checkout action to v7</li>
<li><a
href="a2f4e7c046"><code>a2f4e7c</code></a>
[fix] Count empty fragments toward the limit (<a
href="https://redirect.github.com/websockets/ws/issues/2329">#2329</a>)</li>
<li><a
href="e79f912cb3"><code>e79f912</code></a>
[pkg] Approve install scripts for bufferutil and utf-8-validate</li>
<li><a
href="4ea355d6d3"><code>4ea355d</code></a>
[doc] Document 32-bit signed integer coercion for option values</li>
<li><a
href="2120f4c8c6"><code>2120f4c</code></a>
[example] Remove uuid dependency</li>
<li><a
href="4c534a6b8a"><code>4c534a6</code></a>
[security] Add latest vulnerability to SECURITY.md</li>
<li><a
href="bca91adf15"><code>bca91ad</code></a>
[dist] 8.21.0</li>
<li>Additional commits viewable in <a
href="https://github.com/websockets/ws/compare/8.19.0...8.21.1">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=ws&package-manager=npm_and_yarn&previous-version=8.19.0&new-version=8.21.1)](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>
2026-07-21 12:03:45 -05:00
Nicky Leach 14da75dfc7
feat(codex-local): outbound auth copy-back as home-asset restore contribution (#9788) 2026-07-18 09:13:45 -05:00
Nicky Leach 936215693c
feat(codex-local): add outbound direction to codex-auth-merge decision predicate (#9787)
## Thinking Path

> - Paperclip runs Codex as a sandboxed agent with its own CODEX_HOME;
at the start of each run Paperclip merges the sandbox's auth.json with
the host's so the agent can authenticate to the Codex API
> - The merge uses `codex-auth-merge-decision.cjs`, a small CJS script
that reads two `auth.json` snapshots and exits `10` (use source copy) or
`20` (keep destination copy)
> - Until now the script only handled the **inbound** direction (host →
sandbox) with hard-coded sandbox/host semantics
> - Sandbox-to-host copy-back (**outbound**) requires the same freshness
guard but with swapped roles — and exposing both directions via a flag
requires hard-coding knowledge about which role is "sandbox" and which
is "host" into the predicate itself
> - A cleaner design: the predicate is **direction-agnostic** — it
accepts a `source` path and a `destination` path; the caller decides
direction by which argument it passes first. The script answers one
question: "should destination be replaced by source?" Exit `10` = yes
(use source); exit `20` = no (keep destination)
> - This PR refactors `codex-auth-merge-decision.cjs` to this
source/destination model, removes the `--direction` flag, and extends
coverage with a 15-row source/destination predicate matrix plus updated
extract integration tests

## Linked Issues or Issue Description

No public GitHub issue exists. The underlying problem:

**Context** — Paperclip merges `auth.json` files between sandbox and
host to keep Codex credentials in sync across agent runs. The existing
decision predicate (`codex-auth-merge-decision.cjs`) handled the inbound
direction (host→sandbox) with hard-coded sandbox/host naming. A
copy-back (outbound) direction was needed, but rather than add a
`--direction` flag that hard-codes role knowledge into the predicate,
the design was simplified: the predicate is now **direction-agnostic**,
taking `source` and `destination` paths and answering "replace
destination with source?" The freshness guard is unified: exit `10` only
when source and destination share the same `account_id`, same
subscription-kind, both carry a parseable `last_refresh`, and
`source.last_refresh > destination.last_refresh` (strict). Ties and null
freshness keep the destination copy so a spent single-use refresh token
(openai/codex#15502) is never written back over a valid one.

Related PRs:
- Refs #9785 — Phase 2: relocated the decision predicate from
`adapter-utils` into `codex-local`; this PR builds on that merged change
- Refs #9621 — community PR targeting Codex sandbox auth sync-back via a
different approach; operates on different files (runtime layer vs.
decision script), non-conflicting

## What Changed

-
`packages/adapters/codex-local/src/server/codex-auth-merge-decision.cjs`
— refactored from direction-parameterized (sandbox/host with
`--direction`) to **direction-agnostic source/destination** semantics.
Args: first = source path, second = destination path. Exit `10` (use
source) only when: same `account_id`, same subscription-kind, both carry
a parseable `last_refresh`, and `source.last_refresh >
destination.last_refresh` (strict). Every other case exits `20` (keep
destination). Unknown/extra flags are still rejected with exit `1`. No
token bytes are emitted to stdout/stderr.
- `packages/adapters/codex-local/src/server/codex-auth-merge.test.ts` —
rewritten to source/destination API: 15-row predicate matrix
(strictly-newer→`10`;
tie/older/identity-mismatch/null-refresh/apikey/kind-mismatch/unusable→`20`)
plus token-bytes non-emission guard. The inbound extract integration
suite updated to match.
- Runtime callers (`codex-auth-merge-extract.sh`) already invoke `node
decision <sandbox> <host>` = `(source, destination)` and branch on exit
`10` → keep sandbox, so **no caller changes are needed**.

**Behavioral note:** unifying the two directions under a single "use
source only when strictly fresher" rule means a tie (exact equal
`last_refresh`) now keeps the **destination** for both the inbound and
outbound frames. For inbound restore, this means an exact timestamp tie
keeps the host copy. On a tie, both credentials are the same generation
— preferring the canonical destination (host) copy is more conservative.
This is an intentional consequence of the unified guard.

## Verification

```sh
# From the codex-local package root:
pnpm vitest run src/server/codex-auth-merge.test.ts
# Expected: all predicate rows green (15-row source/destination matrix + token-leak guard)
# Plus: codex-auth-merge-extract integration rows green
```

The test suite drives the `.cjs` as a child process over temporary
`auth.json` fixtures:
- Source/destination predicate matrix (15 rows): strictly-newer→`10`;
tie→`20`; older→`20`; identity-mismatch→`20`; source last_refresh
unparseable→`20`; destination last_refresh unparseable→`20`; apikey
either side→`20`; kind-mismatch→`20`; unusable either side→`20`
- Token-bytes non-emission guard: asserts no auth token bytes appear in
`stdout`/`stderr`
- Inbound extract integration: `codex-auth-merge-extract.sh` end-to-end
rows including tie/identity-mismatch/sandbox-newer cases

## Risks

- **Tie behavior change**: exact `last_refresh` ties now always keep the
destination copy (was: keep-sandbox for inbound). On a tie both
credentials are the same generation; keeping the canonical destination
(host) copy is the more conservative choice. Covered by test assertions.
- **Token non-emission**: `stdout`/`stderr` of the `.cjs` must not echo
credential bytes; covered by the token-bytes non-emission guard test.
- **Unknown/extra flags**: handled with `process.exit(1)` rather than a
silent default, so misconfigured callers surface errors immediately.
- **Caller compatibility**: the only runtime caller,
`codex-auth-merge-extract.sh`, already calls `node decision <sandbox>
<host>` with no flags — compatible with the new source/destination API
with no changes required.
- **Low risk overall**: the script is exercised end-to-end via the
extract integration tests; all paths covered.

## Model Used

Claude claude-sonnet-4-6 (Anthropic, `claude-sonnet-4-6`), 200 k context
window, tool use and agentic code execution enabled. Automated Paperclip
multi-agent system.

## 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: Harold Kim <harold@paperclip.ing>
Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-07-17 16:18:39 -05:00
Nicky Leach 7ffeafad1f
refactor(codex-local): relocate Codex auth-merge scripts + decision predicate into the adapter (#9785)
## Thinking Path

> - Paperclip is an open source platform for managing AI agent teams,
with adapter packages providing concrete runtime environments (e.g.
`codex-local` runs a local OpenAI Codex sandbox)
> - `adapter-utils` is the shared utilities package — it should hold
only generic, adapter-agnostic primitives (sandbox lifecycle helpers,
merge logic, type definitions) usable by every adapter
> - Three files lived in `adapter-utils/src/` that are entirely
Codex-specific: `codex-auth-merge-extract.sh` (shell script that
extracts auth tokens), `codex-auth-merge-decision.cjs` (CJS decision
helper), and `codex-auth-merge-scripts.ts` (TypeScript factory that
wires them into the inbound provision seam added in PR #9778)
> - Their presence in a "generic" package violates the adapter isolation
principle and requires a cross-package build step to copy `.sh`/`.cjs`
files into `codex-local/dist/server/` at build time
> - This PR completes Phase 2 of the inbound-seam refactor: move all
three files to `packages/adapters/codex-local/src/server/`, rebase the
TypeScript imports, update `execute.ts` to import locally, move the
Codex-auth tests into a new `codex-local` test file, and fix packaging
so `codex-local` copies its own scripts to `dist/server/`
> - Script bytes are identical after the move; no change to inbound
auth-merge behavior or to which bytes cross the sandbox boundary
> - The benefit is a clean ownership boundary: `adapter-utils` retains
only generic runtime code, and the structural "Codex-free core" test in
the adapter-utils suite validates this invariant going forward

## Linked Issues or Issue Description

No pre-existing public GitHub issue. Describing the underlying problem
inline:

**Problem:** `packages/adapter-utils/src/` contains three files
(`codex-auth-merge-extract.sh`, `codex-auth-merge-decision.cjs`,
`codex-auth-merge-scripts.ts`) consumed exclusively by the `codex-local`
adapter. Their presence in a generic utilities package violates adapter
isolation and requires a cross-package build step (copy `.sh`/`.cjs`
into `codex-local/dist/server/`). The inbound provision seam landed in
PR #9778 routed these through `adapter-utils`; this PR finishes the
relocation.

**Related:** Refs #9778 (Phase 1 — generic asset-lifecycle-seam, now
merged).

## What Changed

- Moved `codex-auth-merge-extract.sh`, `codex-auth-merge-decision.cjs`,
and `codex-auth-merge-scripts.ts` from `packages/adapter-utils/src/` →
`packages/adapters/codex-local/src/server/` (script bytes are unchanged;
`codex-auth-merge-scripts.ts` imports rebased to `adapter-utils`
subpaths for `shellQuote` and `SandboxManagedRuntimeAssetProvision`)
- `packages/adapters/codex-local/src/server/execute.ts`: updated import
of `buildCodexAuthInboundProvision` from `adapter-utils` → local
`./codex-auth-merge-scripts`
- New
`packages/adapters/codex-local/src/server/codex-auth-merge.test.ts` — 5
Codex-auth test rows extracted from
`adapter-utils/src/workspace-restore-merge.test.ts`; the generic test
file stays and no longer references Codex
- `packages/adapters/codex-local/package.json`: build now copies
`.sh`/`.cjs` from `src/server/` into `dist/server/` directly
- `packages/adapter-utils/package.json`: removed the now-obsolete
cross-package copy step for those files

## Verification

```sh
# Type-check both affected packages
pnpm --filter @paperclipai/adapter-utils --filter @paperclipai/adapter-codex-local typecheck

# Codex auth-merge suite (moved tests — 5/5 pass)
pnpm --filter @paperclipai/adapter-codex-local test -- --reporter=verbose codex-auth-merge

# Full adapter-utils suite including the structural "core free of Codex literals" test (243 passed, 4 pre-existing skips)
pnpm --filter @paperclipai/adapter-utils test

# Confirm build copies scripts to dist/server
pnpm --filter @paperclipai/adapter-codex-local build
ls packages/adapters/codex-local/dist/server/*.sh packages/adapters/codex-local/dist/server/*.cjs
```

All of the above were run locally and passed before this PR was opened.

## Risks

Low risk — pure file relocation:

- No change to `.sh` or `.cjs` script bytes; the same content reaches
the sandbox boundary as before
- No behavioral change to inbound auth-merge logic from the sandbox's
perspective
- `adapter-utils`' structural "core free of Codex literals" test now
validates that the relocation is complete and will catch any regression
- Only `codex-local` consumed these files from `adapter-utils`; no other
package in the monorepo imported them from there

## Model Used

Claude Sonnet 4.6 (`claude-sonnet-4-6`) — Anthropic, 200k context
window, tool use, agentic reasoning. Used to author the refactor.
`Co-authored-by: Paperclip <noreply@paperclip.ing>` trailer present on
all 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 (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

Co-authored-by: Harold Kim <harold@paperclip.ing>
Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-07-17 14:45:36 -05:00
Nicky Leach cf5ba4bbea
feat(adapter-utils): generic per-asset lifecycle-contribution seam (#9778)
## Thinking Path

> - Paperclip's sandbox managed runtime is responsible for provisioning
the agent's execution environment — it extracts a home directory asset
into the sandbox before the adapter runs.
> - The sandbox runtime core was directly branching on the adapter key
(`codex`) to decide which merge scripts to stage and which merge-extract
command to run, coupling generic infrastructure to a specific adapter's
credential-merge protocol.
> - This makes it harder to add, remove, or modify per-adapter asset
provisioning without touching the runtime core; it also prevents other
adapters from contributing staged files or a custom extract command at
all.
> - The fix is to move the adapter-specific knowledge into the adapter
itself: the asset descriptor gains optional `provision` (stageFiles +
extractCommand) and `restore` contribution fields that any adapter can
populate, and the runtime core consumes them generically.
> - This pull request introduces those contribution fields, wires the
Codex adapter's inbound credential-merge as a `provision` contribution,
and removes the adapter-specific branching from the runtime core.
> - The benefit is a clean seam: the runtime core is now
adapter-agnostic for asset provisioning, the inbound behavior is
unchanged (same merge matrix, same scripts), and other adapters can
attach custom staged files or extract commands without modifying shared
infrastructure.

## Linked Issues or Issue Description

No pre-existing public GitHub issue. Describing the problem inline per
the feature template:

**Problem or motivation**

The sandbox managed-runtime asset provisioning in
`sandbox-managed-runtime.ts` branched directly on the adapter key
(`codex`) to decide which merge scripts to stage and which shell command
to use during asset extraction. This tight coupling prevents other
adapters from customizing their provisioning without modifying the
runtime core, and it means the runtime core must import and know about
adapter-specific merge scripts.

**Proposed solution**

Add an optional `provision` contribution (array of `stageFiles` entries
+ an `extractCommand` string) and an optional `restore` contribution to
the asset descriptor returned by adapters. The runtime core now consumes
these generically — if a `provision` contribution is present, it stages
those files and uses the supplied command; otherwise it falls back to
the default `tar -xf` extraction. The Codex adapter populates the
`provision` contribution where it previously depended on core branching.

**Alternatives considered**

Keeping the adapter-specific logic in the core as a documented
exception; rejected because it makes the seam inextensible.

**Roadmap alignment**

Decoupling — removes a latent coupling between the runtime core and a
specific adapter.

## What Changed

- Added `provision` contribution field (`stageFiles: Array<{src, dest}>`
+ `extractCommand: string`) to the `SandboxManagedRuntimeAsset`
descriptor type in `adapter-utils`.
- Added `restore` contribution field (hook for post-restore logic,
populated in a later phase) to the descriptor.
- Removed adapter-key branching (`if adapterKey === 'codex'`) from the
runtime core in `sandbox-managed-runtime.ts`; the core now reads
`provision.stageFiles` and `provision.extractCommand` generically.
- Extracted Codex-specific merge-script paths and the merge-extract
command into `codex-auth-merge-scripts.ts` in `adapter-utils`; the Codex
adapter's `execute.ts` now attaches them as a `provision` contribution
when it builds its managed-home asset descriptor.
- Updated `execution-target.ts` to pass the extended asset type through
to the adapter call site so the new fields are load-bearing end-to-end.
- Added seam-proving unit tests in `sandbox-managed-runtime.test.ts`:
contribution-less asset uses the default path; a non-adapter asset
round-trips the generic provision+restore seam; a structural assertion
verifies the runtime core carries no Codex-specific string literals.
- Added one test in `workspace-restore-merge.test.ts` confirming the
inbound merge matrix is unaffected.

## Verification

```bash
# Unit tests (20 pass):
npx vitest run packages/adapter-utils/src/sandbox-managed-runtime.test.ts packages/adapter-utils/src/workspace-restore-merge.test.ts

# Type-check both affected packages:
cd packages/adapter-utils && npx tsc --noEmit
cd packages/adapters/codex-local && npx tsc --noEmit

# Structural: runtime core carries no adapter string literals
grep -n 'codex\|auth\.json' packages/adapter-utils/src/sandbox-managed-runtime.ts
# Expected: zero matches
```

## Risks

**Low risk.** This is a behavior-preserving refactor: the inbound
provisioning output (which files get staged, which command runs) is
identical to before, now driven by the adapter-supplied contribution
instead of core branching. The existing inbound merge matrix tests are
the regression guard. No change to which bytes cross the sandbox
boundary. The SSH transport is untouched.

## Model Used

- **Provider:** Anthropic
- **Model:** Claude Sonnet 4.6 (`claude-sonnet-4-6`)
- **Context window:** 200 K tokens
- **Capabilities used:** tool use (file read/edit, bash execution,
Paperclip API), extended reasoning over multi-file TypeScript refactor
- **Mode:** agentic (Paperclip ACPX 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>
Co-authored-by: Harold Kim <harold@paperclip.ing>
2026-07-17 14:18:01 -05:00
Dotta 1f1f545238
feat: add built-in summarizer and summary slots (#9713)
## Thinking Path

> - Paperclip is the open source control plane people use to organize,
govern, and understand AI-agent work
> - Operators need concise, current status views across projects and
execution workspaces without manually reading every issue and run
> - Paperclip already has auditable issues, documents, built-in agents,
routines, and live run events, but no first-class summary-slot workflow
connecting those systems
> - A built-in Summarizer can generate status prose through ordinary
governed tasks while summary slots provide stable, revisioned
destinations for that output
> - The UI needs to show current summaries, generation progress,
failures, revisions, and streaming draft status in the places operators
already work
> - This pull request adds the end-to-end summary-slot data, API, agent,
orchestration, and UI surfaces behind an experimental setting
> - The benefit is decision-oriented status context that remains
company-scoped, auditable, retryable, and inexpensive by default

## Linked Issues or Issue Description

No public GitHub issue exists for this feature.

**Problem**

Operators currently have to reconstruct project and workspace status by
reading many issues, runs, and comments. This makes it hard to identify
decisions, review queues, recent work, and the next event worth
watching.

**Proposed capability**

Add an experimental summary system with revisioned summary slots for
projects and workspaces, a paused-by-default built-in Summarizer agent,
governed generation tasks, live draft status, and reusable UI cards.

**Expected behavior**

- Summary data remains company-scoped and revisions remain auditable.
- Generation runs through normal issue/agent orchestration and
deduplicates active requests.
- Only the linked built-in Summarizer generation task can author a slot
revision.
- Operators can generate, retry, inspect revisions, and follow draft
progress from project and workspace views.
- The feature remains opt-in and background generation remains paused by
default.

## What Changed

- Added summary-slot schema, idempotent migrations, shared contracts,
validators, API paths, and service tests.
- Added company-scoped summary-slot routes for reading revisions,
requesting generation, and guarded Summarizer writes with activity
logging.
- Added terminal generation finalization, failure reasons, assignment
wakeups, and orchestration integration.
- Added the paused-by-default built-in Summarizer bundle, low-cost
runtime defaults, status-summarization skill, and stale-summary routine.
- Added summary cards, revision selection, retry/configuration states,
live draft streaming, transcript chunk handling, and project/workspace
integrations.
- Updated Claude local parsing for streamed status output and expanded
server, adapter, shared, database, catalog, and UI coverage.

## Verification

- `pnpm -r typecheck`
- `pnpm exec vitest run packages/db/src/summary-slots-schema.test.ts
packages/shared/src/summary-slot.test.ts
server/src/__tests__/summary-slot-routes.test.ts
server/src/__tests__/summary-slots.test.ts
server/src/__tests__/built-in-agents.test.ts
ui/src/components/SummarySlotCard.test.tsx
ui/src/components/SummarySlotCard.status.test.tsx
ui/src/components/useSummaryDraftStream.test.tsx
ui/src/lib/summary-draft-stream.test.ts
ui/src/lib/run-log-chunks.test.ts
ui/src/context/LiveUpdatesProvider.hook.test.tsx` — 113 tests passed
- `pnpm test:run` — server and UI suites passed; one CLI AWS doctor test
was affected by inherited `AWS_ACCESS_KEY_ID`/`AWS_SECRET_ACCESS_KEY`,
and passed when those host credentials were removed
- `pnpm exec vitest run cli/src/__tests__/secrets.test.ts` with
inherited AWS credential variables removed — 8 tests passed
- `pnpm build`
- `pnpm check:token-gates` currently reports nine `#9627` comment
references introduced by current `master`; none are in this PR diff

## Risks

- Database risk is limited by incrementally ordered, idempotent
migrations and migration safety checks.
- Summary generation creates normal issues/runs, so misconfiguration can
produce failed slots; the UI exposes retryable failure reasons and agent
configuration entry points.
- Streaming draft parsing depends on the documented `STATUS:` protocol;
final persisted revisions remain the source of truth.
- The feature is experimental, opt-in, and its built-in routine is
paused with no background token spend by default.

> 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.3 Codex with reasoning, repository tool use, code
execution, GitHub CLI, and Paperclip control-plane integration. Earlier
branch commits also record Claude model co-authorship where applicable.

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 11:03:07 -05:00
dependabot[bot] c4da1c925f
build(deps): bump @agentclientprotocol/claude-agent-acp from 0.52.0 to 0.59.0 (#9484)
Bumps
[@agentclientprotocol/claude-agent-acp](https://github.com/agentclientprotocol/claude-agent-acp)
from 0.52.0 to 0.59.0.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/agentclientprotocol/claude-agent-acp/releases">@​agentclientprotocol/claude-agent-acp's
releases</a>.</em></p>
<blockquote>
<h2>v0.59.0</h2>
<h2><a
href="https://github.com/agentclientprotocol/claude-agent-acp/compare/v0.58.1...v0.59.0">0.59.0</a>
(2026-07-13)</h2>
<h3>Features</h3>
<ul>
<li><strong>deps-dev:</strong> bump nanoid from 3.3.15 to 3.3.16 (<a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/875">#875</a>)
(<a
href="e67dacdcac">e67dacd</a>)</li>
<li><strong>deps:</strong> bump
<code>@​anthropic-ai/claude-agent-sdk</code> to 0.3.207 (<a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/874">#874</a>)
(<a
href="c7f5b8fe76">c7f5b8f</a>)</li>
</ul>
<h3>Bug Fixes</h3>
<ul>
<li>Add subagent parent tool use attribution (<a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/859">#859</a>)
(<a
href="9cd48c597a">9cd48c5</a>)</li>
<li>forward result text when the turn emitted no assistant message (<a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/858">#858</a>)
(<a
href="61ae8609d4">61ae860</a>)</li>
<li>hold a turn open while its background subagents are still live (<a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/870">#870</a>)
(<a
href="7a70f82739">7a70f82</a>)</li>
<li>Refine tool calls from streamed input (<a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/867">#867</a>)
(<a
href="2c19974d5b">2c19974</a>)</li>
<li>Seed context window from SDK usage report (<a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/868">#868</a>)
(<a
href="3ba2d367a2">3ba2d36</a>),
closes <a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/596">#596</a></li>
<li>Skip synthetic login messages on replay (<a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/869">#869</a>)
(<a
href="c7dff3cf7e">c7dff3c</a>),
closes <a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/863">#863</a></li>
</ul>
<h2>v0.58.1</h2>
<h2><a
href="https://github.com/agentclientprotocol/claude-agent-acp/compare/v0.58.0...v0.58.1">0.58.1</a>
(2026-07-09)</h2>
<h3>Bug Fixes</h3>
<ul>
<li>Use valid npm version for publish (<a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/855">#855</a>)
(<a
href="8b366d8e9a">8b366d8</a>)</li>
</ul>
<h2>v0.58.0</h2>
<h2><a
href="https://github.com/agentclientprotocol/claude-agent-acp/compare/v0.57.0...v0.58.0">0.58.0</a>
(2026-07-09)</h2>
<h3>Features</h3>
<ul>
<li><strong>deps:</strong> update to
<code>@​anthropic-ai/claude-agent-sdk</code> 0.3.205 (<a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/854">#854</a>)
(<a
href="f664ced76d">f664ced</a>)</li>
</ul>
<h3>Bug Fixes</h3>
<ul>
<li>Preserve live model on resumed sessions (<a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/848">#848</a>)
(<a
href="f3d8ae3eb3">f3d8ae3</a>),
closes <a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/845">#845</a></li>
<li>Report usage for cancelled active turns (<a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/846">#846</a>)
(<a
href="b03318f59c">b03318f</a>),
closes <a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/844">#844</a></li>
<li>tolerate missing text in streamed thinking chunks (<a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/852">#852</a>)
(<a
href="e944ceddea">e944ced</a>)</li>
<li>Use SDK guards for elicitation validation (<a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/850">#850</a>)
(<a
href="32b93501d7">32b9350</a>)</li>
</ul>
<h2>v0.57.0</h2>
<h2><a
href="https://github.com/agentclientprotocol/claude-agent-acp/compare/v0.56.0...v0.57.0">0.57.0</a>
(2026-07-07)</h2>
<h3>Features</h3>
<ul>
<li>Update <code>@​anthropic-ai/claude-agent-sdk</code> to 0.3.202 (<a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/843">#843</a>)
(<a
href="1612c07895">1612c07</a>)</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/agentclientprotocol/claude-agent-acp/blob/main/CHANGELOG.md">@​agentclientprotocol/claude-agent-acp's
changelog</a>.</em></p>
<blockquote>
<h2><a
href="https://github.com/agentclientprotocol/claude-agent-acp/compare/v0.58.1...v0.59.0">0.59.0</a>
(2026-07-13)</h2>
<h3>Features</h3>
<ul>
<li><strong>deps-dev:</strong> bump nanoid from 3.3.15 to 3.3.16 (<a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/875">#875</a>)
(<a
href="e67dacdcac">e67dacd</a>)</li>
<li><strong>deps:</strong> bump
<code>@​anthropic-ai/claude-agent-sdk</code> to 0.3.207 (<a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/874">#874</a>)
(<a
href="c7f5b8fe76">c7f5b8f</a>)</li>
</ul>
<h3>Bug Fixes</h3>
<ul>
<li>Add subagent parent tool use attribution (<a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/859">#859</a>)
(<a
href="9cd48c597a">9cd48c5</a>)</li>
<li>forward result text when the turn emitted no assistant message (<a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/858">#858</a>)
(<a
href="61ae8609d4">61ae860</a>)</li>
<li>hold a turn open while its background subagents are still live (<a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/870">#870</a>)
(<a
href="7a70f82739">7a70f82</a>)</li>
<li>Refine tool calls from streamed input (<a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/867">#867</a>)
(<a
href="2c19974d5b">2c19974</a>)</li>
<li>Seed context window from SDK usage report (<a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/868">#868</a>)
(<a
href="3ba2d367a2">3ba2d36</a>),
closes <a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/596">#596</a></li>
<li>Skip synthetic login messages on replay (<a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/869">#869</a>)
(<a
href="c7dff3cf7e">c7dff3c</a>),
closes <a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/863">#863</a></li>
</ul>
<h2><a
href="https://github.com/agentclientprotocol/claude-agent-acp/compare/v0.58.0...v0.58.1">0.58.1</a>
(2026-07-09)</h2>
<h3>Bug Fixes</h3>
<ul>
<li>Use valid npm version for publish (<a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/855">#855</a>)
(<a
href="8b366d8e9a">8b366d8</a>)</li>
</ul>
<h2><a
href="https://github.com/agentclientprotocol/claude-agent-acp/compare/v0.57.0...v0.58.0">0.58.0</a>
(2026-07-09)</h2>
<h3>Features</h3>
<ul>
<li><strong>deps:</strong> update to
<code>@​anthropic-ai/claude-agent-sdk</code> 0.3.205 (<a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/854">#854</a>)
(<a
href="f664ced76d">f664ced</a>)</li>
</ul>
<h3>Bug Fixes</h3>
<ul>
<li>Preserve live model on resumed sessions (<a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/848">#848</a>)
(<a
href="f3d8ae3eb3">f3d8ae3</a>),
closes <a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/845">#845</a></li>
<li>Report usage for cancelled active turns (<a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/846">#846</a>)
(<a
href="b03318f59c">b03318f</a>),
closes <a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/844">#844</a></li>
<li>tolerate missing text in streamed thinking chunks (<a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/852">#852</a>)
(<a
href="e944ceddea">e944ced</a>)</li>
<li>Use SDK guards for elicitation validation (<a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/850">#850</a>)
(<a
href="32b93501d7">32b9350</a>)</li>
</ul>
<h2><a
href="https://github.com/agentclientprotocol/claude-agent-acp/compare/v0.56.0...v0.57.0">0.57.0</a>
(2026-07-07)</h2>
<h3>Features</h3>
<ul>
<li>Update <code>@​anthropic-ai/claude-agent-sdk</code> to 0.3.202 (<a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/843">#843</a>)
(<a
href="1612c07895">1612c07</a>)</li>
</ul>
<h3>Bug Fixes</h3>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="30b7c06f76"><code>30b7c06</code></a>
chore(main): release 0.59.0 (<a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/860">#860</a>)</li>
<li><a
href="c7f5b8fe76"><code>c7f5b8f</code></a>
feat(deps): bump <code>@​anthropic-ai/claude-agent-sdk</code> to 0.3.207
(<a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/874">#874</a>)</li>
<li><a
href="7a70f82739"><code>7a70f82</code></a>
fix: hold a turn open while its background subagents are still live (<a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/870">#870</a>)</li>
<li><a
href="e67dacdcac"><code>e67dacd</code></a>
feat(deps-dev): bump nanoid from 3.3.15 to 3.3.16 (<a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/875">#875</a>)</li>
<li><a
href="61ae8609d4"><code>61ae860</code></a>
fix: forward result text when the turn emitted no assistant message (<a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/858">#858</a>)</li>
<li><a
href="2c19974d5b"><code>2c19974</code></a>
fix: Refine tool calls from streamed input (<a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/867">#867</a>)</li>
<li><a
href="c7dff3cf7e"><code>c7dff3c</code></a>
fix: Skip synthetic login messages on replay (<a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/869">#869</a>)</li>
<li><a
href="3ba2d367a2"><code>3ba2d36</code></a>
fix: Seed context window from SDK usage report (<a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/868">#868</a>)</li>
<li><a
href="f4e750decf"><code>f4e750d</code></a>
feat(deps): bump the minor group with 11 updates (<a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/862">#862</a>)</li>
<li><a
href="9cd48c597a"><code>9cd48c5</code></a>
fix: Add subagent parent tool use attribution (<a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/859">#859</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/agentclientprotocol/claude-agent-acp/compare/v0.52.0...v0.59.0">compare
view</a></li>
</ul>
</details>
<br />

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-16 13:17:13 -05:00
Dotta 5a5c918705
fix(acpx): configure Codex models at startup (#9700)
Move Codex ACPX model, reasoning effort, and fast-mode settings into CODEX_CONFIG startup config so arbitrary model IDs avoid ACP session picker validation.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-07-16 11:41:48 -05:00
Dotta 9a92124c63
fix(codex-local): raise default output-inactivity timeout to 30m (#9699)
## Thinking Path

> - Paperclip is the open source control plane for managing AI-agent
companies.
> - Agent adapters are responsible for launching, observing, and
terminating provider processes safely.
> - The local Codex adapter uses an output-inactivity monitor to stop
genuinely hung child processes.
> - The existing seven-minute default also stopped legitimate
long-running tasks that emitted no output while tests or remote checks
were still running.
> - Explicit per-agent timeout overrides already provide configuration
flexibility, so the smallest safe correction is to increase only the
default window.
> - This pull request raises the default to 30 minutes, retains the
existing termination behavior, and adds a regression assertion for the
new value.
> - The benefit is fewer unnecessary Codex restarts while still bounding
genuinely silent processes well below the platform safety limit.

## Linked Issues or Issue Description

**Pre-submission checklist**
- Searched open and closed GitHub issues and pull requests; no duplicate
fix exists. The original inactivity monitor was introduced in #5017.
- Reproduces on the current `master` implementation.
- The termination originates in Paperclip's Codex adapter inactivity
monitor rather than the model provider or local configuration.

**What happened?**
Long-running `codex_local` tasks were terminated after seven minutes
without stdout or stderr, even when the child process was still
performing legitimate work such as a quiet test suite or waiting for
remote checks.

**Expected behavior**
The default inactivity window should tolerate common long-running quiet
tasks while continuing to terminate processes that remain silent for an
extended period.

**Steps to reproduce**
1. Start a `codex_local` run with the default
`outputInactivityTimeoutMs` configuration.
2. Have the child process perform legitimate work without emitting
stdout or stderr for more than seven minutes.
3. Observe the adapter terminate the process at the old default
threshold.

**Version / deployment**
Current `master`, built from source in local/self-hosted deployments,
using the Codex adapter. This behavior is not database- or
access-context-specific.

## What Changed

- Raise `DEFAULT_CODEX_OUTPUT_INACTIVITY_TIMEOUT_MS` from seven minutes
to 30 minutes.
- Update the adapter configuration documentation to state the new
default.
- Add a focused regression assertion that pins the default to 30
minutes.

## Verification

- `pnpm vitest run
packages/adapters/codex-local/src/server/output-inactivity-monitor.test.ts`
— 15 tests passed.
- `pnpm --filter @paperclipai/adapter-codex-local typecheck` — passed.

## Risks

- Low risk: only the fallback default changes; explicit positive timeout
values and `null` disablement retain their existing behavior.
- A genuinely silent Codex process now remains alive up to 23 minutes
longer before the same SIGTERM/SIGKILL cleanup path runs.
- No schema, API, migration, UI, or workflow changes are included.

> This is a focused bug fix and does not overlap with planned core
feature work in `ROADMAP.md`.

## Model Used

- Anthropic Claude Fable 5 via the `claude_local` adapter produced the
initial investigation and implementation with repository/tool access.
- OpenAI Codex via the Codex CLI prepared the PR, added the focused
regression assertion, and ran verification; the runtime did not expose a
more specific model ID or 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)
- [ ] I have used a public-friendly branch name without internal tracker
identifiers (execution-workspace exception: this branch is
runtime-managed and cannot be renamed)
- [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

The source branch is execution-workspace managed and cannot be renamed
during this run; the PR title and body intentionally contain no internal
tracker references.

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-07-16 11:41:29 -05:00
Dotta df2404d443
fix(codex): count raw child output as activity (#9632)
## Thinking Path

> - Paperclip is the open source control plane teams use to manage AI
agents and their work
> - The Codex local adapter supervises CLI child processes and
terminates genuinely silent runs
> - The existing inactivity timer only recognized parsed JSONL stdout
events as activity
> - Long verification commands can emit ordinary stdout or stderr while
producing no JSONL, so healthy children could be killed
> - This pull request makes the watchdog observe raw child-process
output before filtering or parsing
> - The benefit is that long typecheck, build, and test phases survive
while truly silent children remain bounded

## Linked Issues or Issue Description

- **Bug:** The Codex output-inactivity watchdog could terminate healthy
runs during long verification phases because non-JSON stdout and stderr
did not reset its timer.
- **Expected:** Any bytes emitted by the child process count as output
activity; only a child with no stdout or stderr for the configured
interval is terminated.
- **Reproduction:** Configure a short `outputInactivityTimeoutMs`, run a
Codex child that periodically emits plain-text verification progress
without JSONL events, and observe the old monitor firing despite
continued output.
- **Deployment mode:** Local `codex_local` adapter execution.
- Related implementation: #5017
- Related recovery behavior: #8680

## What Changed

- Reset the Codex inactivity monitor on every non-empty stdout or stderr
chunk before stderr noise filtering.
- Track raw output chunk and byte counts in monitor diagnostics while
retaining parsed JSONL event counts.
- Add regression coverage for more than 21 simulated minutes of non-JSON
verification output and retain silent-child termination coverage.
- Document that `outputInactivityTimeoutMs` observes raw child output
and that `null` still disables the monitor.

## Verification

- `/srv/paperclip/home/paperclipai/paperclip/node_modules/.bin/vitest
run
packages/adapters/codex-local/src/server/output-inactivity-monitor.test.ts
packages/adapters/codex-local/src/server/output-inactivity-monitor.integration.test.ts`
- `/srv/paperclip/home/paperclipai/paperclip/node_modules/.bin/tsc -p
packages/adapters/codex-local/tsconfig.json --noEmit`

## Risks

- Low risk: the monitor becomes more conservative and may allow a
noisy-but-stuck child to run longer, but the configured hard timeout and
platform silent-run safety net remain unchanged.
- No schema, API, migration, or UI changes.

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

## Model Used

- OpenAI Codex CLI coding agent; runtime model ID and context-window
size were not exposed to the agent. Used repository/tool access, code
execution, and focused test verification.

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-07-15 21:49:30 -05:00
Dotta d32ed88443
fix(recovery): route recovery by failure cause (#9634)
## Thinking Path

> - Paperclip is the open source control plane people use to coordinate
AI-agent companies and their work.
> - Its recovery subsystem detects stranded issue execution and decides
whether to retry, escalate, or request operator intervention.
> - The existing recovery path used a mostly generic owner ladder and
generic execution contract, so transient failures could wake a manager
who then performed the deliverable instead of repairing and returning
the task.
> - Provider quota failures also entered the same takeover path even
when the correct action was to wait for capacity and retry the original
assignee.
> - Recovery actions already retain the source owner and evidence needed
to choose a cause-specific route, render a scoped contract, and measure
whether work was handed back.
> - This pull request adds a cause-keyed recovery playbook, propagates
its contract through every built-in adapter, and makes resolved recovery
actions return work to the original owner by default.
> - The benefit is bounded self-recovery that preserves task ownership,
avoids needless management takeover, and makes recovery outcomes
observable.

## Linked Issues or Issue Description

No matching public GitHub issue was found.

Related recovery work was reviewed but is not duplicated here: #9630
restores bounded recovery continuations, #8807 changes one
assignee-ranking case, and #9404 records runtime-failure transition
evidence. This change instead introduces cause-specific routing and
recovery contracts across the recovery lifecycle.

### What happened?

When an issue became stranded, recovery generally selected an owner
through the same fallback ladder and rendered the normal execution
contract. That made the recovery wake look like ordinary deliverable
work, even when the correct action was to retry the original agent,
repair its runtime, or wait for a provider quota reset.

### Expected behavior

Recovery should select a response by failure cause, tell the recipient
to recover rather than complete the deliverable, suppress takeover wakes
for provider quota waits, and return repaired work to its original
assignee unless the recovery owner explicitly completes it.

### Actual behavior

Recovery could escalate transient failures to management, omit the
cause-specific next action from the wake, and leave the recovery owner
assigned after the runtime problem was resolved.

### Impact

The generic path creates avoidable management work, ownership churn, and
budget consumption while obscuring whether recovery successfully
returned work to the responsible agent.

## What Changed

- Added cause-keyed routing for process loss, missing disposition,
provider quota limits, Codex output inactivity, workspace validation
failures, and fallback recovery causes.
- Added recovery-scoped wake rendering that replaces the generic
execution contract with the failure summary, original assignee, attempt
count, next action, and cause-specific playbook instruction.
- Propagated the structured recovery contract through all built-in
adapter execution paths, including Hermes local and gateway adapters.
- Added provider-quota wait monitoring so capacity failures schedule the
original assignee instead of enqueueing a takeover wake.
- Added hand-back behavior and `handed_back` / `owner_completed` outcome
accounting when recovery actions are resolved.
- Added focused routing, renderer, quota-monitor, and hand-back
regression coverage plus implementation-spec documentation.

## Verification

- `pnpm exec vitest run packages/adapter-utils/src/server-utils.test.ts
server/src/__tests__/heartbeat-process-recovery.test.ts
server/src/__tests__/heartbeat-workspace-branch-containment.test.ts
server/src/__tests__/issue-recovery-actions.test.ts`
  - 4 test files passed; 194 tests passed.
- Targeted `pnpm --filter ... typecheck` across
`@paperclipai/adapter-utils`, `@paperclipai/shared`,
`@paperclipai/server`, `@paperclipai/ui`, and all nine changed adapter
packages.
  - 13 affected workspace packages passed typecheck.
- `pnpm check:token-gates`
  - All UI token gates passed.

## Risks

- Recovery routing behavior changes for stranded work, so an incorrectly
classified cause could select a different recipient than before;
fallback causes retain the existing management ladder.
- Provider quota detection depends on structured failure evidence and
conservative text matching; unmatched failures continue through fallback
recovery.
- Adapter prompt plumbing changes across built-ins, covered by shared
renderer tests and compile-time call signatures.

> 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 exact model ID `gpt-5.6-sol`, using reasoning, tool
use, and code execution. The runtime does not expose its configured
context-window size.

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-07-15 20:04:42 -05:00
Nicky Leach 3a727bf780
fix(codex): warn when sandbox auth is shadowed (#9259) 2026-07-15 10:02:28 -07:00