Skip to content

Richer emergency handoff note from runtime-reconstructed facts #180

Closed

Description

@lbacik

This was generated by AI during triage.

Split out of #159 (part 3). See the glossary term Emergency handoff note in CONTEXT.md.

Agent Brief

Category: enhancement
Summary: When the model reaches a limit without writing a handoff note, the runtime writes an emergency handoff note that carries everything it can reconstruct.

Current behavior:
When model execution ends with MODEL_LIMIT_REACHED and no note commit exists for this attempt, the runtime writes a note with _build_emergency_handoff_note. The note contains:

  • the four header fields (issue, started_at, reason, last_work_commit)
  • a one-line explanation
  • the fixed remaining-work line "Review progress preserved on this branch and continue implementation."

A continuation, as in #155, has nothing to go on. The runtime also discards the seal commit returned by seal(). Model execution doesn't record the last assistant text, the tool calls, or the model's Bash commands and their exit status; these exist only as archived log files.

Desired behavior:
The emergency handoff note keeps its title and four header fields exactly as today, so the note validator still passes. It then contains these sections, in order:

  • Provenance: says the runtime wrote this note because the model did not, and which limit fired (the existing reason plus the explanation).
  • Changes:
    • git diff --stat <base>..<seal or HEAD>
    • the attempt's commits (git log --oneline <base>..HEAD)
    • the files that were uncommitted when sealing happened (the files in the seal commit), or "none" when there was no seal commit
    • the edited-files list is capped at 50 entries with a +N more line
  • Last model intent: the last assistant text message, truncated to about 1,500 characters, and whether the handoff skill was invoked on the main thread (invoked / not invoked).
  • Activity trail:
    • the files the model edited or created (from Edit/Write calls)
    • the last 15 tool calls, as the tool name, a short target and an ok/error flag
    • the last Bash call whose command contains one of the profile's check commands, with its ok/error flag, or "none recorded"
  • Check state: "final check: not run" (the runtime doesn't run it on this path), plus the result of the pre-model baseline check if one ran.
  • Budget facts:
    • budget_tokens, max_budget_tokens
    • where the soft threshold was crossed, or "not crossed"
    • peak_main_context_tokens
    • main-thread prompt-cache hit rate
    • number of turns
    • elapsed time
  • Pointers: the attempt log directory, if there is an archive, and the CLI transcript session id, if known.
  • Remaining work: states that the runtime could not determine what remains, that the issue's acceptance criteria are the reference, and that none were verified by the runtime. Don't copy the issue body: the continuation's prompt already includes it.

Each part degrades gracefully: a missing archive, session id or baseline check, or no tool calls, renders as "not available" rather than failing.

Key interfaces:

  • _build_emergency_handoff_note(...): takes the additional facts and renders the sections above.
  • ModelExecution: gains the last assistant text and a bounded activity record (edited paths, recent tool calls with ok/error, last check-command call). These are recorded in memory by the PreToolUse/PostToolUse hooks, not parsed back from the archive.
  • The token budget summary (token_budget): add explicit budget_tokens, turns and elapsed time if they're not already present.
  • The runner keeps the commit returned by seal() so it can name the files that sealing committed.

Acceptance criteria:

  • An attempt that hits the token hard ceiling without a model-written note produces an emergency handoff note with all sections above, and it passes _validate_handoff_note (test).
  • Same for the turn-limit and cost-limit paths (reason is turn_limit / cost_hard_limit).
  • The tool-call trail is bounded at 15 entries, the edited-files list at 50 entries with +N more, and the assistant text at about 1,500 characters (unit tests).
  • With no archive, no session id, no baseline check and no tool calls, the note still renders with "not available" / "none recorded" and validates (test).
  • The note says plainly that the runtime wrote it and that the final check was not run.
  • A model-written note is never replaced or altered (existing tests keep passing).

Out of scope:

  • Running the final check before writing the note.
  • Copying acceptance criteria or checklists from the issue body.
  • Changing when an emergency note is written, or the four header fields.
  • The soft-threshold calculation and the model-facing handoff flow (separate sub-issues).

Activity

  1. added
    enhancementNew feature or request
    ready-for-agentFully specified implementation issue ready for an unattended agent
    on Oct 8, 2026
  2. self-assigned this
    on Oct 8, 2026
  3. lbacik commented on Oct 8, 2026

    @lbacik
    OwnerAuthor

    Agent Attempt Result: complete

    Branch: agent/issue-180
    PR: #183

    Evidence

    • Check command: /home/agent/target-venv/bin/python -m pytest → exit code 0
    • Review cycles: 0/2
    • Review findings: all clear

    Details

    Claude SDK completed the implementation workflow.

  4. removed
    ready-for-agentFully specified implementation issue ready for an unattended agent
    on Oct 8, 2026
  5. removed their assignment
    on Oct 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions