Files
PaperClipAI/packages/paperclip-runner/test
DottaandClaude Opus 5.5 1880526603 fix(runner): never start an OpenCode session without its Paperclip tools (#20964)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - Native OpenCode agents use Paperclip tools through a local MCP
bridge in the runner
> - OpenCode 1.18 connects each MCP server one time per process. It does
not retry
> - One failed `initialize` or `tools/list` at startup marks the
Paperclip server "failed" for the full session
> - The agent then works with only built-in tools. In one chat it told
the person "Switched the working design to blue", but no saved state
supported this claim
> - This pull request makes the runner confirm the Paperclip tools while
the session loads, reconnect them, restart OpenCode if necessary, and
fail the session by name if the tools stay unavailable
> - The benefit is that an OpenCode turn never starts without its
Paperclip tools, so the agent cannot silently claim actions that it
could not do

## Linked Issues or Issue Description

Refs #20886, #20921.

**What happened**
In chat eval `steering.steer-active` (private paid run 43086418488, on a
commit with #20886 and without #20921), two of three OpenCode sessions
started without Paperclip tools. One was the CEO chat (fresh session).
One was the worker task after its saved session resumed in a new
OpenCode process. The CEO agent ran `opencode mcp list` and saw
`paperclip ✗ failed — Failed to get tools`. It then sent a request to
the bridge without the bearer token and got HTTP 401. That 401 came from
its own probe, not from OpenCode. The run still succeeded with the reply
"Switched the working design to blue …", because a plain chat reply
counts as the result.

**Expected behavior**
Every native OpenCode session starts with the Paperclip MCP tools. If
the tools cannot be loaded, the session fails with a named reason, and
the turn does not start without tools.

**Steps to reproduce**
1. Start OpenCode 1.18.34 with a remote MCP server whose first
`tools/list` request fails (for example, the server resets the socket
one time).
2. `GET /mcp` returns `{"paperclip":{"status":"failed","error":"Failed
to get tools"}}`. OpenCode keeps this status for the life of the
process.
3. `POST /mcp/paperclip/connect` returns `true`, and then `GET /mcp`
returns `connected` (about 8 ms). We measured this with the real 1.18.34
binary.

This is the same class as #20886: `Connection: close` made the one-shot
startup connect fail more often (about 9 of 25 sessions), and #20921
removed the trigger. Any other transient failure at startup still
produced a toolless session. This change removes the class.

## What Changed

- `opencode-server-driver.ts`: while a session opens (fresh, resumed or
recovered), the driver reads OpenCode's `GET /mcp`. If the `paperclip`
server is not `connected`, it calls `POST /mcp/paperclip/connect` up to
two times. If the server is still not connected, it throws
`paperclip_tools_unavailable`. The existing startup retry restarts
OpenCode for this error (three attempts in total). After that, the
session fails visibly.
- The check runs in parallel with session creation or resume. The added
work on a healthy start is one local HTTP request.
- `fake-opencode-server.mjs`: the fixture now serves `GET /mcp` and
`POST /mcp/paperclip/connect`. It connects to the real bridge with the
configured token, and it can simulate failed connects.
- New `paperclip-tools-startup.test.ts`: reconnect after one failed
connect, restart after a process stays failed, reconnect on a saved
session that resumes in a new process, and a named failure when the
tools never load. All four tests fail on master (master opens a toolless
session).

## Verification

- `pnpm exec vitest run
src/drivers/opencode/paperclip-tools-startup.test.ts` (in
`packages/paperclip-runner`): 4 passed. Red on master: 4 failed.
- All OpenCode driver, proxy, live runnerd OpenCode and native-runtime
server suites that use the fixture: 29 files, 567 tests passed.
- `node --test scripts/contracts/contract-fingerprints.test.mjs`: 11
passed. `tsc --noEmit -p packages/paperclip-runner`: clean.
- Real OpenCode 1.18.34 probe (failure, then `connect`, then
`connected`) as in the steps above.
- Paid chat eval run 43117909094 on this change (steering.steer-active
and three other OpenCode chat cases). Result is in a comment on this PR.

## Risks

- Low. A healthy start adds one local `GET /mcp` request, in parallel
with session creation.
- If OpenCode cannot load the Paperclip tools after reconnects and
restarts, the session now fails with `paperclip_tools_unavailable`.
Before, it ran without tools. This is intended.
- No persisted run, session or pack state changes. A session saved by
the previous release resumes through the same open path and gets the
same check.

## Model Used

- Anthropic Claude Opus 5.5 (`claude-opus-5-5`), agentic coding with
tool use (shell, file edits, GitHub 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

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

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-11 18:07:38 -06:00
..