Skip to content

feat(adopt): accept transcripts under the agent's recorded homes - #2716

Merged
hiddeco merged 2 commits into
mainfrom
hidde/adopt-across-homes
Oct 9, 2026
Merged

hiddeco merged 2 commits into
mainfrom
hidde/adopt-across-homes

Conversation

@hiddeco

@hiddeco hiddeco commented Oct 8, 2026 •

Copy link
Copy Markdown
Contributor

https://entire.io/gh/entireio/cli/trails/1531

Splitting #2636 into smaller chunks. Builds on #2710.


entire session adopt can now adopt a session whose transcript lives under one of the agent's recorded homes rather than its active one. Before this, adopt only accepted a transcript in the session directory of an agent's active home. So a session started under CLAUDE_CONFIG_DIR=~/.claude-work could not be adopted from a plain shell, or from a shell running another CLAUDE_CONFIG_DIR. It failed with "… is not owned by a registered agent".

What changes

  • A trusted AgentHome can authorize the transcript. When the source state names an AgentHome that agent.ResolveTrustedHome accepts (the active home or one in agent_homes.json), the session transcript and its declared task transcripts may also lie where that home keeps the source worktree's sessions. Paths are compared in the spelling ResolveTrustedHome returns. Task transcripts must still match the agent's task layout (TaskTranscriptMatcher). Every other path is checked against the active home as before.
  • The check is scoped to the source worktree, not the whole store. The new agent.RepoHomeLayout narrows the agent's stores the same way its session directory is narrowed under the active home: Claude Code's project directory, or every store for an agent without per-project directories such as Codex (so archived rollouts are accepted). For the active home this is exactly the check adopt already made. A trusted home never admits another project's files, such as projects/<other>/memory/MEMORY.md.
  • Adopted state keeps AgentHome only when it holds the transcript. It is kept in the checked spelling. Only that home vouches for task transcripts. An untrusted home, or one that does not hold the transcript, is cleared, and the next turn start records the home the agent runs under. Previously AgentHome was copied verbatim.
  • Clearer refusals.
    • When the home was refused, the error says why and names the relocation variables (agent.RelocationEnvVars).
    • When the home is trusted but the path is outside the worktree's session directory, it says that instead, without the variable hint.

Threat model

Unchanged from #2703. Session state imported with adopt --from is untrusted, so a home it names authorizes nothing until ResolveTrustedHome matches it against homes the user's own environment resolved. Narrowing to the source worktree keeps foreign state from naming other projects' files in the user's stores, which condensation would read into a checkpoint. Local files only the user can write remain outside the boundary.

Behaviour for users without relocated homes

Unchanged. AgentHome is usually the active home, whose narrowed layout is the session directory adopt already checked.

Not in this PR

  • Windows: a foreign AgentHome naming a UNC path reaches EvalSymlinks inside ResolveTrustedHome. Codex condensation already did this. The fix belongs in ResolveTrustedHome (match lexically before touching the filesystem).
  • Binding the transcript's file name to the session ID, which would also reject predictably named files inside the source worktree's own project directory. This is pre-existing.
  • Size-bounded, regular-file transcript reads.
  • Adopting across homes for an agent that keeps sessions outside its home, such as Pi with PI_CODING_AGENT_SESSION_DIR: there is nothing beneath the session's home to check against, so such a session is adopted only where that store is active. Adopt says so instead of suggesting a relocation variable.

Testing

  • mise run check.

  • New tests:

    • Adopting a Claude session and task transcript under a recorded home while another home is active. The out-of-layout task transcript is still dropped.
    • An unrecorded home: refused, with the reason and the relocation variables.
    • Another project's file under a recorded home and under the active home: refused, without the variable hint.
    • A state with no AgentHome: the recorded home is not consulted.
    • A home that does not hold the transcript (untrusted, trusted, or with no agent type): cleared from the adopted state.
    • Codex: an archived rollout and a child rollout under a recorded home, and a stale home vouching for no task.
    • A session without a transcript keeps no home, so the home vouches for no task transcript.
    • A Pi home whose sessions live outside it: reported as uncheckable, without the variable hint.
    • agent.RepoHomeLayout per layout shape.
  • Each fix was checked by removing it and confirming its test fails.

  • Manually with the built binary, in an isolated HOME, using real Claude session-start and prompt hooks under a relocated CLAUDE_CONFIG_DIR. Main refuses and this branch adopts:

    • a CLAUDE_CONFIG_DIR=work session, from a plain shell.
    • a personal session, from a shell with CLAUDE_CONFIG_DIR=work.

    A commit in the target repo then condensed both transcripts into the checkpoint. A foreign unrecorded home and another project's file were refused.

entire session adopt only accepted a transcript in the session directory
of an agent's active home, so a session recorded under CLAUDE_CONFIG_DIR
(or another relocated home) could not be adopted from a shell that runs
the agent elsewhere.

When the source session names an AgentHome that agent.ResolveTrustedHome
accepts, the session transcript and its declared task transcripts may
also lie where that home keeps the source worktree's sessions. The new
agent.RepoHomeLayout narrows the agent's stores to the worktree the same
way its session directory is narrowed under the active home (Claude
Code's project directory; every store for Codex), so a trusted home
admits no other project's files, and for the active home the check is
the one adopt already made. Task transcripts still have to match the
agent's task layout. Other paths are checked against the active home as
before.

Only a trusted home that holds the transcript is kept in the adopted
state and vouches for task transcripts; any other home is cleared. The
not-owned error names the relocation variables and why the recorded
home was refused.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Entire-Checkpoint: 01M4EQ4XJPDMT3GNBGK97G5AT7
@hiddeco
hiddeco requested a review from a team as a code owner October 8, 2026 22:21
Copilot AI balanced review requested due to automatic review settings October 8, 2026 22:21

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

An empty main transcript can incorrectly retain a trusted home and authorize task transcript paths.

1 open finding
What changed in this PR

Enables session adoption across trusted recorded agent homes while preserving repository-scoped transcript validation.

Changes:

  • Adds repository-scoped agent-home layouts and adoption validation.
  • Retains trusted homes only when authorized and validates task transcripts.
  • Adds cross-home tests and updates architecture/security documentation.
File Description
docs/​development/​filesystem-safety.md Documents trusted-home adoption rules.
docs/​architecture/​sessions-and-checkpoints.md Updates task transcript validation architecture.
cmd/​entire/​cli/​session_adopt.go Implements trusted-home adoption and validation.
cmd/​entire/​cli/​session_adopt_test.go Updates adoption helper calls.
cmd/​entire/​cli/​session_adopt_task_test.go Updates task validation tests.
cmd/​entire/​cli/​session_adopt_home_test.go Tests cross-home adoption scenarios.
cmd/​entire/​cli/​agent/​home_layout.go Adds repository-narrowed home layouts.
cmd/​entire/​cli/​agent/​agent_homes_test.go Tests repository layout narrowing.

🧠 Review effort: Balanced


💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread cmd/entire/cli/session_adopt.go Outdated
…omes

A source session without a transcript returned its trusted AgentHome,
which was then kept and vouched for task transcripts with no transcript
behind it. validateAdoptSourceTranscript now returns a home only when it
holds the session's transcript, as the docs already said, and skips the
registry lookup when there is no transcript.

When the agent keeps the worktree's sessions outside its active home
(agent.RepoHomeLayout reports false), the error said the recorded home
"was refused" and suggested setting a relocation variable. The home was
not refused, and the variable is already set. The error now says the
home cannot be checked and why, without the hint. Such a session (Pi
with PI_CODING_AGENT_SESSION_DIR, for one) still cannot be adopted
across homes, only where that store is active.

Also rejoin a line the previous reflow stranded in
sessions-and-checkpoints.md.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Entire-Checkpoint: 01M4FXET0XJV4ZEQY9JSP2QSKR
@hiddeco
hiddeco merged commit 31a42c5 into main Oct 9, 2026
18 checks passed
@hiddeco
hiddeco deleted the hidde/adopt-across-homes branch October 9, 2026 10:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

3 participants