An agent-native estimation layer for Claude Code. Estimates coding tasks in the unit agents actually work in — tool-call rounds (discovery, implementation, verification, rework) — then converts to a low/expected/high wall-clock range using local calibration history that self-corrects as outcomes are logged.
Why: coding agents inherit human developer heuristics from training data, so a 30-minute agent task gets called "2–3 days". This skill never starts from human hours.
skills/agent-time-estimator/
SKILL.md # the Claude Code skill (3 modes: estimate / re-estimate / calibrate)
estimator.py # stdlib-only engine — all the math, transparent constants up top
references/model.md # full model: priors tables, risk math, calibration cascade
hooks/ # optional PostToolUse/Stop hooks (auto round-counting)
examples/
sample-history.jsonl # seed calibration data (7 realistic outcomes)
example-session.md # pre → during → post walkthrough
.claude/settings.json # live hook wiring (+ .example to port elsewhere)
.claude/skills/agent-time-estimator # symlink so the skill is live in this repo
tests/test_estimator.py # stdlib unittest suite
Calibration history lives at <repo>/.claude/agent-time/history.jsonl (JSONL, one
record per line, human-editable). Override with --data or $AGENT_TIME_DATA. A
user-level ~/.claude/agent-time/history.jsonl is auto-blended when the project's own
history is sparse (see cross-repo calibration below).
Three layers make estimates sharper than a static prior:
- Automatic actuals (hooks). An optional
PostToolUsehook counts rounds and records edited files + commands per session, solog/reestimatefill in actuals with no self-report. Wired live here via.claude/settings.json; copy.exampleto port it. Seehooks/README.md. - Per-model reliability (METR-style). Each model has a single-run horizon
(opus-4.8 = 90 min, sonnet-4.6 = 30 min, …). When expected wall-clock exceeds its
model's horizon, the estimate recommends a checkpoint/split. A pace factor also adjusts
minutes-per-round once enough per-model data exists. Pass
--model. - Cross-repo calibration. User-level history blends into sparse local buckets
(local weighs 3× user), so a fresh repo is useful on day one. Disable with
--no-user-history.
roadmap — a tool for scoping and orchestrating AI coding sessions across a repo — consumes these estimates at the macro scale. It tags each planned slice with a shape (+ risks), calls estimate --json per slice, and rolls the durations up its dependency/concurrency schedule into projected per-project target dates on a Linear timeline (roadmap estimate / roadmap estimate timeline), feeding actuals back to log as slices complete.
This skill stays standalone and unaware of it — roadmap is just another caller of the CLI, so nothing here changes. The payoff of the pairing: the same calibrated numbers that size one task also plan the whole program, and every completed slice sharpens the next estimate. See roadmap's Estimation & timeline section.
Copy (or submodule) the skill directory and expose it to Claude Code:
cp -r skills/agent-time-estimator /path/to/repo/.claude/skills/
# or user-wide:
cp -r skills/agent-time-estimator ~/.claude/skills/
# optional: enable auto round-counting hooks
cp .claude/settings.json.example /path/to/repo/.claude/settings.jsonNo dependencies. Python 3.8+.
Claude runs a bounded discovery pass (≤10 tool calls), classifies the task shape, selects evidenced risk factors, then calls:
python3 skills/agent-time-estimator/estimator.py estimate \
--summary "add rate limiting to the webhook endpoint" \
--shape localized-feature \
--risks external-api,no-tests \
--findings "handler in src/hooks.py; no middleware; no tests for hooks" \
--assumptions "in-memory limiter acceptable"Output (abridged):
## Agent Time Estimate
Task shape: localized-feature
Round estimate (mode per category, before risk): Discovery 3, Implementation 5, Verification 3, Rework 2 ...
Risk factors: external-api (×1.25), no-tests (×1.20) → combined ×1.45
Calibration basis: calibrated (global median, n=7) · 2.82 min/round · sparse-data widening ×1.27
Agent rounds (low/expected/high): 10.2 / 18.9 / 30.9
Wall-clock estimate: Low: 19 min · Expected: 45 min · High: 93 min
Confidence: low-medium
Checkpoint: re-estimate after the first verification round if anything surprised you
The estimate is logged as pending with a task id; the wall clock starts there.
When a hidden dependency, failing suite, or environment issue appears (or rounds spent exceed ~1.5× expected):
python3 skills/agent-time-estimator/estimator.py reestimate \
--task-id t-20260708-a1b2 --rounds-spent 12 \
--reason "test suite fails on main; must fix fixtures first" \
--add-risks slow-flaky-tests \
--rounds-json '{"implementation": 3, "verification": 5, "rework": 4}'The engine blends the task's own observed pace (60% weight after 5+ rounds), shows the original vs. revised numbers, and appends a revision record — the original estimate is never rewritten.
python3 skills/agent-time-estimator/estimator.py log \
--task-id t-20260708-a1b2 --status pass \
--variance "fixtures were broken on main, cost ~5 extra rounds"With the hook enabled, actual rounds, files changed, and commands are auto-filled from
session activity — no --actual-rounds needed (pass it to override). Elapsed wall time is
computed from the estimate timestamp. Each logged outcome tightens future ranges: median
minutes-per-round by similar-task match → task-shape → global, plus a recency-weighted
bias correction. estimator.py stats shows calibration health, including a per-model
pace/horizon table.
| Logged outcomes | Behavior |
|---|---|
| 0 local, but user-level exists | blends in cross-repo history (labeled user-level/blended) |
| 0–4 (no user data) | UNCALIBRATED static prior (3 min/round), ranges widened ×~1.75 |
| 5+ | global median pace, bias correction kicks in, ranges narrow as 1 + 0.75/√(n+1) |
| 3+ of same shape | per-shape pace |
| 3+ similar tasks (keyword match) | similar-task pace — the strongest signal |
| 5+ per model | per-model pace factor + reliability-horizon checkpointing |
| 15+ predicted outcomes in bucket | fully empirical p20/p80 spread |
Full math: skills/agent-time-estimator/references/model.md.
Start from the sample data to see calibrated behavior immediately:
mkdir -p .claude/agent-time
cp skills/agent-time-estimator/examples/sample-history.jsonl .claude/agent-time/history.jsonlOr backfill real past tasks: estimator.py log without --task-id
(requires --summary --shape --actual-minutes --actual-rounds).
python3 -m unittest discover testsPractical over academic · local-first (no services, no network) · transparent math (every constant in one CONFIG block) · useful from day one, better with history · never a single precise ETA.