Kirtan Soni
← All writing

Meet Forge — context management for AI agent harnesses

A git-like CLI that gives AI agents a senior engineer's memory of your codebase — automatically, incrementally, and always in sync. Forge is part of anvil, a Claude-Code-like agentic harness written in Rust. built in rust

$ forge init && forge update

The problem: agents read code, they don't understand it

When an AI agent edits a file, it sees structure — function signatures, types, control flow. What it doesn't see is the reasoning behind it.Claude Code's CLAUDE.md does this at the project level. Forge does it per file — the difference matters once a project stops fitting in one note. Why does this file exist? What must never change? Where does new code belong?

Without that context, agents make plausible-but-wrong decisions. They duplicate logic that already exists elsewhere. They violate invariants that aren't written down. They refactor things that can't be refactored.

Without Forge

Agent reads parser.rs — 400 lines of syn AST traversal.

It doesn't know the 15-line collapse threshold is a deliberate policy decision.

It doesn't know non-Rust parsers should be sibling files, not added here.

It makes a plausible change. It breaks something subtle.

With Forge

Before touching the file, the agent reads its context note.

"COLLAPSE_THRESHOLD must remain a named constant — it's a tunable policy decision."

"Non-Rust parsers belong in sibling files, not here."

The agent acts with intent. The change is correct the first time.

Think of forge as the notes a senior engineer leaves on their first day handing off a file — not documentation, not a spec, but the things you'd only learn after breaking something in production.

Four commands. That's the whole workflow.

01
Initialize tracking

Forge walks your project respecting .gitignore, records the current git hash for every source file, and creates a .anvil/manifest.toml. No context is generated yet — just a baseline snapshot. Fast and free.

forge init
02
See what's stale

Compare stored hashes against current git state. Every file gets a clear status: up to date, stale (hash changed), or missing context. Like git status but for your agent's understanding of the codebase.

forge status
03
Generate or patch context

For new files: sends full source to Claude and generates a structured context note. For changed files: sends only the git diff and the existing note — Claude patches just the affected sections. Up to four files run concurrently. Prints a token and cost breakdown when done.

forge update
04
Wire up your agent

Installs a PreToolUse hook into Claude Code's settings.json. From that point on, every time Claude reads a file forge silently injects its context note as additionalContext — no prompt changes, no manual steps. The agent always understands why a file exists before it touches it.

forge for-agent claude
forge status
ok crates/anvil-core/src/tools/read_file.rs
ok crates/anvil-core/src/utils/parser.rs
stale crates/forge/src/commands/update.rs (e8f53f6 → cfbe244)
ok crates/forge/src/git.rs
stale crates/forge/src/store/manifest.rs (e8f53f6 → cfbe244)
 
28 up to date, 2 stale
forge update
updated crates/forge/src/commands/update.rs
updated crates/forge/src/store/manifest.rs
 
Usage 2 files claude-sonnet-4-6
input 12,450 $0.0374
output 8,230 $0.1235
─────────────────────────
total $0.1608

Context files: six sections, every file, injected automatically

Each context file lives in .anvil/ mirroring your source tree. The format is fixed so agents can query specific sections rather than parsing free-form prose.

📄 .anvil/crates/anvil-core/src/utils/parser.md
## purpose
## intent
## structure
## constraints
## add here
## do not add here
## purpose

Parses Rust source files using syn and converts the AST into a structured FileSpec summary that an AI agent can reason about without reading every line.


## constraints (example)

• Must not panic on any valid Rust source file — unrecognized items return None, never unwrap
COLLAPSE_THRESHOLD must remain a named constant, not an inline literal — it is a tunable policy decision
• Output must be deterministic for a given input — no random ordering, no timestamps

Every context file answers the same six questions. An agent reading parser.rs for the first time gets all of this before writing a single line.

Incremental updates: diffs in, patches out

Forge doesn't regenerate a context file from scratch every time a file changes. It sends Claude the diff alongside the existing note and asks it to patch only the affected sections. This keeps updates focused and API costs minimal.

first run full source Claude context.md
on change git diff+ context.md Claude patched

The hash stored in manifest.toml is the commit hash of the file at the last successful update — not HEAD. So if you update a file across three commits before running forge update, the diff covers all three at once.

The .anvil store: structured like your project, committed with your code

Context files live in .anvil/, mirroring the source tree one-to-one. The manifest tracks the hash for every file. Both are committed to git — context evolves alongside code, and diffs are meaningful.

.anvil/
  manifest.toml
  crates/
    anvil-core/src/
      tools/read_file.md
      utils/parser.md
      utils/formatter.md
      utils/query.md
    forge/src/
      commands/update.md
      commands/init.md
      git.md
      store/manifest.md
 
manifest.toml
↳ "crates/forge/src/git.rs" = "cfbe244..."
↳ "crates/anvil-core/src/utils/parser.rs" = "cfbe244..."

By the numbers: forged on itself

The first thing we ran forge on was anvil — the project that built it.$1.97 for thirty files of handoff notes. The per-run cost breakdown exists because surprise API bills are how side projects die. Here's what that looked like.

30
files tracked on init
6
sections per context file
0
stale after update
forging anvil
$ forge init
Initialized forge — tracking 30 files
 
$ forge update
updated crates/anvil-core/src/tools/read_file.rs
updated crates/anvil-core/src/utils/parser.rs
updated crates/forge/src/commands/update.rs
... 27 more
 
Usage 30 files claude-sonnet-4-6
input 187,320 $0.5620
output 94,150 $1.4123
─────────────────────────
total $1.9743
 
$ forge for-agent claude
forge → claude
hook .claude/hooks/forge-context.sh
settings .claude/settings.json
 
$ forge status
30 up to date, 0 stale

Design: built like git, reliable like a tool should be

Atomic writes

Context files are written to a temp path and renamed into place. A crash mid-write never leaves a corrupt file.

Partial failure

One file failing to update doesn't abort the rest. Errors are collected and reported at the end.

Gitignore-aware

Uses the same engine as ripgrep to walk your project. If git ignores it, forge ignores it. Any language, any file type.

Idempotent init

forge init fails immediately if .anvil/ already exists. No half-initialized state.

Bounded concurrency

Updates run four files at a time via a semaphore. Fast enough to not block you, conservative enough to not flood the API.

Transparent cost

Every forge update run prints a full token and cost breakdown — input, output, cache reads and writes — so you always know what you spent.

forge is part of anvil — a Claude Code-like agentic CLI harness written in Rust.
Built with: anthropic-sdk-rust · tokio · syn · ignore · clap

Tags: Rust, Agents, Claude, Tooling