Local Gradient

Open Knowledge Format · v0.2

YAML frontmatter
type: Skill
title: "Agent Effort Estimation"
description: "Forecasts agent wall-clock (primary), human-hours-equivalent, and a confidence cone for work NOT yet started, using measured rates by work type from the local ledger of completed items. Use only when invoked by name or when the user explicitly asks to apply calibrated/measured rates or convert an existing estimate to agent time. Do not auto-select for generic \"how long will this take\" questions — answer those conventionally first so the input stays unanchored. For work already shipped, use look-back-effort-accounting."
resource: "https://localgradient.dev/okf/resources/agent-effort-estimation/index.md"
tags: ["coding-agents", "skill", "estimation"]
status: stable
generated: { by: human:local-gradient, at: "2026-07-25T16:00:00-04:00" }
okf_version: "0.2"
save_as: "agent-effort-estimation/SKILL.md"

Agent Effort Estimation (Forward)

Forecast how long upcoming work will take before it starts. The headline

output is agent wall-clock — what you actually schedule against — because

agent dev time is far faster than human-only dev time. Human-hours-equivalent and

a confidence band come alongside.

Invocation. Invoke this explicitly, after a conventional estimate or work

breakdown already exists. Reading the rates puts the multiplier in context, so

a first-pass estimate produced under this skill is anchored to it — produce

that estimate first, then convert.

Direction matters. This skill looks FORWARD at work not yet started. To

account for work already shipped, use `look-back-effort-accounting`. That

skill writes the ledger this one reads. Forecast quality rises every time the

ledger grows — estimation is only as good as the actuals behind it.

What these numbers are, and are not

Read this before quoting a forecast to anyone:

  • Human-hours-equivalent is a size proxy, not a duration. It is computed as

counted lines ÷ fixed tier rates, so it says "a solo human writing this volume

at these rates would take N hours" — nothing about value, quality, or what a

team would actually take. Per 100 lines it lands near-constant (~3.0–3.8 h)

across every work type, which is the tier mixture showing through rather than a

discovered difference between kinds of work.

  • The multiplier is one global constant, not a per-type measurement.

attach_agent() shares a single attended-hours total across items in

proportion to their human-hours, so human/agent is identical for every row by

construction. derived_agent_h is exactly

median_human_h / overall_multiplier. No per-type speed signal exists until

agent wall-clock is attributed per item.

  • The attended denominator may be assumed. Absent ATTENDED_WALLTIME_H, it

is distinct active days × 6 h nominal. Check

run_manifest.json → denominators.attended_walltime_source; when it reads

assumed, say so rather than presenting the multiplier as measured.

  • Rates are conditional on line attribution. Medians come from countable rows

only (net_lines > 0); coverage reports that fraction. Judge thin basis on

n_countable, not n — a type can show n=115 on a median resting on 51 rows.

  • Work-type size differences are contaminated by day-buckets. kind: direct

rows lump a day of mixed commits under one type, so a type dominated by them

looks larger without being harder. Compare kind: pr rows when the distinction

matters.

Current calibration snapshot (real, anonymized)

One personal workflow's rates — published so the method is reproducible and

criticizable, not so the numbers can be copied without local recalibration.

Window: 2026-06-17..2026-07-14 · Rates version: v2.1-countable-medians · Built:

2026-07-26 · Overall human-equivalent → attended-agent multiplier: 43.8× (denominator source: assumed)

Work typencountablecoverageMedian human-eq hp25–p75Median net linesDerived agent h
bug65480.7423.7310.69–142.03729.50.542
chore1380.6221.83.58–59.7586.00.498
docs420.52.871.91–3.83100.50.066
feature115510.446.141.26–17.121840.14
infra1880.444.854.13–14.85163.00.111
orchestration26120.469.455.85–36.07276.50.216
research221.095.3835.14–155.612522.52.178

Read `coverage` before trusting a row. Medians come from countable rows only

(items whose commits produced counted lines). Where coverage is low, the rate

describes the countable subset, not the work type as a whole.

How it works

  1. Describe the work as items. For each intended unit, give:

- work_type ∈ {feature, bug, chore, docs, research, orchestration, infra}

- a rough size: expected net lines OR a complexity tier (T1–T5), plus the

files/areas it touches.

  1. Read our measured rates from the calibration built off the ledger (the

pipeline's versioned home is <your-repo>/measure/devmetrics/):

```

<your-repo>/measure/devmetrics/rates.json # rates by work_type (committed seed)

<your-repo>/measure/devmetrics/work_items.jsonl # raw ledger (recompute if stale)

```

Each work_type carries: derived_agent_h (median human-hours ÷ the global

multiplier — a transform, not an observed agent median; see the caveat above),

median human-hours, n_countable/coverage, and a p25–p75 spread.

  1. Project each item, then sum:

- agent_h ≈ size × (derived_agent_h per unit for that work_type)

- report a cone from the p25–p75 spread (early estimates are wider —

McConnell's cone of uncertainty).

  1. Cite the basis. Every estimate states n and the rate it used, e.g.

"feature, n=12 prior items, median 0.9h agent / 38x → 1.1h agent (0.6–1.8h cone)."

Output format

## Estimate: [work description]

| Item | Type | Size | Agent h | Cone (p25–p75) | Human-equiv h |
|------|------|-----:|--------:|---------------:|--------------:|
| ...  | feature | 400 ln | 1.1 | 0.6–1.8 | 18 |
| **Total** | | | **X.X agent h** | **lo–hi** | **NN human h** |

Basis: rates.json built YYYY-MM-DD from N ledger items.
Multiplier (this mix): NN× vs human-only.

When the ledger is thin

If a work_type has few COUNTABLE prior items (n_countable < 5 — judge on that,

not the full n; a type can show n=115 on a median resting on 51 rows), say so

and fall back to the

look-back-effort-accounting COCOMO tier rates for that type, flagged as

low-confidence. Never present a forecast as precise when the basis is thin —

widen the cone and name the n.

Closing the loop

After the work ships, run look-back-effort-accounting on it. Comparing the

forecast here to the actual there is the estimate-accuracy signal — track it

over time and the rates self-correct. (Estimate accuracy is a local signal, not

one of the four DORA metrics; the pipeline computes those separately into

dora_summary.json.)

Rebuilding rates

The calibration is produced by the dev-metrics pipeline:

python3 <your-repo>/measure/devmetrics/pipeline.py rates   # rebuild rates.json from the ledger

See <your-repo>/measure/devmetrics/SCHEMA.md for ledger + rates schema.

Files in this bundle

  • SKILL.md — the verbatim agent-facing skill. Save it as agent-effort-estimation/SKILL.md wherever your agent loads skills.