Skip to content

Conversation

@Soph
Copy link
Collaborator

@Soph Soph commented Feb 9, 2026

Claude Code's git commit -m during a session produced commits without Entire-Checkpoint trailers, so session metadata was never linked to commits.

Two problems in the prepare-commit-msg hook's -m flag path:

  1. Content detection bails out early mid-session (no shadow branch yet, transcript analysis fails)
  2. Even when it doesn't, askConfirmTTY blocks waiting for input the agent can't provide

Tests missed this because GitCommitWithShadowHooks didn't pass source="message", always taking the editor path which unconditionally adds trailers.

Fix: Use TTY availability to distinguish agent from human. Agents don't have a controlling terminal — hasTTY() checks /dev/tty. When !hasTTY() and a session is ACTIVE, a fast path adds the trailer directly, bypassing content detection and TTY prompts. The human flow is unchanged.

Tests now pass source="message" and use ENTIRE_TEST_TTY=1 (human) or ENTIRE_TEST_TTY=0 (agent) to control the TTY check deterministically.


Note

Medium Risk
Changes git hook behavior for a specific non-interactive execution path; risk is mainly misclassifying environments as no-TTY and adding trailers more broadly than intended, affecting commit metadata linkage.

Overview
Fixes missing Entire-Checkpoint trailers for mid-session agent git commit -m by detecting lack of a controlling TTY and taking a fast path.

manual_commit’s prepare-commit-msg hook now, when !hasTTY() and any session is ACTIVE, bypasses transcript/content detection and interactive confirmation and directly writes a generated (or pending) checkpoint trailer via addTrailerForAgentCommit.

Integration tests were updated to better mirror real git commit -m (source="message"), add deterministic TTY simulation via ENTIRE_TEST_TTY, and include a new test asserting agent commits always receive the trailer.

Written by Cursor Bugbot for commit 2645133. This will update automatically on new commits. Configure here.

@Soph Soph requested a review from a team as a code owner February 9, 2026 13:56
Copilot AI review requested due to automatic review settings February 9, 2026 13:56
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

Entire-Checkpoint: 02d49af5bfe0
@Soph Soph force-pushed the soph/fix-midsession-commit branch from c1f3267 to f07c305 Compare February 9, 2026 15:00
@khaong
Copy link
Contributor

khaong commented Feb 10, 2026

Note on TTY behavior

The hasTTY() fast path won't trigger for the primary use case (Claude Code running in a user's terminal). Agent subprocesses inherit the controlling terminal from the parent process, so /dev/tty is available even for agent-invoked commits:

Terminal (has TTY)
  └─ Claude Code (inherits TTY)
       └─ git commit -m "..." (inherits TTY)
            └─ prepare-commit-msg hook (inherits TTY)
                 └─ hasTTY() → opens /dev/tty → true

hasTTY() only returns false in truly headless environments (CI, cron, daemons, setsid-detached processes).

The main mid-session commit fix landed in PR #184 (path normalization, BaseCommit staleness, PendingCheckpointID lifecycle). This PR's fast path is a safety net for headless edge cases, not the primary detection mechanism. The test infrastructure improvements (ENTIRE_TEST_TTY, source="message", GitCommitWithShadowHooksAsAgent) are the main value here.

@khaong
Copy link
Contributor

khaong commented Feb 10, 2026

Correction: TTY behavior is correct

Disregard my previous comment — I verified empirically and the assumption is correct.

Claude Code spawns Bash subprocesses with pipes (to capture stdout/stderr), not a PTY. This means child processes don't have a controlling terminal:

$ ps -o tty -p $$
TTY
??
$ python3 -c "import os; os.open('/dev/tty', os.O_RDWR)"
OSError: [Errno 6] Device not configured

So the actual flow is:

Terminal (has TTY)
  └─ Claude Code (captures output via pipes, no PTY)
       └─ bash subprocess (no controlling terminal, TTY=??)
            └─ git commit -m "..." (inherits: no TTY)
                 └─ prepare-commit-msg hook (no TTY)
                      └─ hasTTY() → false ✓

The fast path correctly triggers for agent-invoked commits and is skipped for human commits at the terminal. LGTM.

@khaong khaong enabled auto-merge February 10, 2026 00:52
@khaong khaong merged commit b4080a2 into main Feb 10, 2026
4 checks passed
@khaong khaong deleted the soph/fix-midsession-commit branch February 10, 2026 00:58
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