Skip to main content

agentpace

Stop estimating agent work in human weeks. agentpace measures how long coding agents actually take: a P50/P80/P90 range from real runs, with the human part stated apart, never derived.

A speech bubble, dashed and fading, holds a wall calendar shedding blank pages. Beside it a solid stopwatch, its hand a terminal cursor, is measured by two small cursor robots with a tape measure.

CI Python 3.10+ Code: MIT Data: CC0-1.0

Try it

With uv, this needs no install, no clone and no history of your own:

uvx agentpace estimate --example
<!-- claim:example_output -->
Plan total on the session clock: P50 2.4 h, P80 5.9 h, P90 9.0 h
The session clock counts agent runs and the gaps between them, each gap up to the idle cap (900 s by default), so waiting on you between runs sits inside the total up to that cap.
Human part (review, testing, decisions, waiting between agent turns): not measured. No allowance for it is added to the total above. State it separately; do not derive it from the agent time.

task          P50        P80        P90  critical  cell (n)
schema     30 min     85 min      2.5 h     100%  feature x normal x claude-opus-5-5 (n=205)
api        30 min     87 min      2.5 h      53%  feature x normal x claude-opus-5-5 (n=205)
ui         30 min     86 min      2.6 h      47%  feature x normal x claude-opus-5-5 (n=205)
docs         72 s      6 min     13 min      18%  docs x normal x claude-opus-5-5 (n=0)
review      3 min      8 min     13 min      82%  review x low x claude-opus-5-5 (n=1255)

Critical path: schema -> ui -> review (longest in 47% of simulations)
Effective parallelism at cap 3: 0.90 (from 29 sessions). Throughput set the total in 76% of simulations.
Method: shrunk. 3383 runs, 47 not completed so excluded. 20000 simulations, seed 20261107.
Not completed, by harness: claude-code 13 of 3219 (0.4%; 3 failed, 10 unknown), codex 34 of 211 (16.1%; 33 failed, 1 unknown). These are recorded harness outcomes, not task acceptance, and they are left out of the fit.

Warnings:
  - cell docs x normal x claude-opus-5-5: n=0. No recorded run has kind docs at risk normal with model claude-opus-5-5. Mean from docs x normal (n=21); residuals pooled from all; interval widened by the spread between models. Recorded models under docs x normal: claude-sonnet-5-5 (21).
<!-- /claim -->

The plan it estimated is examples/plan.json, where each task is one agent run:

{
  "agent_cap": 3,
  "model": "claude-opus-5-5",
  "tasks": [
    { "id": "schema", "kind": "feature", "risk": "normal" },
    { "id": "api", "kind": "feature", "risk": "normal", "depends_on": ["schema"] },
    { "id": "ui", "kind": "feature", "risk": "normal", "depends_on": ["schema"] },
    { "id": "docs", "kind": "docs", "risk": "normal", "depends_on": ["api"] },
    { "id": "review", "kind": "review", "risk": "low", "depends_on": ["api", "ui"] }
  ]
}

To estimate your own, write a plan like it and run agentpace estimate plan.json, or pass - to read it from stdin. In a plan, depends_on and model are optional, and risk can be left out: it defaults to the risk the rows record for the task's kind, because in the data risk is the agent's role, not a rating of the work. Effective parallelism is work divided by elapsed time. It can be below 1, because a session's clock includes the time between runs.

Why a range and not one number? Agent run times have a long tail, so any single number misses most of the time. P50 is a coin flip, and P80 is the one to plan on.

In your agent

npx skills add mohamedzhioua/agentpace

Then ask your agent: "How long will the billing feature take?" The skill calls the CLI, so install it first (Install). Without it, the skill offers the install command or a portable rule-of-thumb prompt.

Why agentpace

Ask an assistant how long a feature will take and it answers in human-team time, "a few weeks", even when agents will do the work. agentpace answers from measured agent runs instead. Give it a plan of agent tasks and it returns P50/P80/P90 ranges measured from real agent runs and a critical path. It states the human part (review, testing, decisions, waiting) on its own line, and it publishes how often it is wrong. It is a standard-library Python CLI, an agent skill, and an open CC0 dataset.

How long agent runs took, by task kind

These are 3,383 completed agent runs: Claude Code subagent runs and Codex turns. Half finished within 2 min, and one in ten took more than 20 min. All of them come from one person so far, so read Limitations before trusting any of this.

Does it fit your setup?

You want to Works with today
Estimate a plan Anywhere. The seed data ships inside the package, so no history of your own is needed
Log your own runs Claude Code, subagent runs only: work Claude Code hands to a subagent, not the main conversation. Your rows pool with the seed, and --data ~/.agentpace/runs.jsonl uses only yours
Log your own Codex runs Codex, one agent turn per run: agentpace ingest --source codex reads ~/.codex/sessions. The published rows include Codex turns, and the backtest scores Codex on its own
Log your own Gemini CLI runs Experimental: agentpace ingest --source gemini-cli reads ~/.gemini/tmp, one agent turn per run. The adapter is built from the Gemini CLI source, not yet verified on real sessions, and no published rows come from it (validate rejects them until the adapter is verified; how to verify it). Report problems in an issue
Log your own OpenCode runs Experimental: agentpace ingest --source opencode reads ~/.local/share/opencode/opencode.db. The adapter is built from the OpenCode source, not yet verified on real sessions, and no published rows come from it (validate rejects them until the adapter is verified; how to verify it). Report problems in an issue
Log your own Cline runs Experimental: agentpace ingest --source cline reads Cline's task folders in VS Code's global storage, one agent turn per run. The adapter is built from the Cline source, not yet verified on real sessions, and no published rows come from it (validate rejects them until the adapter is verified; how to verify it). Report problems in an issue
Another harness Not yet. The adapter interface takes one module per harness

Install

uv tool install agentpace

pipx install agentpace works too. It needs Python 3.10 or later and has no dependencies. After installing, drop uvx from the command above.

Then add the agent skills:

npx skills add mohamedzhioua/agentpace

Without Node, copy the four folders under skills/ into your agent's skills folder, for example ~/.claude/skills/ for Claude Code. No skill-capable agent? Paste the portable prompt into any assistant.

Skills

Skill Say this You get
agentpace "How long will the billing feature take?", or "my manager says this is a 3-month project" The work split into agent tasks, a measured P50/P80/P90 range with its critical path, the human part on its own line, and any quoted timeline shown beside it as unverified
/pace-estimate /pace-estimate plan.json, or a task list The same estimate for a plan you hand it
/pace-log /pace-log, "log my agent runs", "that run was a bug fix" Your runs ingested into ~/.agentpace, labels corrected, and the opt-in hook that logs each run as it finishes
/pace-share /pace-share, only when you ask The exact rows you could contribute, previewed first. It writes a file only after you say yes, and sends nothing

agentpace triggers by itself on questions about how long software work will take. The three /pace-* skills run when you call them. The portable prompt gives a rule-of-thumb version of the same answer in assistants without skills.

Re-answer a quoted timeline

Suppose someone has called a customer-import feature "a 3-month project". The skill splits it into agent tasks, as in examples/quote-plan.json, and passes the quote on exactly as it was given:

agentpace estimate examples/quote-plan.json --quoted "3 months"
<!-- claim:quote_example_output -->
Plan total on the session clock: P50 4.3 h, P80 10.3 h, P90 15.7 h
Quoted: "3 months" (calendar time, as quoted; unverified, not converted)
The session clock counts agent runs and the gaps between them, each gap up to the idle cap (900 s by default), so waiting on you between runs sits inside the total up to that cap.
Human part (review, testing, decisions, waiting between agent turns): not measured. No allowance for it is added to the total above. State it separately; do not derive it from the agent time.

task               P50        P80        P90  critical  cell (n)
schema          30 min     85 min      2.5 h     100%  feature x normal x claude-opus-5-5 (n=205)
importer        30 min     86 min      2.6 h      40%  feature x normal x claude-opus-5-5 (n=205)
api             30 min     87 min      2.5 h      60%  feature x normal x claude-opus-5-5 (n=205)
settings-ui     31 min     86 min      2.5 h      32%  feature x normal x claude-opus-5-5 (n=205)
tests           38 min      2.1 h      3.8 h      68%  tests x normal x claude-opus-5-5 (n=2)
review           3 min      8 min     13 min     100%  review x low x claude-opus-5-5 (n=1255)

Critical path: schema -> importer -> tests -> review (longest in 40% of simulations)
Effective parallelism at cap 3: 0.90 (from 29 sessions). Throughput set the total in 78% of simulations.
Method: shrunk. 3383 runs, 47 not completed so excluded. 20000 simulations, seed 20261107.
Not completed, by harness: claude-code 13 of 3219 (0.4%; 3 failed, 10 unknown), codex 34 of 211 (16.1%; 33 failed, 1 unknown). These are recorded harness outcomes, not task acceptance, and they are left out of the fit.

Warnings:
  - cell tests x normal x claude-opus-5-5: n=2, effective n=2.0, below 30. Mean shrunk toward broader cells; residuals pooled from all; interval widened.
<!-- /claim -->

The quote is calendar time, as quoted, and nothing has checked it. The range is built from measured agent time on the session clock, which counts the gaps between runs up to the idle cap. The human part is stated apart, on its own line, and no allowance for it is added to either. The quote is shown beside the range, never converted into agent time or set against it.

Commands

Use What it does
agentpace estimate <plan> P50, P80 and P90 for a plan, and the human part on its own line
agentpace estimate <plan> --review-capacity "4 PRs a day" The same, with your stated review capacity shown on its own line as yours: not measured, not applied to the range
agentpace estimate <plan> --data ~/.agentpace/runs.jsonl The same, from your own ingested runs only
agentpace estimate <plan> --record --quoted "3 weeks" Keep the forecast on your machine to score later, with any timeline someone already quoted
agentpace ingest [path] Read local agent history into rows
agentpace runs List recent runs and their references
agentpace label <ref> Correct the kind or risk of a run
agentpace share Preview exact rows, or write a file to contribute
agentpace score [id] Score a recorded forecast against a session that started after it, or see how your forecasts held up
agentpace turns Measure how long you wait between agent turns, from your own main sessions. Kept local, never shared
Maintain What it does
agentpace backtest Regenerate the published evaluation
agentpace validate Check data files: the bundled seed by default; contributors pass data/runs
agentpace site Refresh the data inside the static page
agentpace claims Check every number in this README against the data

agentpace ingest reads Claude Code subagent transcripts from ~/.claude/projects and keeps rows in ~/.agentpace, on your machine. A second run reads only what changed. To log every run as it finishes, add the opt-in hook that /pace-log shows.

There is also a leaderboard of median, P75 and P90 by model, kind and risk.

Backtest: how often it is wrong

Bottom line. On 56 held-out sessions, the whole-session P80 covered 80% (CI 70% to 91%) and the P90 covered 91% (CI 84% to 98%). For a single task, the P80 covered 77.7% (CI 71.4% to 83.8%), but the median miss of its P50 is 78%, so plan on the range, never the middle. Calibration drifts from week to week: per-session P80 coverage ran from 66% to 86%.

Every number here comes from the published rows. agentpace backtest regenerates them, and CI fails if they drift. The headline scores Claude Code sessions, the population the method was chosen on. Codex is scored on its own. The full report has every split, every baseline and every loss.

Forecasts use only what is known before a run: model, kind and risk. Whole sessions are held out, so no run can leak into its own forecast. These headline numbers come from the same time folds that chose the method, so treat them as slightly optimistic. Weeks after 2026-W45 form a locked holdout that never takes part in selection. Its status: not enough data (no weeks after 2026-W45 yet). Every interval below is a 95% bootstrap interval that resamples whole sessions.

Every number, with intervals and baselines

Whole sessions. Each of 56 later sessions with at least 5 completed runs was predicted from earlier weeks only. This is the only direct test of plan totals.

Forecast Target Got
Session finished within P50 50% 59% (CI 45% to 71%)
Session finished within P80 80% 80% (CI 70% to 91%)
Session finished within P90 90% 91% (CI 84% to 98%)

P80 and P90 coverage land near target, but with this few sessions the intervals are wide, and so are the ranges: P90 is typically 2.7x P50, and the median error of the P50 is 67%. The test also uses information a real forecast would not have, namely the session's actual task list and peak concurrency, and real dependencies are not recorded. So it tests the throughput model, not dependency planning. Pinball loss on whole sessions is 19720 (CI 13260 to 28000) seconds, against 37990 for a sum of medians.

Single tasks. On the time split, with each session counting equally:

Method P80 coverage (target 80%) Pinball loss (lower is better) Its pinball minus agentpace's
agentpace (<!-- claim:winner -->shrunk<!-- /claim -->) 77.7% (CI 71.4% to 83.8%) 1047 (CI 831 to 1316) n/a
Fixed 3 minutes per round n/a 1308 +75 to +467
Global median n/a 1719 +373 to +991
Naive human-time guess n/a 7569 +5725 to +7439

The human-time guess is a hand-written table, an assumption rather than a measurement. A difference interval wholly above zero means that baseline is worse at the 95% level.

Calibration is not stable from week to week. That P80 coverage pools 4 test weeks, and the pooled figure hides misses in both directions. Week by week it ran from 66% to 86% with each session counting equally, and from 60% to 94% with each run counting equally. In the latest week, 2026-W45, it was 66% per session and 60% per run, from only 8 sessions. Read the pooled P80 as an average over weeks, not a promise for any one week. The week-by-week table has every fold.

P80 coverage by method

Where it falls short.

  • The median error on a single task is 78%. Use the range, not the middle.
  • Pooled, P80 coverage is 88.8% when each run counts equally rather than each session, so the ranges are too wide for the small, fast runs that dominate the row count.
  • A global median beats agentpace on MAPE (234% against 494%), and a sum of medians beats it on plan MAPE (85% against 249%), though that sum covers only 5% of sessions at P80. MAPE punishes the long tail of over-forecasts that honest ranges need.
  • The report lists 20 places where a baseline won. That list is generated, so it cannot be edited out.
  • On the project split, which runs over both harnesses and where the largest project, a codex one, holds 137 of 212 held-out sessions, P80 coverage is 88.9%. The contributor split could not run (1 contributor).
  • The session-weighted design this project started with did not beat the simpler unweighted one, so the simpler one shipped. The selection rule was fixed before the first result. Scoring it on Claude Code sessions only was decided after a run with Codex rows pooled in had been seen, and that pooled result is printed in the report.

Privacy

agentpace never stores prompts, code or commit messages, and the rows you publish hold no content, file paths or repo names. Paths live in one local place, the ingest cache in ~/.agentpace/, which is never shared. It holds two kinds: the path of each transcript, so the next ingest re-reads only what changed, and the project folder (for Codex, the working folder), which reaches a row only as a keyed hash.

  • What gets read. From each transcript: timestamps, model ids, token counts, tool names, error flags and two metadata keys, plus the project folder as a hash input. JSON is decoded one line at a time, so other text passes through memory, but only those values are copied out. A test plants marker strings in every sensitive field and proves none reach any output.
  • What a row holds. Only the fields in schema/run.schema.json. Every string is an enum or a strict pattern, so free text has nowhere to land.
  • Who you are. Keyed hashes under a random secret that never leaves your machine. No email, handle or hostname goes in, so nobody can reverse them by guessing names.
  • Nothing is sent. There is no network code in this package at all, and a test fails if any is added. Contributing is a git push you run yourself. The site loads nothing from anywhere else.

Rows are not anonymous in every sense. They link to each other, they show roughly when you worked, and a pull request ties them to your GitHub account. agentpace share says so before it writes anything.

Contribute your runs

Sharing is opt-in, and your rows join a public-domain dataset.

git clone https://github.com/<your-fork>/agentpace && cd agentpace
uv tool install .           # or pipx install .
agentpace ingest
agentpace share --dry-run    # prints the exact rows and writes nothing
agentpace share --write      # adds or extends one file under data/runs, and still sends nothing
agentpace validate data/runs # the same checks CI runs

Then open a pull request with that one file. A data pull request dedicates your rows to the public domain under CC0-1.0. See CONTRIBUTING.md.

The most useful thing you can do is contribute: the contributor split cannot run until a second person does.

How it compares

Audited at the commits listed in docs/DESIGN.md.

agentpace agent-estimate claude-eta agent-estimation web-dev-estimation mythical-agent-month
Base Observed run durations PERT tiers in minutes Per-turn seconds Tool-call rounds Human time with multipliers Size tables with PERT
Numbers come from Published rows Hand-set, with a small private sample Your own hook data Hand-set Hand-set One 398-run build, unpublished
Output P50, P80, P90 O/M/P and sigma P50, P80 Low to high Mandatory range Likely, range, plan
Runs in repo Yes No No No No No, a shape file only
Multi-agent Graph simulation, learned throughput Graph, wave planning No Waves No Critical path, default 1.8
Published check Time and project holdouts, regenerated by CI Coverage audit, needs OACP files Walk-forward: n=285, P80 76.8%, MdAPE 79% None Prompt evals One holdout: -24% and -37%
Runtime deps None typer, pydantic, networkx, others None None None None

Each of these does something better than agentpace:

  • agent-estimate binds forecasts to receipts, so one issued after work started cannot score. It also forecasts token cost, and ships as a pip package and a GitHub Action.
  • claude-eta gives live per-turn ETAs inside a session, evaluates itself walk-forward on your own history, and has consent-gated community sharing and a repair-loop detector.
  • agent-estimation is the simplest and most teachable model here, and it needs no data at all.
  • web-dev-estimation has the best skill structure, with batch and re-estimate modes that work from documents before any history exists.
  • mythical-agent-month separates machine, human and waiting time, tracks usage budgets, and openly publishes its own held-out miss.

Limitations

  • One person's workflow. Every run comes from 1 contributor, across 21 projects and 293 sessions, from 2026-W40 to 2026-W45. One project holds 67% of runs, and three sessions hold 45%. It includes heavy automated fan-out, so it may not resemble your setup.
  • Not a model speed ranking. People send harder work to stronger models, so a slower row may just mean harder tasks.
  • feature means any implementation work. Without reading prompts, metadata cannot separate features, bug fixes and refactors. Those kinds stay thin until people label runs.
  • Retries are not separated. A run's duration includes any test-fix loop inside it. retries counts errored tool results, a proxy, because a real retry cannot be seen without reading content, and no field that describes what happened in a run (retries, tool_calls, tokens, outcome) ever predicts a duration. Codex upkeep sessions (compact) are skipped; nothing else is split out.
  • Pooled by kind, risk and model only. A cell with fewer than 30 runs leans on broader cells, with a warning. Repository size is not recorded, and size is an edit count measured after the run, so neither can segment the published runs. Long integration work has no cell of its own. risk in the rows is the agent's role (review and research agents low, migration agents high, all else normal), and a plan's risk is read the same way, so marking a task high does not lengthen its range.
  • Two harnesses, still one person. The published rows hold Claude Code subagent runs and, since 0.6.0, Codex turns, all from the same contributor. Codex is scored on its own, never in the headline. Each Codex exec session is a single turn, so the session effect and the parallelism factor learn nothing from Codex, and a Codex plan borrows Claude Code's session structure. Gemini CLI, OpenCode and Cline have experimental adapters: built from each tool's source, not yet verified on real sessions, with no published rows (validate rejects them until each adapter is verified; how to verify one), and problems go in an issue. Other harnesses have no adapter.
  • No human allowance, and short waits sit inside the clock. The plan total is a forecast on the session clock, which counts agent runs and the gaps between them, each gap up to the idle cap (900 s in the published rows). So a wait on you shorter than that sits inside the total, a longer one is clipped at the cap, and no allowance for review, testing or decisions is added. Every estimate says so on its own lines and never derives the human part from agent time. agentpace turns measures your own wait per human turn from your main-session timestamps and keeps it on your machine. That is elapsed time, not effort, shown beside the range and never added to it.
  • Failed runs are under-counted. Only runs with a clear completion signal train the estimator, so P90 may run low. Recorded runs that did not complete (failed or unknown), by harness: claude-code 13 of 3,219 (0.4%), codex 34 of 211 (16.1%). Those are harness outcomes, not task acceptance, and every estimate prints the counts for the rows it loaded.
  • Size is not used by default. Stored size is measured after a run, so it would leak the answer into the forecast.
  • The transcript format is undocumented. It may change, and Claude Code removes old transcripts, so run agentpace ingest regularly.
  • Dependencies are untested. The whole-session test cannot see real dependencies.

Development

PYTHONPATH=src python -m unittest discover -s tests -t .

The tests need nothing installed. All the math is in src/agentpace/estimate.py. The reasoning behind the design is in docs/DESIGN.md.

License

Code: MIT. Data: CC0-1.0.

Metadata

Release files for agentpace 0.12.5

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for agentpace 0.12.5
File Size Uploaded Provenance Actions
agentpace-0.12.5.tar.gz 855.2 kB Without provenance Details for agentpace-0.12.5.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for agentpace 0.12.5
File Interpreter ABI Platform Actions
agentpace-0.12.5-py3-none-any.whl Python 3 none any Details for agentpace-0.12.5-py3-none-any.whl

Total release size: 1.0 MB

Release files / agentpace-0.12.5.tar.gz

Download URL agentpace-0.12.5.tar.gz
Size 855.2 kB
Tags Source
SHA-256 checksum
How to use checksums
233b663586eff61730fd131c22881ca1929c308eadfd6fe7c0552f714e2d30ec
BLAKE2b-256 checksum
How to use checksums
e412e4ef243da10d6cf22a1b6fedeb7b3fd1a978fd82b4bdf1608df6fc3dfba4
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.13.7 {"installer":{"name":"uv","version":"0.13.7","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"26.04","id":"resolute","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / agentpace-0.12.5-py3-none-any.whl

Download URL agentpace-0.12.5-py3-none-any.whl
Size 172.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
df7412f86d86515de7b0a21465709183c4543736e89687bc49f245268b1033bf
BLAKE2b-256 checksum
How to use checksums
822cc59f7d78986de8e55990636932a384b20314757fd4226c37c181378cdcc7
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.13.7 {"installer":{"name":"uv","version":"0.13.7","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"26.04","id":"resolute","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Security for agentpace 0.12.5

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page