Skip to content

Fix #251: session handoff file for long-running work - #257

Merged
vicgupta merged 1 commit into
mainfrom
amf/issue-251
Oct 30, 2026
Merged

vicgupta merged 1 commit into
mainfrom
amf/issue-251

Conversation

@vicgupta

Copy link
Copy Markdown
Owner

Closes #251

Summary

Adds an opt-in session handoff for long-running work, following the long-running harness pattern from the issue:

  • --handoff / handoff.enabled: true (off by default; --handoff=false turns it off).
  • Run start: a fresh run reads .tinyagent/handoff.md (configurable handoff.path) and places it before the task in the first user message inside a <session_handoff> block that labels it as data from earlier sessions, not instructions (AGENTS.md and the task outrank it), like project memory. Capped by handoff.max_bytes (16 KiB), with a truncation marker. A missing file tells the model it's the first session.
  • Startup command: optional handoff.startup_command, run with sh -c in --cwd before the first turn, bounded by handoff.startup_timeout_seconds (120); its exit code and the tail of its output (handoff.startup_max_output, 8 KiB) are given to the model as data. Failures warn and the run continues.
  • Run end: tinyagent atomically rewrites the handoff file with time, model, status, trajectory path, task, final answer (the model is asked to end it with what was done, next steps and how to start/verify) and the startup command; flags untrusted context if the run was tainted.
  • --json events: handoff.loaded, handoff.startup, handoff.saved (no file text or command output).

New code lives in internal/handoff, internal/config/handoff.go and cmd/tinyagent/handoff_run.go; main.go only gets the flag field, the override, and two calls. agent.Agent gains a TaskPreamble field so the handoff rides in the first user message (t.Task stays the bare task and resume needs no system-prompt reconstruction).

Decisions on open questions

  • Off by default; settings come only from the user config, -c or a profile (never the repository), so a repo can't set a startup command.
  • handoff.path must be relative and stay inside --cwd.
  • The handoff is injected into the first user message, not the system prompt, so --resume/follow-ups replay it from the checkpoint and don't reload, rerun or rewrite anything.
  • --read-only runs load the file but skip the startup command and don't rewrite the file.
  • The file is written by tinyagent from the run's task, status and final answer (deterministic, testable) rather than by a model tool call.
  • The startup command runs on the host like a hook, outside any sandbox/container (documented).
  • Workers, delegated subagents and --acp sessions don't use the handoff.

Testing

  • gofmt -l . clean; go build ./..., go vet ./..., go test -count=1 ./... pass.
  • New tests (fake model server only): internal/handoff (load/truncate, preamble wrapping, render/write, startup exit code/tail/timeout), internal/config (defaults off, YAML parsing, validation errors), cmd/tinyagent (off by default, write-then-load across two runs, startup command output in context + JSON events + custom path, --handoff=false, read-only leaves the file).

Docs updated

  • README.md feature list (linked to the new section) and docs table row
  • docs/subcommands.md (--handoff)
  • docs/config.md (handoff: keys)
  • docs/json-output.md (three new events)
  • docs/long-runs.md (new "Session handoff" section)

--handoff / handoff.enabled reads .tinyagent/handoff.md into the first
message as data, runs an optional handoff.startup_command before the
first turn, and rewrites the file with the task, status and final answer
when the run ends. Docs: README, subcommands, config, json-output,
long-runs.
@vicgupta
vicgupta merged commit 05898bb into main Oct 30, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Session handoff file for long-running work

1 participant