Skip to content

Trajectory Logging via Progress Files and Git History

A progress file, git commits, feature-state JSON, and a bootstrap script capture a replayable audit trail of agent decisions — no observability backend required.

Learn it hands-on with Breaking the Loop — a guided lesson with quizzes.

Also known as

Progress File Pattern, Audit Trail for Agent Decisions

The problem

Long-running agents make decisions across many sessions. Without a persistent record, each new session loses the trajectory: what was tried, what failed, and what the agent decided next. Rebuilding that context wastes tokens and produces inconsistent outcomes.

OTel GenAI semantic conventions solve this at the infrastructure level (OTel GenAI span conventions). The filesystem pattern solves the same problem with no backend and no extra dependencies.

The four-component harness

Anthropic's harness engineering guidance describes a pattern for long-running agents. It uses four components that together form a complete trajectory log.

graph TD
    A[init.sh bootstrap] --> B[Read progress file]
    B --> C[Select next feature from feature-state JSON]
    C --> D[Implement and commit]
    D --> E[Update progress file]
    E --> F[Commit trajectory checkpoint]
    F -->|next session| A

1. Progress file (claude-progress.txt)

A plain text or markdown file, updated at session end and read at session start. It captures what was completed, what is next in priority order, and any blockers. Reading it before work begins gives each fresh context window a recoverable record of prior decisions, without re-analyzing the full codebase.

2. Git commits as trajectory checkpoints

Agents commit after each completed task with descriptive messages. The git history then becomes a chronological, diff-linked record of every agent decision. Humans can read it and future sessions can query it via git log. A community best-practices guide recommends committing at least once per completed task.

3. Feature-state JSON as machine-readable snapshot

A JSON file tracks discrete features with passes/fails status. Agents set passes only after verification. The file survives context resets as an independent state snapshot, so the agent does not declare premature completion.

4. init.sh as environment trajectory

The initializer agent writes init.sh to rebuild the development environment. Later sessions run it at startup to confirm the environment is in a known-good state before any code changes.

Filesystem write-on-summarization

When context is compressed, the LangChain context management pattern writes full conversation messages to the filesystem alongside a structured summary: session intent, artifacts created, and next steps. The trajectory is offloaded rather than discarded.

When this is missing, a visible failure mode is goal drift. After summarization, agents ask for clarification they do not need or declare premature completion. Both signal that the trajectory was lost.

Active trajectory monitoring

Two middleware patterns from LangChain's harness engineering post extend the static logging pattern into active monitoring:

  • LoopDetectionMiddleware tracks per-file edit counts via tool-call hooks. When edits pile up, it injects a contextual reminder that catches doom loops before they exhaust the context budget.
  • PreCompletionChecklistMiddleware intercepts the agent before it signals completion. It forces a verification pass against the task spec, so the agent does not close the task too early.

When this backfires

The filesystem pattern assumes a persistent, local working directory. That assumption breaks in three common cases:

  • Serverless or ephemeral agents: containers spun up per request have no stable filesystem between invocations, so progress files and git state disappear on teardown.
  • Parallel agent pools: several concurrent sessions writing to the same progress file or committing to the same branch produce conflicts and race conditions.
  • Teams with existing observability infrastructure: when OTel pipelines, structured logging, or cost dashboards are already in place, copying trajectory data into flat files adds upkeep with no extra insight.

When any of these conditions apply, prefer structured observability backends (see OTel GenAI span conventions) over the filesystem approach.

Example

This shows the four-component harness in a real project layout. The agent maintains each file across sessions and commits it after every completed task.

my-project/
├── claude-progress.txt       # 1. progress file — read at start, updated at end
├── feature-state.json        # 3. machine-readable feature snapshot
├── init.sh                   # 4. environment trajectory / reproducibility check
└── src/
  1. claude-progress.txt, written by the agent at session end:
## Session 2026-03-11

Completed:
- Implemented POST /auth/login with RS256 JWT signing
- Private key loaded from env SECRET_KEY; verified with curl

Next (priority order):
1. Implement token refresh endpoint (POST /auth/refresh)
2. Write integration tests for /auth/login using pytest-httpx

Blockers:
- None
  1. feature-state.json, set only after verified completion:
{
  "features": [
    { "name": "POST /auth/login",        "passes": true  },
    { "name": "POST /auth/refresh",      "passes": false },
    { "name": "auth integration tests",  "passes": false }
  ]
}
  1. init.sh, run at the start of every session:
#!/usr/bin/env bash
set -euo pipefail

node --version | grep -qF "$(cat .nvmrc)" || { echo "Wrong Node version"; exit 1; }
npm ci --prefer-offline
timeout 5 npm run start:check || { echo "Server health check failed"; exit 1; }
echo "Environment OK"
  1. Git commit as a trajectory checkpoint:
git add src/auth/login.ts feature-state.json claude-progress.txt
git commit -m "feat(auth): implement POST /auth/login with RS256 JWT

- feature-state.json: /auth/login passes=true
- progress file: /auth/refresh listed as next task"

Each session runs bash init.sh, reads claude-progress.txt to recover prior decisions, consults feature-state.json to pick the next unfinished feature, implements and verifies it, then commits all artifacts. The result is a replayable audit trail with no external backend.

FAQ

How do git commits function as a trajectory record?

Agents commit after each completed task with descriptive messages, so the history becomes a chronological, diff-linked record of every decision. Humans can read it, and future sessions can query it with git log. A community best-practices guide recommends committing at least once per completed task, which keeps checkpoints fine-grained enough to reconstruct what happened between sessions.

What is init.sh for?

The initializer agent writes it to rebuild the development environment, and later sessions run it at startup to confirm the environment is in a known-good state before any code changes. It is the environment component of the trajectory: rather than assuming the workspace is intact after a gap between sessions, each session checks it first.

What happens to the trajectory when context is compressed?

In the LangChain context-management pattern, full conversation messages are written to the filesystem alongside a structured summary covering session intent, artifacts created, and next steps, so the trajectory is offloaded rather than discarded. When that write is missing, goal drift becomes visible: agents ask for clarification they do not need, or declare premature completion.

When should I use an observability backend instead?

When the filesystem assumption breaks. Serverless or ephemeral agents have no stable directory between invocations, so progress files and git state disappear on teardown. Parallel agent pools writing one progress file or one branch produce conflicts and races. Teams already running OTel pipelines, structured logging, or cost dashboards gain no extra insight from copying trajectory data into flat files.

Key Takeaways

  • A progress file read at session start and written at session end eliminates cold-start context loss.
  • Git commit messages are a zero-cost audit trail when agents commit after each completed task.
  • Feature-state JSON provides a machine-readable snapshot independent of LLM memory.
  • LoopDetectionMiddleware and PreCompletionChecklistMiddleware extend passive logging into active trajectory monitoring.