## Thinking Path > - Paperclip manages AI agents and their execution environments. > - Managed Git helpers run next to those agents. > - Some environments keep their Node interpreter outside the agent PATH. > - The current generator always emits an env-based Node shebang. > - This pull request lets the environment select an absolute interpreter path. > - Existing callers keep the same default behavior. ## Linked Issues or Issue Description Refs #18212. **What happened?** A managed helper can fail when Node exists only as a private runtime binary. The caller must currently alter generated source or expose that runtime through PATH. **Expected behavior** The source generator accepts an optional interpreter path. The environment can keep its own runtime private. **Steps to reproduce** Generate a helper in an environment whose PATH has no usable Node. Run a local Git command through that helper. The env-based shebang cannot select the private interpreter. ## What Changed - Add optional `interpreterPath` to `githubLauncherSource`. - Preserve `/usr/bin/env node` when the option is absent. - Reject relative paths, whitespace and NUL bytes. - Document the option and test actual execution with an unusable Node on PATH. ## Verification - The affected adapter-utils package typecheck passed. - All 26 tests in `packages/adapter-utils/src/github-launcher.test.ts` passed. - The new test runs a generated helper as a child process. It proves that the selected interpreter bypasses a failing PATH-selected Node and that the helper body stays unchanged. - Invalid-path tests passed. Existing broker and local-Git tests passed. - Full checks run in GitHub CI per the user's request. No full local suite was run. ## Risks The option changes only the shebang. Callers own interpreter installation and immutability. Default behavior, PATH, credentials and permission policy stay unchanged. No schema or workflow changes. ## Model Used OpenAI GPT-6.1 Sol (`gpt-6.1-sol`), high reasoning, with source inspection and targeted execution. The host does not expose an exact 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>
@paperclipai/adapter-utils
Shared utilities for Paperclip adapters: process spawning, environment injection, sandbox/SSH transport, workspace sync, and the round-trip helpers that move code between the local execution-workspace cwd and wherever the agent actually runs.
For the adapter-author guide see
docs/adapters/creating-an-adapter.md
and the in-repo notes at packages/adapters/AUTHORING.md.
Sandbox bridge deadlines
Command-managed bridge control operations (queue reads, input delivery, setup, and cleanup) have a host-enforced deadline of at most 30 seconds per shell command. A shorter configured timeout still applies. These operations cannot inherit the agent run's hours-long lifetime or wait forever on a provider that ignores its timeout. Long-lived agent session commands keep their own limits.
A control timeout reports a transport failure. It does not prove that the remote command stopped and does not replay an uncertain write. The process session closes failed input delivery and uses its existing shutdown path; normal execution settlement must still verify termination.
No-remote-git contract
The local execution-workspace cwd is the only persistence boundary across runs. No adapter may depend on a git remote for cross-run state.
Adapters that run the agent on a different host should use the SSH round-trip
helpers in src/ssh.ts:
prepareWorkspaceForSshExecution({ spec, localDir, remoteDir })— bundles the local cwd (tracked files, dirty edits, untracked additions, and the git history needed to reconstruct it) toremoteDirbefore the run starts. Runs with nogit remoteconfigured.restoreWorkspaceFromSshExecution({ spec, localDir, remoteDir, ... })— syncs the remote cwd back intolocalDirafter the run, including any new commits the agent created. Also runs with nogit remoteconfigured.
prepareRemoteManagedRuntime in
src/remote-managed-runtime.ts wraps both
calls for adapters that want a per-run remote workspace and an automatic
restoreWorkspace() finally hook.
The invariant is pinned by the no-remote-git contract case in
src/ssh-fixture.test.ts, which asserts that a
remote-only commit propagates to the local worktree through the
prepare → restore round-trip with no git remote configured at any point. Do
not regress that test.