## Thinking Path
> - Paperclip is the open source app people use to manage AI agents for
work.
> - A qualified ACPX profile binds exact provider and runtime package
versions.
> - Package metadata alone does not prove which executable will run.
> - A pathname, directory entry, or open inode can still change after
verification.
> - A verified launch therefore needs a one-use lease over entry bytes
and retained directories, with ambient loader and package authority
removed.
> - Provider compatibility is admitted later, per provider; this
primitive must fail closed when a provider needs an unqualified path or
dependency.
## Linked Issues or Issue Description
**Agent or provider**
Internal qualified ACPX profiles. The first production consumer remains
Codex-only in the follow-on dependency and adapter changes.
**Why this adapter is useful**
The runner needs to prove that installed package metadata and executable
bytes match a reviewed profile, then prevent pathname replacement,
symlink escape, host-package lookup, or loader injection from changing
what executes.
**How the agent is invoked**
A later provider-specific adapter requests an opaque one-use command
lease. On Linux, the lease starts Node with a synchronous hook, supplies
the verified entry snapshot over a private pipe, and retains only the
verified package directories needed by that profile. This pull request
does not register an adapter, change runtime selection, or make any
provider user-visible.
**Compatibility boundary**
The launched entry deliberately has a Linux descriptor-backed identity
such as `/proc/self/fd/4/...`; preserving a mutable canonical pathname
would reopen the replacement vulnerability. A provider that requires
canonical `import.meta.url`, `__filename`, or `process.argv[1]` is not
admitted by this primitive until its provider-specific adapter proves
compatibility. Likewise, arbitrary package-manager ancestors are not
retained. Hoisted dependencies must be explicitly qualified by a later
provider-specific layer; otherwise startup fails closed. The initial
production slice is Codex only, not Pi or Claude.
## What Changed
- Verify exact server and optional runtime package versions from bounded
metadata.
- Require one supported relative Node executable and reject ambiguous or
package-escaping paths.
- Canonicalize the command directory and open final components without
following symbolic links.
- Bound and hash the open entry file while checking device, inode, size,
and timestamps around the read.
- Return an opaque installation and one-use launch lease instead of an
executable pathname.
- Reopen and revalidate retained directory and executable identities
when acquiring a lease.
- Load the admitted entry bytes and package-contained modules through
retained Linux descriptors.
- Resolve CommonJS and ESM bare imports only from retained roots, reject
host ancestors, and make symlink escape terminal.
- Open module bytes with `O_NOFOLLOW`, bound each read, recheck
identity, and reject native or unsupported module formats.
- Strip Node, native dynamic-loader, glibc, and OpenSSL injection
variables before spawn.
- Add regressions for replacement races, direct resources, sibling and
ancestor imports, explicit runtime roots, host-ancestor denial,
descendant and final symlinks, bounded reads, and environment injection.
## Verification
- The authoritative GitHub Actions and exact-head Greptile review are
the merge gates for the final head.
- Prettier and `git diff --check` pass for the final two-file diff.
- The diff does not change `pnpm-lock.yaml`, workflows, dependencies,
public exports, server selection, or UI behavior.
## Risks
The security/compatibility tradeoff is explicit: descriptor identity
prevents a replaced lexical path from supplying resources, but
pathname-sensitive providers require a later adapter-specific
qualification. Unqualified or unsupported dependencies, native addons,
non-Linux launch, and unsupported module formats fail closed. No
production call path reaches this primitive in this pull request.
## Model Used
OpenAI Codex with GPT-5 and repository tool use.
## 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 does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have described the issue and provider boundary above
- [x] I have not referenced internal or instance-local Paperclip issues
or links
- [x] My branch name describes the change and contains no internal task
identifier
- [x] I have added or updated affected tests
- [x] I have documented the trust, compatibility, dependency, and
rollout boundaries
- [ ] All applicable GitHub Actions are green on the final head
- [ ] Greptile is 5/5 on the final head with every actionable comment
resolved