Skip to content

Link files that agents change through shell commands - #2720

Open
Soph wants to merge 4 commits into
mainfrom
soph/shell-edit-linking
Open

Soph wants to merge 4 commits into
mainfrom
soph/shell-edit-linking

Conversation

@Soph

@Soph Soph commented Oct 9, 2026 •

Copy link
Copy Markdown
Collaborator

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

Summary

Since #2692, a commit links to a session by the files the session recorded. Two cases recorded nothing when an agent changed a file through a shell command, so the commit carrying that file got no Entire-Checkpoint trailer.

Shell edit to a file that was already untracked. Turn end excludes untracked files that existed at prompt start from "new", and git status cannot report an untracked file as modified, so the edit was invisible. The prompt-start baseline now also records each untracked file's stat data (PrePromptState.UntrackedFileStats): size, modification time, inode and status-change time, the fields git's index compares. The change time catches a same-size rewrite that restores the modification time (cp -p, touch -r); Windows has no change time, so only size and modification time are compared there. At turn end, a baseline file whose stat data changed joins the modified list before filterToUncommittedFiles, so a file committed mid-turn is still dropped. Stat data instead of content hashes keeps UserPromptSubmit free of an extra git hash-object per prompt.

File created by a background subagent's shell command after the parent's turn ended. A background SubagentStop deliberately skips the worktree scan (it would sweep in the parent's and other agents' concurrent work), and the transcript names no file. Once the parent's next prompt starts, the file sits in that prompt's untracked baseline, so no later turn end claims it. SubagentStop now also claims untracked files created since the task launched that no session in the same worktree has recorded (unrecordedNewFilesSinceLaunch). Files the parent's own turns or another session recorded are excluded. When another background task in the worktree overlapped this one (new TaskRecord.Background flag, still live or completed after this task's launch), nothing is claimed, since the first task to stop would otherwise take both tasks' files. Accepted trade-off: a file the user creates while the parent is idle is claimed as well. Since #2692 removed line attribution, that only adds a session link to the commit carrying it, which matches what turn end already does for user edits made during an active turn.

The first commit also pins the ordering from #2653: a background task completes mid-turn and the parent commits in the same turn. The commit links, lists the file, and carries the subagent transcript. #2653's reported symptom was in line attribution, which #2692 removed.

Tests

  • TestSubagentCheckpoints_BackgroundTaskCompletesMidTurn_ParentCommitLinks: the Background subagent's lines are attributed to the human when the parent commits in the same turn #2653 ordering. It fails if the subagent's completion is dropped.
  • TestShellEditToPreExistingUntrackedFile_LinksCommit: the shell-edited file is recorded and linked, and an untouched pre-existing untracked file is not recorded.
  • TestBackgroundSubagentShellCreatedFile_LinksCommit: the subagent's shell-created file is recorded and linked.
  • TestShellRewriteKeepingSizeAndMtime_IsRecorded: a same-size rewrite with the original modification time restored is still recorded. Skipped on Windows. It fails when the change time is dropped from the comparison.
  • TestOverlappingBackgroundTasks_ClaimNoNewFiles: two overlapping background tasks from different sessions each create a file, and neither session claims either file. It fails when the overlap check is removed.
  • TestBackgroundSubagentStop_ClaimsOnlyUnrecordedNewFiles: of five files, the task claims only the subagent's file and the user's idle-window file. It does not claim the pre-launch file, the parent's later-turn file, or another session's file. It fails when the "already recorded" exclusion is removed.

Both gap tests failed on main before the fix. Their controls, where the transcript names the file, passed.

mise run check passes.

🤖 Generated with Claude Code

Soph and others added 2 commits October 9, 2026 17:35
…nt commits

Covers the ordering from #2653: a background subagent appends to a tracked
file, its completion arrives while the parent is still active, and the parent
commits in the same turn. The commit links to the session, lists the file and
carries the subagent transcript.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Entire-Checkpoint: 01M4GMWV09RQNFG4SPEGH8HWRR
Two cases recorded nothing, so the commit carrying the file had no trailer:

- A shell edit to a file that was already untracked when the prompt started.
  git status lists it as untracked before and after. The prompt-start
  baseline now records each untracked file's size and modification time,
  and turn end treats a mismatch as a modified file.
- A file a background subagent creates through a shell command after the
  parent's turn ended. SubagentStop captures only transcript-named files,
  and the parent's next prompt puts the file in its untracked baseline.
  SubagentStop now also claims untracked files created since the task
  launched that no session in the worktree has recorded. A file the user
  creates while the parent is idle is claimed too; that only adds a
  session link to the commit carrying it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Entire-Checkpoint: 01M4H12QJ3CFVD038QA68DKB87
Copilot AI balanced review requested due to automatic review settings October 9, 2026 19:17
@Soph
Soph marked this pull request as ready for review October 9, 2026 19:17
@Soph
Soph requested a review from a team as a code owner October 9, 2026 19:17

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

Metadata collisions can miss edits, while concurrent background tasks can claim each other’s files.

2 open findings
What changed in this PR

Improves checkpoint linking for files changed by shell commands.

Changes:

  • Detects edits to pre-existing untracked files using metadata.
  • Claims unrecorded files created during background tasks.
  • Adds integration coverage and architecture documentation.
File Description
docs/​architecture/​sessions-and-checkpoints.md Documents shell-change capture behavior.
cmd/​entire/​cli/​strategy/​manual_commit_session.go Finds files recorded by worktree sessions.
cmd/​entire/​cli/​state.go Stores and compares untracked-file metadata.
cmd/​entire/​cli/​lifecycle.go Integrates shell-created files into capture.
cmd/​entire/​cli/​integration_test/​subagent_commit_in_turn_test.go Tests mid-turn subagent commits.
cmd/​entire/​cli/​integration_test/​shell_capture_test.go Tests shell-based file capture.

🧠 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/lifecycle.go
Comment thread cmd/entire/cli/state.go
Soph and others added 2 commits October 9, 2026 21:31
…tasks

- Size and modification time miss a same-size rewrite that restores the
  mtime (cp -p, touch -r). The untracked-file baseline now also records
  the inode and status-change time on linux and darwin, the stat fields
  git's index compares.
- Two overlapping background tasks made the first to stop claim both
  tasks' new files. Task records launched in the background now carry a
  Background flag, and a stop claims nothing when another background task
  in the worktree ran during its own.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Entire-Checkpoint: 01M4H2BZGFM85AKH05Z0996QF0
A stop that finds no launch marker (a resumed run under a new key) created
its record through launchStubTaskRecord, which dropped the flag, so an
overlapping task's claim check could not see it. The background stop path
now sets Background on the record it completes, the stub copies it, and
completion sets it on a record launched by an older CLI.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Entire-Checkpoint: 01M4H34V2EP4CH4NR01HZ7FWVJ
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.

2 participants