paperclip/docker/daytona-runner
Nicky Leach c1b55537ba
fix(paperclip-runner): bump claude-agent-acp pin to 0.73.0 (#13162)
## Thinking Path

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

## Linked Issues or Issue Description

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

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

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

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

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

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

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

## What Changed

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

## Verification

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

## Risks

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

## Model Used

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

## Checklist

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

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

---------

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-10 11:35:33 -07:00
..
Dockerfile fix(paperclip-runner): bump claude-agent-acp pin to 0.73.0 (#13162) 2026-09-10 11:35:33 -07:00
README.md fix: share current CLI runtimes across sandbox adapters (#12994) 2026-09-07 10:09:29 -05:00

README.md

Paperclip Daytona runner image

This image is the Paperclip Cloud fleet sandbox image plus a source-built paperclip-runnerd and immutable provider pack. The pack contains Node 24.11, OpenCode 1.18.29, the compiled OpenCode proxy, ACPX 0.13.1 sidecar, qualified ACP agents, and the production lockfile. Its manifest digests each executable bridge and binds the pack to the runner source revision, avoiding artifact upload and npm installation on every fresh lease.

The fleet pins are intentionally copied from paperclip-cloud/fleet-sandbox-image/Dockerfile. Update both definitions together until the fleet base is published as a stable image that this Dockerfile can extend directly.

Build and verify

The fleet image is currently amd64-only because the pinned Cursor and GitHub CLI checksums cover amd64.

content_id="$(pnpm --silent test:e2e:runner:image-id)"
docker buildx build \
  --platform linux/amd64 \
  --build-arg PAPERCLIP_RUNNER_CONTENT_ID="${content_id}" \
  --build-arg PAPERCLIP_RUNNER_SOURCE_REVISION="$(git rev-parse HEAD)" \
  --tag "paperclip-daytona-runner:e2e-content-${content_id}" \
  --load \
  --file docker/daytona-runner/Dockerfile \
  .

docker run --rm --platform linux/amd64 \
  --entrypoint paperclip-runnerd \
  "paperclip-daytona-runner:e2e-content-${content_id}" \
  --build-metadata

The metadata must advertise dial_ws_loopback, dial_wss, and listen_ws. The explicit entrypoint is needed only for this local probe because Daytona's base image uses its own long-running sandbox entrypoint.

test:e2e:runner:image-id hashes the audited Docker build dependency closure, target platform, the immutable Dockerfile syntax-frontend digest, and every immutable FROM reference. It fails before the paid workflow can build when the frontend or a base is not pinned to a sha256 digest. When updating the syntax version, resolve and review its registry digest and update both values in the first Dockerfile line. Git commits that do not change those inputs reuse the same content tag.

PAPERCLIP_RUNNER_SOURCE_REVISION remains the full Git SHA that built the first published copy and is retained as provenance rather than cache identity.

Use in Paperclip

Publish the image to a registry Daytona can pull, or use the environment editor's Configure image flow to produce a Daytona snapshot. Set the environment image to that immutable tag or snapshot. Paperclip probes the sandbox user's PATH for paperclip-runnerd and codex and checks /opt/paperclip-runner/provider-pack for OpenCode and ACPX. It uses the pack only when its complete manifest matches the controller's build-owned pack; otherwise it stages the pack configured by PAPERCLIP_RUNNER_REMOTE_PROVIDER_PACK_PATH. Remote OpenCode and ACPX never fall back to host-local processes.

Do not promote paperclip-runner-e2e-20260826-v2 for OpenCode or ACPX. Build a new immutable image or snapshot from a clean committed revision and pass that full Git SHA as PAPERCLIP_RUNNER_SOURCE_REVISION.

Do not bake provider credentials, Paperclip bootstrap tickets, or Daytona preview tokens into this image. They remain per-run secret material.

Provider CLI updates are manifest-only changes: repository CI owns the root lockfile. The image build resolves the complete workspace manifest graph before its frozen install, matching CI when a source commit precedes the lockfile bot. The complete resolved lockfile must match PAPERCLIP_RUNNER_LOCK_SHA256 before package installation or lifecycle execution. Review and refresh that digest with source dependency changes; registry-time resolution drift fails closed. Keep one latest stable CLI installation per provider; refresh exact runtime versions and qualification digests together, never install a private older copy or download dependencies when a task starts.