Commit Graph
2 Commits
Author SHA1 Message Date
cc127f5516 fix(runner): drop unusable musl builds and duplicate Copilot from provider packs (#17387)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - The runner release builds a Linux "provider pack". The pack is a
self-contained runtime with Node, Claude Code, Codex, and OpenCode. The
Daytona runner image and SSH hosts use it.
> - The release artifacts for this pack are large: 1,182 MB for
linux-x64 and 543 MB for linux-arm64.
> - Most of that size is necessary. But about 20–30% of it is code that
the pack can never run.
> - pnpm 9 installs all libc variants of optional platform packages.
Thus the pack includes the musl (Alpine) builds of Claude Code and
OpenCode. The pack runs only its copied glibc Node, so these builds are
never used.
> - On linux-x64, the npm Copilot package is also a byte-identical copy
of the verified Copilot provider asset (162 MB).
> - This pull request removes these unused bytes from the pack at build
time.
> - The benefit is smaller release artifacts and Docker images, and
faster uploads and downloads.

## Linked Issues or Issue Description

**What happened?**
The runner release workflow uploads `runner-provider-packs-linux-x64`
(1,182 MB) and `runner-provider-packs-linux-arm64` (543 MB). The darwin
daemon artifacts are about 10 MB. The darwin artifacts are a different
artifact type, so the comparison is not direct. But inspection of the
extracted Linux packs found real waste:
- `@anthropic-ai/claude-agent-sdk-linux-*-musl` (about 225 MB
uncompressed)
- `opencode-linux-*-musl` and `opencode-linux-x64-baseline-musl` (about
180 MB each)
- on linux-x64,
`node_modules/.pnpm/@github+copilot-linux-x64@1.0.88/.../copilot`, which
has the same SHA-256 (`0059754c…`) as
`provider-assets/copilot/linux-x64/copilot`

**Expected behavior**
The pack contains only code that its copied Node and its launch shims
can run.

**Paperclip version or commit**
`master` at `e0d9033`. The inspected release run built commit `837add0`.

**Steps to reproduce**
1. Install `@agentclientprotocol/claude-agent-acp@0.73.0` and
`opencode-ai@1.18.34` with pnpm 9.15.4 on a glibc Linux host.
2. List `node_modules/.pnpm`.
3. See the `*-musl` entries. Their `package.json` declares `"libc":
["musl"]`.

## What Changed

- `provider-pack-runtime-tree.mjs`: add `providerPackLibc()`. It reports
the libc of the Node that the pack copies (`glibc` or `musl` on Linux,
none on other platforms).
- `provider-pack-runtime-tree.mjs`: add
`removeForeignLibcPackagesFromProviderPack()`. It removes each pnpm
virtual-store entry whose own `package.json` declares a `libc` list
without the pack libc. Packages without a `libc` field stay (for example
`@openai/codex-linux-*`, which holds Codex's static musl binary).
- `provider-pack-runtime-tree.mjs`: add `removePnpmStoreEntries()`. It
removes store entries and every symlink that resolves into them, so no
dangling link stays in the pack. It refuses names outside
`node_modules/.pnpm`.
- `provider-pack-executable-shims.mjs`: when
`provider-assets/copilot/<platform>/copilot` has the same bytes as the
npm Copilot executable, the `copilot-<platform>` command now points at
the asset and the npm copy is removed. If the bytes are different, the
old behavior stays.
- `build-provider-pack.mjs`: run the libc prune immediately after `pnpm
deploy`. Log the removed entries.
- No file bound by `provider-pack.json` changes. Thus the manifest
digest and the qualification and digest pins do not change.

## Verification

- `node --test
packages/paperclip-runner/scripts/provider-pack-runtime-tree.test.mjs
packages/paperclip-runner/scripts/provider-pack-executable-shims.test.mjs
packages/paperclip-runner/scripts/candidate-provider-pack.test.mjs
packages/paperclip-runner/scripts/release-provider-pack.test.mjs`: 40/40
pass.
- The new Copilot test fails with the old
`provider-pack-executable-shims.mjs` and passes with the new file.
- A real pnpm 9.15.4 tree with the pack's provider dependencies, on
linux-x64 (glibc):
- The prune removed `@anthropic-ai+claude-agent-sdk-linux-x64-musl`,
`opencode-linux-x64-musl`, and `opencode-linux-x64-baseline-musl`. The
Copilot dedupe removed the npm Copilot entry.
  - `node_modules` changed from 1.9 GB to 1.1 GB.
  - `find node_modules -xtype l` found no dangling links.
- The claude-agent-acp SDK still resolves
`@anthropic-ai/claude-agent-sdk-linux-x64/claude`.
  - `opencode --version` prints `1.18.34`.
- The rewritten `copilot-linux-x64` prints `GitHub Copilot CLI 1.0.88.`
- Earlier measurement: we pruned the same paths from the extracted pack
artifacts and compressed them again with `tar -czf`. linux-x64 went from
1131 MB to 876 MB. linux-arm64 went from 519 MB to 360 MB.
- Not run locally: a full `build-provider-pack.mjs` build. This sandbox
has 10 GB of disk, which is not sufficient for a full workspace install
and a 3 GB pack. The `release-verify.yml` provider-pack step and the
Daytona image `RUN claude/codex/acpx --version` checks run the full
build.
- `test/acpx-codex-package-contract.test.mjs` has 1 failure in this
sandbox, and the failure is the same on `master`. The cause is that this
checkout has no `node_modules`.

## Risks

- Low risk. All pack builds run on glibc hosts (Debian bookworm images
and Ubuntu CI). On a musl build host, the prune removes the glibc
packages, and the existing Claude executable resolution fails at build
time. Before this change, that build gave a pack with a Claude binary
that could not run.
- The `copilot-linux-x64` command now runs the binary from
`provider-assets/copilot/linux-x64/`. The bytes are identical. Runtime
admission already uses this asset, through the descriptor-pinned lease.
- The pack content changes but the manifest digest does not. The remote
verifier checks only the bound artifacts, `dist`, and provider asset
trees. None of these change.
- Not in this pull request: Pi's bundled Node is byte-identical to the
pack Node (121 MB, about 43 MB compressed). A fix for it changes the
qualified Pi closure digest. Also, the `release.yml` publish jobs
download the full packs, but they read only `provider-pack.json`. These
are possible follow-ups.

## Model Used

- Claude Opus 5.5 (Anthropic), model ID `claude-opus-5-5`, used through
Claude Code with tool use (shell, file edit) and code execution in a
sandbox.

## Checklist

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

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

Co-authored-by: devinfoley <139239+devinfoley@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 16:41:14 -07:00
Devin FoleyandPaperclip 0ac194450a fix: make Copilot provider-pack wrappers portable (#15586)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Container images include a movable provider pack for agent
execution.
> - pnpm executable wrappers can contain the temporary build directory.
> - New optional Copilot packages add wrappers that the build does not
replace.
> - This pull request gives those installed wrappers relative executable
paths.
> - Image publication can finish while the existing path check remains
enforced.

## Linked Issues or Issue Description

Refs #15572 and #15560. The small portability loop comes from
cryppadotta's larger Copilot runtime PR #15560. This separate fix
repairs image publication without waiting for that feature's
qualification and runtime changes. That PR can remove its duplicate loop
after this lands.

**What happened?**

The standard Docker build stops with `Provider pack shim
copilot-linux-x64 retains its temporary build path`. The failure
occurred before and after #15522. See [the failed master
build](https://github.com/paperclipai/paperclip/actions/runs/37802065316).

**Expected behavior**

Installed native Copilot wrappers resolve their pinned executable after
the provider pack moves. Optional packages that are absent do not gain a
command. The builder still rejects wrappers with temporary paths.

**Steps to reproduce**

1. Run the provider-pack build from the affected master revision on
Linux x64.
2. Let `pnpm deploy --prod` install the optional Copilot package.
3. The wrapper scan rejects its temporary `NODE_PATH`.

**Paperclip version or commit**

Master `3367b75ccce34d02f355cda1f1ed3fe0b34cf93d`.

**Deployment mode**

Docker and provider-pack builds.

## What Changed

- Replace installed Copilot platform wrappers with relative native
executable launchers.
- Move the existing executable wrapper writer into an importable helper.
Retain the same launch behavior for Node, Claude and OpenCode.
- Test relocation, argument handling, exit status, absent optional
packages and missing executable packages. Register the tests in the
existing Runner test preparation command.
- Hash the helper in Daytona image identity and prove that helper
changes invalidate the image cache.
- Document the packaging rule. Keep dependencies, provider qualification
and the final temporary-path check unchanged.

## Verification

- 17 Node packaging tests passed across the new wrapper tests,
provider-pack release tests and candidate selection tests.
- Six existing bundled remote-provider-pack tests passed using the
Runner Vitest configuration.
- Nine Daytona image identity tests and Runner E2E typecheck passed
after the cache-input correction.
- `pnpm -r typecheck`: passed.
- `pnpm build`: passed.
- Real `pnpm deploy --prod` reproduction on macOS ARM64: the original
Copilot wrapper contained the temporary path. After the rewrite and
directory relocation, the actual executable returned Copilot CLI 1.0.88
with exit code zero using only `/usr/bin:/bin` in `PATH`.
- Syntax checks, `git diff --check` and the pre-push secret scan passed.
- The full local `pnpm test:run` reproduced the same five
skill/connector fixture failures observed earlier in this workspace. It
was stopped after current-head clean-checkout CI passed; later local
phases were not run. This local run is not claimed as passing. Focused
packaging tests, workspace typecheck/build and all hosted CI passed.
- [Hosted Docker verification
passed](https://github.com/paperclipai/paperclip/actions/runs/37804902678):
Linux AMD64 and ARM64 image builds, multi-architecture publication and
the process-reaping smoke check. This run tested
`779d94989c54d9abbeba0838194c951186af66a6`; the only later changes are
Daytona cache identity and its regression test. Provider-pack build code
is identical. Local Docker did not respond within the bounded probe.
- Current head `db2c19e270b8d5a7bab5db39d3de0e4761cf57c3`: 54 successful
checks, two conditional skips, no failures and no merge conflicts. Apex
is 5/5 with no unresolved comments.

## Risks

The helper uses each installed package's exported executable. An
installed wrapper with a missing package still fails the build. This
change does not execute Copilot during image construction, alter
dependency pins, change runtime admission or weaken the temporary-path
check.

## Model Used

OpenAI GPT-6 via Codex, with reasoning, repository inspection, tool use
and code execution. The exact serving model identifier and context
window are not exposed in this session.

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-08 09:33:24 -07:00