Files
PaperClipAI/doc/runner-launch-preparation.md
Nicky LeachandPaperclip 6d61990692 fix: allow managed Git helpers to select a private interpreter (#18337)
## 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>
2026-10-30 09:29:51 -07:00

90 lines
4.6 KiB
Markdown

# Runner launch preparation
Core selects the provider, model, instructions, tools, and task permissions.
The execution environment supplies executable paths and filesystem locations.
The built-in TypeScript implementation constructs the provider descriptor in
`createRunnerProviderLaunch`. The transport sends this descriptor with
`run.prepare`. Provider backends keep their existing validation and session rules.
By default, the SDK prepares local files. It stages remote files through the
existing execution driver.
## Environment-owned preparation
An execution driver can supply `prepareLaunch`.
The callback receives `RunnerProviderLaunchRequirements`.
It returns `PreparedRunnerProviderLaunch`.
Requirements contain the selected provider, model, policy, run identity, and
runtime context. They do not contain task text, process callbacks, provider
credentials, or controller executable choices. Resource paths identify source
locations. They do not grant filesystem access on the execution host.
The environment resolves its resources and prepares the provider descriptor.
It can use `bindRunnerLaunchResources` to replace registered context locations.
It can use `createRunnerProviderLaunch` for the existing descriptor projection.
The transport does not perform its built-in file preparation in this mode.
The process owner supplies the Runner artifact and process lifecycle.
The result contains a configuration ID, a requirements digest, and a provider
descriptor. The transport checks Core's selected profile and policy before
registration and launch. Core still supplies authorized tools and completion
criteria through PRP. A failed preparation does not enable a fallback launch.
### Codex probe policy
Core can select `settings.disableCodexProjectInstructions` for a hello probe.
Preparation must preserve it as `project_doc_max_bytes=0` before `app-server`,
after any environment-supplied overrides. Core validates this setting alongside
`disableCodexWebSearch`. Ordinary tasks retain project instructions when the
setting is absent or false. This does not change the selected filesystem policy.
### Working directory
In this mode the environment chooses the provider working directory. Core does
not supply one. The backend uses `workingDirectoryAuthority:
"runner_prepared_launch"`, and its controller environment stays empty.
- Core authorizes the agent, task, projects, and workspace binding.
- The environment resolves that assignment into mounts and the descriptor's
`cwd`. For a projectless task it selects its own default directory.
- The transport accepts only a normalized absolute `cwd` that is not a
filesystem root. Runnerd validates the directory on its own filesystem.
- The transport reports that `cwd` to the driver. The driver records it in
session context, snapshots, and recovery, and ignores the caller's directory.
- Recovery and run attachment must keep the same `cwd`. A runner snapshot or
recovered thread that reports another directory fails recovery. Core does not
substitute a controller-local or temporary directory.
`remote_runner` remains the mode in which Core assigns the remote directory
through `PAPERCLIP_WORKSPACE_CWD`.
The transport saves the exact requirements and prepared configuration in its
private `launch-preparation.json` file. The file holds at most two records.
A new attachment keeps the active run's record. Runner commands contain the
provider descriptor once. They do not contain these recovery records.
Recovery within the same run must return the same configuration. This rule also
applies during an interrupted warm attachment. A new run uses its current
requirements. For a new run, `runtimeContext: null` removes the assigned context.
Only an omitted context can reuse the previous context.
Provider session compatibility checks remain in their existing
backends. Close waits for preparation within its deadline. A timeout retains an
unsettled checkpoint and prevents reuse.
## Plugin task protocol
The [environment task API](plugins/PLUGIN_ENVIRONMENT_TASKS.md#launch-preparation)
defines the plugin preparation exchange. The [native plugin integration](plugins/PLUGIN_RUNNER_EXECUTION.md)
connects the callback to task execution. A Launcher implementation remains the
execution owner's responsibility.
## Managed Git helper interpreter
`githubLauncherSource({ interpreterPath })` can select an absolute Node interpreter
owned by the execution environment. Without this option, generated helpers retain
`#!/usr/bin/env node`. The option changes only the shebang; it does not change PATH,
command discovery, credential handling, or helper behavior. Interpreter paths must
be absolute and contain no whitespace or NUL bytes.