## Thinking Path
> - Paperclip is the open source app people use to manage AI agents for
work.
> - A durable ACPX session must resume only the workspace, profile,
model, policy, and provider session that created it.
> - Sanitized directory names can collide, and lexical workspace paths
can change meaning through symbolic links.
> - Schema-less draft records cannot prove workspace or
normalized-session provenance.
> - This pull request establishes one closed v1 identity format and
rejects records that cannot prove every immutable binding.
> - The benefit is fail-closed recovery without enabling or selecting
the ACPX runtime.
## Linked Issues or Issue Description
**Agent or provider**
Durable sessions for qualified Pi, Claude, and Codex ACP servers through
the internal ACPX driver.
**Why this adapter is useful**
The runner must prevent a persisted provider session from being reused
with another workspace, model, permission policy, profile, or normalized
session. It must also distinguish normalized session names that sanitize
to the same pathname.
**How the agent is invoked**
A later pull request will use this binding when the private ACPX runtime
opens or recovers a session. This pull request does not launch a
process, add a dependency, register an adapter, or change runtime
selection.
**Compatibility boundary**
No ACPX identity writer exists on master or in a shipped runtime. This
pull request establishes the first accepted persisted format. Draft
schema-less records and early-v1 command-digest records cannot prove
every immutable binding and are intentionally rejected; an affected
experimental session must start fresh.
## What Changed
- Resolve real workspace and runtime-directory paths and reject
filesystem roots or non-directories.
- Derive collision-resistant runtime roots and provider session keys.
- Bind the session key to workspace, complete qualified profile, model,
protocol, agent, and permission mode.
- Add a closed v1 ACPX identity record.
- Verify controller identity and persisted identity against every
immutable binding.
- Reject schema-less, early-digest, unknown-version, unknown-field, and
malformed records.
- Add tests for canonical paths, collision resistance, drift,
workspace/session replay, missing policy, malformed records, and unsafe
roots.
## Verification
- GitHub Actions are the authoritative typecheck, test, build, and
integration gate for the final head.
- Greptile, Superagent, and Snyk are required to pass on the final head.
- `git diff --check` passes for the two-file delta.
- The diff does not change `pnpm-lock.yaml`, a workflow, a dependency, a
public export, server selection, migration, or UI behavior.
## Risks
The main risk is accepting an identity under a different immutable
session configuration. Controller and v1 record fields are compared
exactly, including permission mode and the complete qualified-profile
digest. Records that lack workspace/session provenance or use an
obsolete partial digest fail closed. Because no writer for those draft
formats has shipped, requiring a fresh experimental session is safer
than synthesizing missing authority from the current 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 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 linked an existing public item or described the
issue in this PR
- [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 tests where applicable
- [x] I have documented the recovery and compatibility boundary
- [ ] All applicable GitHub Actions are green on the final head
- [ ] Greptile is 5/5 with every actionable comment resolved
- [x] I will address all review findings before requesting merge