# mythical-agent-month

Adopt this skill: https://proskills.md/skills/other/medadembha-mythical-agent-month-skills-mythical-agent-month

Page: https://proskills.md/skills/other/medadembha-mythical-agent-month-skills-mythical-agent-month
This document is the public skill bundle for that page. It contains SKILL.md and every helper file the catalog carries. No login is required.

## File: skills/mythical-agent-month/SKILL.md
size: 8569
sha: 13693facad2394a975b53c341d4a3edd1b2c8cbb
upstream: https://github.com/medadembha/mythical-agent-month/blob/main/skills/mythical-agent-month/SKILL.md

````text
---
name: mythical-agent-month
description: Realistic estimates for software built with AI coding agents or an AI assistant (Claude Code, Codex, Cursor, subagents, multi-agent workflows). Stops the "60-100 days" human-team guess by separating agent wall-clock, human effort, waiting on decisions and usage budget, seeded from measured agent runs. Use when the user asks how long work will take, wants a timeline or roadmap sizing, asks how long an agent build or workflow will run or how much usage it will cost, or wants an AI-made estimate checked, and the work will be done with AI agents or an AI assistant. Not for teams estimating work done without AI.
---

# Mythical Agent Month

Brooks showed that man-months are a myth: people and months don't trade. AI estimates have a newer problem. They are written at human-team pace, because the training data is human tickets and sprint plans, so an agent will say "about 4 months" for work that agents then finish in two days. The typing is now the fast part. The slow parts are tests, review, decisions and the usage limit.

So never give one big number. Separate:

- **Machine time**: how long agents run (wall-clock) and how many agent-hours they burn.
- **Human effort**: hours a person really works: prompting, reviewing, testing, setting up.
- **Waiting**: calendar time for decisions and usage-limit resets. Nobody is working then, and other tasks can move.

## Step 1: Pick the mode

Pick it from context. Ask only if it's unclear and the answer changes the result a lot.

**First check this skill applies.** If a human team will do the work without AI agents or assistants (classic sprint planning, story points for a team), human pace is the right pace: give a normal estimate, say this skill doesn't apply, and stop here.

- **Mode A, Developer + AI**: a person drives an assistant task by task (chat, pair-programming, one agent at a time). Output is in focus hours and days.
- **Mode B, Autonomous agent build**: a plan is split into tasks that agents build on their own, often in parallel (worktrees, lanes, a workflow script, an overnight run). Output is agent wall-clock, usage cost and the human calendar around it.

If the user asks for both ("how long with agents, and how long by hand?"), do B and show A or the no-AI pace as a comparison line.

## Step 2: Get the inputs

Take what the conversation gives and state assumptions for the rest. Ask at most two short questions.

If you can read the code, look before you estimate. For each task find the files and services it touches, whether a similar pattern exists, and whether tests exist nearby. A few minutes per task, not hours. An estimate grounded in real files beats one from the task title.

- **Mode A profile** [defaults]: builds with AI [yes], knows this codebase [familiar], focus hours per day [6], who decides product questions and how fast [1-3 working days each], review required [peer].
- **Mode B profile** [defaults]:
  - parallel agent cap [6, or CPUs - 2];
  - effective parallelism [1.8; real runs land at 25-35% of the cap because of test slots, file conflicts and merge locks];
  - agent hours per day [20; runs go overnight but stop for limits and breakages];
  - which tasks get a reviewer agent [high-risk];
  - phase checks [one per phase per repo];
  - usage [% of the weekly limit available, and % per agent-hour, default 0.6];
  - human review minutes per task [3];
  - local setup after the build [2-3 h].

## Step 3: Size, risk and dependencies per task

1. **Size** XS / S / M / L. **Split anything XL** before estimating; XL estimates are guesses.
2. **Risk**: low / normal / high. High = money, credits, quotas, auth and permissions, data deletion or export, migrations, multi-tenant isolation, anything hard to undo in production.
3. **Services touched**: the apps or services that must change together.
4. **Open decisions**: questions a human must answer. Write each as a concrete question with an owner.
5. **Mode B only:** the `depends_on` list, the model (big model for high-risk, small model for the rest), and the repo or files. Tasks that touch the same files can't run in parallel.

Tables and their reasoning are in `references/heuristics.md`. Real measured numbers are in `references/real-runs.md`.

## Step 4: Compute

If you can run Python, write the tasks as JSON and run `scripts/totals.py <file>`. The input format is at the top of the script, and `--json` gives totals only. It does the arithmetic and, in mode B, the critical path. Otherwise, compute by hand:

- **PERT** per part = (low + 4 × likely + high) / 6.
- **Mode A**:
  - effort days = (build + test + buffer) ÷ focus hours;
  - calendar = effort days, plus the longest decision wait (batched) or the sum of waits (one by one).
- **Mode B**:
  - agent-hours = Σ (task minutes + reviewer minutes + merge) × (1 + failure tax) + phase checks;
  - wall-clock = max(critical path + phase checks, agent-hours ÷ effective parallelism);
  - **plan** = likely × 1.3 until the user has calibrated (in run 1 the raw likely value was 12-37% low), or likely once calibrated. The plan number is the bold figure; likely and the range sit beside it;
  - calendar to ready-to-merge = plan wall-clock ÷ agent hours per day + human hours ÷ focus hours + decision waits + usage-reset waits;
  - usage = agent-hours × % per agent-hour. If it's above what's left this week, add the days until the reset.
- **No-AI pace** (comparison only, unmeasured): from each task's size and risk only, never from the AI-assisted hours: build × 2-3 + test × 1-1.5, + 10-20% coordination. It's the same baseline in both modes. Always give it as a range and label it unmeasured. Never put it in the bottom line, and never use it as the speedup headline.

## Step 5: Present it

Keep prose short; the tables carry the answer.

```markdown
## Estimate: <scope>

**Bottom line:** <Mode B: plan on about P h of agent wall-clock (likely W h, range L-H), ~U% of a weekly limit; ready to merge in C1-C3 calendar days depending on decisions. | Mode A: about X effort days; A-B calendar days depending on decisions.>

**Assumptions:** <profile in one or two lines>

| # | Task | Size | Risk | Model | <Agent min | Build h> | <Review | Test h> | Depends on | Decision needed |

| Part | Value |
|------|-------|
| Agent work / build | |
| Critical path (B) / Review & test (A) | |
| **Wall-clock (B) / Effort total (A)** | |
| Human hours (B) | |
| Usage (B) | |
| Waiting on decisions | calendar days, never added to effort |

**Calendar:** up front <a> · batched <b> · one by one <c> days

**Unblock first:** the decisions that block the most tasks, as questions with owners.

**Biggest risks:** up to three, one line each.

**Confidence:** low / medium / high, and the one thing that would most improve it.
```

If the user pasted an estimate to check, add one line comparing it. For example: "Original: 100 days. This: 35 h of agents + 3 calendar days; the gap is human-team pace, not the work."

## Step 6: Calibrate

The mode B defaults come from **one** run on someone else's machine and codebase. In a held-out test on that run (fit on its first phases, predict the rest), they came out **24% low on agent-hours and 37% low on wall-clock**. Until the user has their own numbers, present the upper half of the range as the plan and say why. Offer calibration at the end:

- **Mode A:** when a task is done, the user gives actual hours. Suggest a personal multiplier when actual hours are consistently off.
- **Mode B:** after a run, `scripts/calibrate.py <subagents dir> --tasks tasks.json` reads the transcripts' timestamps (read-only, no content). It prints real minutes per kind, risk and size, the effective parallelism and the retry rate. Put those into the estimate JSON or the tables.

The log format is in `references/calibration.md`.

## Things to avoid

- **One number with no breakdown.** It hides where the time goes.
- **Human-team pace for agent work.** "3 sprints" for a run that takes 2 nights is the bug this skill exists to fix.
- **Adding decision waits or usage resets into effort hours.**
- **Assuming parallelism = the agent cap.** Six agents give about two agents' throughput once tests, conflicts and merges queue.
- **Shrinking test or review time on high-risk work.** Real runs caught billing, permission and data-loss bugs exactly there.
- **Forgetting the human tail:** review per commit, local setup, seeding data, migrations someone must run.
- **False precision.** Round hours to 0.5 and days to one decimal; always give a range.
````

## File: skills/mythical-agent-month/scripts/calibrate.py
size: 6706
sha: 4472cc2a90610e2132fae0566f0abb1a008c7aaf
upstream: https://github.com/medadembha/mythical-agent-month/blob/main/skills/mythical-agent-month/scripts/calibrate.py

```text
#!/usr/bin/env python3
"""Calibrate Mythical Agent Month from your own agent runs. Read-only.

Reads subagent transcripts (agent-*.jsonl, with optional agent-*.meta.json next to them, the
layout Claude Code writes under ~/.claude/projects/<project>/<session>/subagents/) and prints:
  - real minutes per agent kind (code / review / merge / phase checks / other), by model
  - real minutes per risk class, if you pass your task list
  - wall-clock, busy time and the effective parallelism you actually got
  - suggested values for AGENT_MINUTES / RISK_MULT / effective_parallelism

Usage:
  python3 calibrate.py ~/.claude/projects/<project>/<session>/subagents
  python3 calibrate.py <logs dir> --tasks tasks.json     # tasks.json: {"items":[{"id","risk","size"}]}
  python3 calibrate.py <logs dir> --csv runs.csv          # also write one row per agent run

Only timestamps, labels, model names and token counts are read. No message content is printed.
"""
import csv
import glob
import json
import os
import re
import sys
from datetime import datetime

KINDS = [("review", r"^review"), ("merge", r"^merge"), ("phase_check", r"^(end|phase|final)"),
         ("cleanup", r"^(reset|fail|cleanup)")]

def ts(s):
    try:
        return datetime.fromisoformat(s.replace("Z", "+00:00"))
    except (ValueError, AttributeError):
        return None

def q(v):
    v = sorted(v)
    n = len(v)
    if not n:
        return "-"
    return f"n={n} p25={v[n // 4]:.1f} median={v[n // 2]:.1f} p75={v[(3 * n) // 4]:.1f} p90={v[int(n * 0.9)]:.1f} max={v[-1]:.1f}"

def main():
    args = [a for a in sys.argv[1:] if not a.startswith("--")]
    if not args:
        raise SystemExit(__doc__)
    root = os.path.expanduser(args[0])
    opt = {sys.argv[i]: sys.argv[i + 1] for i in range(1, len(sys.argv) - 1) if sys.argv[i].startswith("--")}
    tasks = {}
    if "--tasks" in opt:
        for it in json.load(open(opt["--tasks"]))["items"]:
            tasks[str(it["id"])] = it
    id_re = re.compile("|".join(sorted((re.escape(k) for k in tasks), key=len, reverse=True))) if tasks else None

    runs = []
    for jl in glob.glob(os.path.join(root, "**", "agent-*.jsonl"), recursive=True):
        meta_p = jl[:-len(".jsonl")] + ".meta.json"
        meta = json.load(open(meta_p)) if os.path.exists(meta_p) else {}
        label = meta.get("description", "") or os.path.basename(jl)
        stamps, out_tok = [], 0
        with open(jl, errors="replace") as f:
            for line in f:
                try:
                    o = json.loads(line)
                except ValueError:
                    continue
                t = ts(o.get("timestamp"))
                if t:
                    stamps.append(t)
                msg = o.get("message")
                if isinstance(msg, dict) and isinstance(msg.get("usage"), dict):
                    out_tok += msg["usage"].get("output_tokens") or 0
        if len(stamps) < 2:
            continue
        kind = "code" if (id_re and id_re.search(label)) else "other"
        for k, pat in KINDS:
            if re.search(pat, label):
                kind = k
        m = id_re.search(label) if id_re else None
        task = tasks.get(m.group(0), {}) if m else {}
        runs.append({"label": label, "kind": kind, "model": meta.get("model", "?"),
                     "start": min(stamps), "end": max(stamps),
                     "minutes": (max(stamps) - min(stamps)).total_seconds() / 60,
                     "out_tokens": out_tok, "risk": task.get("risk", ""), "size": task.get("size", ""),
                     "retry": bool(re.search(r"try ?[2-9]|retry", label))})
    if not runs:
        raise SystemExit(f"no agent-*.jsonl with timestamps under {root}")

    print(f"# Calibration from {len(runs)} agent runs\n")
    print("## Minutes per agent kind\n")
    for kind in sorted({r["kind"] for r in runs}):
        for model in sorted({r["model"] for r in runs if r["kind"] == kind}):
            v = [r["minutes"] for r in runs if r["kind"] == kind and r["model"] == model]
            print(f"- {kind} / {model}: {q(v)}")

    code = [r for r in runs if r["kind"] == "code" and r["minutes"] >= 1]
    if code and tasks:
        print("\n## Code minutes per risk (runs under 1 minute dropped: skips and no-ops)\n")
        med = {}
        for risk in ("low", "normal", "medium", "high"):
            v = sorted(r["minutes"] for r in code if r["risk"] == risk)
            if v:
                med[risk] = v[len(v) // 2]
                print(f"- {risk}: {q(v)}")
        base = med.get("normal") or med.get("medium")
        if base:
            print("\nSuggested RISK_MULT: " + ", ".join(f"{k}={v / base:.2f}" for k, v in med.items()))
        print("\n## Code minutes per size\n")
        for size in ("XS", "S", "M", "L", "XL"):
            v = [r["minutes"] for r in code if r["size"] == size]
            if v:
                print(f"- {size}: {q(v)}")
        n_tasks = len({r["label"].split()[0] for r in code})
        retries = sum(1 for r in code if r["retry"])
        if n_tasks:
            print(f"\nRetries: {retries} of {n_tasks} tasks ({retries / n_tasks:.0%}). "
                  "Failure tax is usually retries + fix-up agents; start at that share + 5%.")

    iv = sorted((r["start"], r["end"]) for r in runs)
    busy, (cs, ce) = 0.0, iv[0]
    for a, b in iv[1:]:
        if a > ce:
            busy += (ce - cs).total_seconds()
            cs, ce = a, b
        else:
            ce = max(ce, b)
    busy += (ce - cs).total_seconds()
    total = sum(r["minutes"] for r in runs) * 60
    span = (max(b for _, b in iv) - iv[0][0]).total_seconds()
    print("\n## Throughput\n")
    print(f"- agent-hours: {total / 3600:.1f}")
    print(f"- span: {span / 3600:.1f} h, busy: {busy / 3600:.1f} h")
    print(f"- effective_parallelism (agent-hours / busy hours): {total / busy:.2f}  <- put this in machine.effective_parallelism")
    tok = sorted(r["out_tokens"] for r in code if r["out_tokens"])
    if tok:
        print(f"- output tokens per code run: median {tok[len(tok) // 2]:,}, p75 {tok[(3 * len(tok)) // 4]:,}")
    print("\nWeekly usage: note your % of the weekly limit before and after the run;"
          " (after - before) / agent-hours = usage.weekly_pct_per_agent_hour.")

    if "--csv" in opt:
        with open(opt["--csv"], "w", newline="") as f:
            w = csv.DictWriter(f, fieldnames=["label", "kind", "model", "risk", "size", "minutes", "out_tokens", "retry"])
            w.writeheader()
            for r in runs:
                w.writerow({k: (round(r[k], 1) if k == "minutes" else r[k]) for k in w.fieldnames})
        print(f"\nwrote {opt['--csv']}")

if __name__ == "__main__":
    main()
```

## File: skills/mythical-agent-month/scripts/totals.py
size: 15406
sha: ffd5d022fe6a7df37083d245e188d56bd3947b0d
upstream: https://github.com/medadembha/mythical-agent-month/blob/main/skills/mythical-agent-month/scripts/totals.py

```text
#!/usr/bin/env python3
"""Mythical Agent Month: estimate totals. Prints Markdown.

Usage:
  python3 totals.py estimate.json            # mode is read from the file ("dev" or "agent")
  python3 totals.py estimate.json --json     # machine-readable totals

Mode "dev" (a developer working with an AI assistant):
{
  "mode": "dev",
  "focus_hours_per_day": 6,
  "items": [
    {"id": 1, "task": "Stripe credit packs", "size": "M", "risk": "high",
     "build": [3, 6, 10], "test": [8, 14, 24], "buffer_pct": 0.25, "decisions": ["d1"]}
  ],
  "decisions": [{"id": "d1", "question": "Which pack sizes?", "owner": "PM", "wait_days": [1, 3]}]
}
build and test are [low, likely, high] hours. buffer_pct is a fraction.

Mode "agent" (autonomous agents build the tasks; a human decides and reviews):
{
  "mode": "agent",
  "machine": {"parallel_agents": 6, "effective_parallelism": 1.8, "agent_hours_per_day": 20},
  "review": "high-risk",          # which tasks get a separate reviewer agent: "none" | "high-risk" | "all"
  "phase_checks": 9,              # full-suite checks between phases (count)
  "failure_tax": 0.20,            # retries, reruns, broken gates (0.15-0.25)
  "human": {"focus_hours_per_day": 6, "review_minutes_per_task": 3, "local_setup_hours": [2, 3]},
  "usage": {"weekly_pct_per_agent_hour": 0.6, "weekly_pct_available": 60},
  "items": [
    {"id": "t1", "task": "Plan catalog model", "size": "M", "risk": "high", "model": "opus",
     "depends_on": [], "minutes": [10, 25, 50], "decisions": ["d1"]}
  ],
  "decisions": [...same as dev mode...]
}
"minutes" per item is optional; without it the size x risk table below is used.
All defaults are seeded from one real run (see references/real-runs.md). Calibrate them with calibrate.py.
"""
import json
import sys

# Agent minutes per task, [low (p25), likely (median), high (p90)], normal risk, incl. the agent's own gate tests.
# Measured on run 1 (references/real-runs.md), not hand-tuned. Size by file count was a weak signal there;
# risk was the strong one.
AGENT_MINUTES = {"XS": [2, 4, 15], "S": [3, 5, 25], "M": [5, 10, 35], "L": [7, 12, 40]}
RISK_MULT = {"low": 0.3, "normal": 1.0, "high": 2.7}   # measured medians vs normal risk
REVIEW_MINUTES = [4, 8, 26]      # separate reviewer agent per reviewed task (median 8.4)
MERGE_MINUTES = 1                # merge agent / scripted merge per task (mean 1.2)
PHASE_CHECK_MINUTES = 12         # full suites + fix-ups between phases (mean 12.2)
# Held-out test on run 1 (fit on phases 0-3, predict 4-9): agent-hours -24%, wall-clock -37%.
# Until calibrated, the bold "Plan" number is likely x 1.3. On run 1 that lands at +14% in-sample and -19% held-out
# (versus -12% / -37% for the raw likely value). Set "calibrated": true, or give per-task minutes, to plan on likely.
PLAN_FACTOR = 1.3
HOLDOUT_NOTE = ("Held-out error on the reference run: agent-hours -24%, wall-clock -37% (later phases ran slower). "
                "Plan = likely x 1.3 until you calibrate.")

# Developer + AI hours, [low, likely, high] (build only; test is a multiple by risk)
DEV_BUILD_HOURS = {"XS": [0.25, 0.5, 1], "S": [1, 2, 4], "M": [3, 6, 10], "L": [8, 14, 24]}
DEV_TEST_MULT = {"low": 0.5, "normal": 1.0, "high": 2.5}
# No-AI comparison, an UNMEASURED baseline: build 2-3x slower without AI, review and test 1-1.5x, plus 10-20%
# coordination. Printed as a wide range and never as the estimate.
NO_AI_LOW = (2.0, 1.0, 1.1)
NO_AI_HIGH = (3.0, 1.5, 1.2)

def pert(r):
    low, likely, high = r
    return (low + 4 * likely + high) / 6

def r1(x):
    return round(x * 2) / 2

def decision_calendar(decisions):
    waits = [(d["wait_days"][0] + d["wait_days"][1]) / 2 for d in decisions.values()]
    return (max(waits) if waits else 0), sum(waits), waits

def unblock_first(items, decisions):
    blocks = {}
    for it in items:
        for d in it.get("decisions", []):
            blocks[d] = blocks.get(d, 0) + 1
    out = []
    for did, n in sorted(blocks.items(), key=lambda x: -x[1]):
        d = decisions.get(did)
        if d:
            out.append(f"- {d['question']} (owner: {d.get('owner', '?')}, blocks {n} task{'s' if n > 1 else ''})")
    return out

def human_team_days(items, team_size=1):
    """No-AI comparison range (low, high) in days, never the estimate. One baseline for both modes: it uses only
    each task's size and risk (never the input build/test hours, which are AI-assisted), so the same task list
    gives the same range in dev mode and agent mode. Unmeasured: show it as a range, keep it out of headlines."""
    out = []
    for bx, tx, cx in (NO_AI_LOW, NO_AI_HIGH):
        total = 0
        for it in items:
            size = it.get("size", "M")
            if size not in DEV_BUILD_HOURS:
                size = "L"
            b = pert(DEV_BUILD_HOURS[size])
            t = b * DEV_TEST_MULT.get(it.get("risk", "normal"), 1)
            total += (b * bx + t * tx) * cx
        out.append(total / 6 / team_size)
    return tuple(out)

# ---------------------------------------------------------------- dev mode
def mode_dev(data, as_json):
    fh = data.get("focus_hours_per_day", 6)
    items = data["items"]
    decisions = {d["id"]: d for d in data.get("decisions", [])}
    rows, tb, tt, tbuf = [], 0, 0, 0
    lo = hi = 0
    for it in items:
        size = it.get("size", "M")
        build = it.get("build", DEV_BUILD_HOURS.get(size, DEV_BUILD_HOURS["L"]))
        test = it.get("test", [x * DEV_TEST_MULT.get(it.get("risk", "normal"), 1) for x in build])
        b, t = pert(build), pert(test)
        buf = (b + t) * it.get("buffer_pct", 0.25)
        tb, tt, tbuf = tb + b, tt + t, tbuf + buf
        lo += build[0] + test[0]
        hi += build[2] + test[2]
        qs = "; ".join(decisions[d]["question"] for d in it.get("decisions", []) if d in decisions)
        rows.append(f"| {it['id']} | {it['task']} | {size} | {it.get('risk', '')} | {r1(b)} | {r1(t)} | {r1(buf)} | {qs or '-'} |")
    effort_h = tb + tt + tbuf
    effort_d = effort_h / fh
    batched_w, serial_w, _ = decision_calendar(decisions)
    human = human_team_days(items)
    res = {"effort_hours": round(effort_h, 1), "effort_days": round(effort_d, 1),
           "calendar_days": [round(effort_d, 1), round(effort_d + batched_w, 1), round(effort_d + serial_w, 1)],
           "solo_no_ai_days_range": [round(human[0]), round(human[1])]}
    if as_json:
        print(json.dumps(res, indent=1))
        return
    print("| # | Task | Size | Risk | Build (h) | Review & test (h) | Buffer (h) | Decision needed |")
    print("|---|------|------|------|-----------|-------------------|------------|-----------------|")
    print("\n".join(rows))
    print()
    print("| Part | Hours | Days |")
    print("|------|-------|------|")
    print(f"| Build with AI | {r1(tb)} | {tb / fh:.1f} |")
    print(f"| Review and test | {r1(tt)} | {tt / fh:.1f} |")
    print(f"| Risk buffer | {r1(tbuf)} | {tbuf / fh:.1f} |")
    print(f"| **Effort total** (range {r1(lo)}-{r1(hi * 1.25)} h) | **{r1(effort_h)}** | **{effort_d:.1f}** |")
    print(f"| Waiting on decisions | n/a | {len(decisions)} decisions, see calendar |")
    print()
    print(f"**Calendar:** decisions up front {effort_d:.1f} days · batched {effort_d + batched_w:.1f} days · "
          f"one by one {effort_d + serial_w:.1f} days")
    print(f"**For comparison only, one developer without AI:** ~{human[0]:.0f}-{human[1]:.0f} days (unmeasured baseline)")
    ub = unblock_first(items, decisions)
    if ub:
        print("\n**Unblock first:**")
        print("\n".join(ub))

# ---------------------------------------------------------------- agent mode
def agent_minutes(it):
    if "minutes" in it:
        return pert(it["minutes"]), it["minutes"][0], it["minutes"][2]
    size = it.get("size", "M")
    if size == "XL":
        print(f"warning: {it['id']} is XL; split it. Counted as 2 x L.", file=sys.stderr)
        base = [2 * x for x in AGENT_MINUTES["L"]]
    else:
        base = AGENT_MINUTES.get(size, AGENT_MINUTES["M"])
    m = RISK_MULT.get(it.get("risk", "normal"), 1.0)
    rng = [x * m for x in base]
    return pert(rng), rng[0], rng[2]

def mode_agent(data, as_json):
    items = data["items"]
    byid = {it["id"]: it for it in items}
    decisions = {d["id"]: d for d in data.get("decisions", [])}
    machine = data.get("machine", {})
    cap = machine.get("parallel_agents", 6)
    eff = min(cap, machine.get("effective_parallelism", max(1.0, 0.3 * cap)))
    agent_h_day = machine.get("agent_hours_per_day", 20)
    review = data.get("review", "high-risk")
    tax = data.get("failure_tax", 0.20)
    human = data.get("human", {})
    fh = human.get("focus_hours_per_day", 6)
    usage = data.get("usage", {})

    dur, lo_sum, hi_sum, code_m, review_m = {}, 0, 0, 0, 0
    reviewed = 0
    for it in items:
        m, lo, hi = agent_minutes(it)
        r = 0
        if review == "all" or (review == "high-risk" and it.get("risk") == "high"):
            r = pert(REVIEW_MINUTES)
            reviewed += 1
        code_m += m
        review_m += r
        lo_sum += lo
        hi_sum += hi
        dur[it["id"]] = (m + r + MERGE_MINUTES) * (1 + tax)

    missing = sorted({d for it in items for d in it.get("depends_on", []) if d not in byid})
    if missing:
        print(f"warning: unknown depends_on ids ignored: {', '.join(missing[:10])}", file=sys.stderr)

    # earliest finish per task, in topological order (Kahn), so big DAGs stay linear
    deps_of = {t: [d for d in byid[t].get("depends_on", []) if d in byid] for t in byid}
    indeg = {t: len(deps_of[t]) for t in byid}
    users = {t: [] for t in byid}
    for t, ds in deps_of.items():
        for d in ds:
            users[d].append(t)
    ready = [t for t in byid if indeg[t] == 0]
    fin = {}
    while ready:
        t = ready.pop()
        fin[t] = dur[t] + max((fin[d] for d in deps_of[t]), default=0)
        for u in users[t]:
            indeg[u] -= 1
            if indeg[u] == 0:
                ready.append(u)
    if len(fin) != len(byid):
        raise SystemExit("dependency cycle among: " + ", ".join(t for t in byid if t not in fin)[:200])
    finish = fin.__getitem__
    cp_min = max(fin.values(), default=0)
    end = max(byid, key=finish) if byid else None
    path = []
    while end:
        path.append(end)
        deps = [d for d in byid[end].get("depends_on", []) if d in byid]
        end = max(deps, key=finish) if deps else None
    path.reverse()

    merge_m = MERGE_MINUTES * len(items)
    phase_m = data.get("phase_checks", 0) * PHASE_CHECK_MINUTES
    work_m = (code_m + review_m + merge_m) * (1 + tax) + phase_m
    work_h = work_m / 60
    wall_h = max(cp_min / 60 + phase_m / 60, work_h / eff)
    # same formula at the low and high ends: every agent kind is in both, only task minutes and tax move
    lo_work_h = ((lo_sum + REVIEW_MINUTES[0] * reviewed + merge_m) * (1 + tax * 0.5) + phase_m) / 60
    hi_work_h = ((hi_sum + REVIEW_MINUTES[2] * reviewed + merge_m) * (1 + max(tax, 0.25)) + phase_m) / 60
    wall_lo = max(cp_min / 60 * 0.7 + phase_m / 60, lo_work_h / eff)
    wall_hi = max(cp_min / 60 * 1.6 + phase_m / 60, hi_work_h / eff)
    calibrated = bool(data.get("calibrated")) or (bool(items) and all("minutes" in it for it in items))
    pf = 1.0 if calibrated else PLAN_FACTOR
    plan_h = min(max(wall_h * pf, wall_lo), wall_hi)
    plan_work_h = work_h * pf
    agent_days = plan_h / agent_h_day

    rev_h = human.get("review_minutes_per_task", 3) * len(items) / 60
    setup = human.get("local_setup_hours", [2, 3])
    human_h = rev_h + (setup[0] + setup[1]) / 2
    human_d = human_h / fh

    batched_w, serial_w, _ = decision_calendar(decisions)
    cal = [agent_days + human_d, agent_days + human_d + batched_w, agent_days + human_d + serial_w]

    pct_h = usage.get("weekly_pct_per_agent_hour", 0.6)
    pct = plan_work_h * pct_h
    avail = usage.get("weekly_pct_available", 100)
    weeks = pct / avail if avail else 0
    usage_wait_days = max(0, -(-pct // avail) - 1) * 7 if avail and pct > avail else 0

    solo = human_team_days(items)
    team = data.get("human_team_size", 4)

    res = {"tasks": len(items), "calibrated": calibrated, "plan_wall_clock_hours": round(plan_h, 1),
           "plan_agent_hours": round(plan_work_h, 1), "agent_hours": round(work_h, 1), "wall_clock_hours": round(wall_h, 1),
           "wall_clock_range_hours": [round(wall_lo, 1), round(wall_hi, 1)],
           "critical_path_hours": round(cp_min / 60, 1), "critical_path_tasks": len(path),
           "human_hours": round(human_h, 1), "calendar_days": [round(c, 1) for c in cal],
           "weekly_usage_pct": round(pct), "weeks_of_usage": round(weeks, 2),
           "usage_wait_days": usage_wait_days, "solo_no_ai_days_range": [round(solo[0]), round(solo[1])],
           f"team_of_{team}_no_ai_days_range": [round(solo[0] / team), round(solo[1] / team)]}
    if as_json:
        print(json.dumps(res, indent=1))
        return

    print(f"**Tasks:** {len(items)} ({reviewed} with a reviewer agent) · parallel cap {cap}, effective {eff:g}")
    print()
    print("| Part | Value |")
    print("|------|-------|")
    plan_lbl = "Plan" if calibrated else f"Plan (likely × {PLAN_FACTOR:g}, not yet calibrated)"
    print(f"| **Agent wall-clock: {plan_lbl}** | **{(f"{plan_h:.1f}" if plan_h < 10 else f"{plan_h:.0f}")} h** · likely {wall_h:.1f} h · range {wall_lo:.0f}-{wall_hi:.0f} h · {agent_days:.1f} days at {agent_h_day} h/day |")
    print(f"| Agent work (all agents, incl. {int(tax * 100)}% failure tax) | plan {plan_work_h:.0f} agent-hours · likely {work_h:.1f} |")
    print(f"| Critical path | {cp_min / 60:.1f} h over {len(path)} tasks |")
    print(f"| Human: review + local setup | {human_h:.1f} h · {human_d:.1f} focus days |")
    print(f"| Usage | ~{pct:.0f}% of a weekly limit ({weeks:.1f} weeks of budget at {avail}% available) |")
    print()
    print(f"**Calendar to ready-to-merge:** decisions up front {cal[0]:.1f} days · batched {cal[1]:.1f} days · "
          f"one by one {cal[2]:.1f} days" + (f" · +{usage_wait_days} days waiting for usage resets" if usage_wait_days else ""))
    print(f"**For comparison only, without AI (unmeasured baseline):** one developer ~{solo[0]:.0f}-{solo[1]:.0f} days · "
          f"a team of {team} ~{solo[0] / team:.0f}-{solo[1] / team:.0f} days")
    if not calibrated:
        print(f"\n_{HOLDOUT_NOTE}_")
    if len(path) > 1:
        shown = " → ".join(path[:12]) + (" → ..." if len(path) > 12 else "")
        print(f"\n**Critical path:** {shown}")
    if wall_h > cp_min / 60 * 1.5:
        print("\n_Throughput-bound: more effective parallelism (test slots, fewer file conflicts) shortens this, not faster agents._")
    else:
        print("\n_Path-bound: split or reorder the critical-path tasks; more agents will not help._")
    ub = unblock_first(items, decisions)
    if ub:
        print("\n**Unblock first:**")
        print("\n".join(ub))

def main():
    args = [a for a in sys.argv[1:] if not a.startswith("--")]
    if not args:
        raise SystemExit(__doc__)
    with open(args[0]) as f:
        data = json.load(f)
    as_json = "--json" in sys.argv
    mode = data.get("mode") or ("agent" if any("depends_on" in i for i in data.get("items", [])) else "dev")
    (mode_agent if mode == "agent" else mode_dev)(data, as_json)

if __name__ == "__main__":
    main()
```

## File: skills/mythical-agent-month/references/calibration.md
size: 2288
sha: 95db9bcd59d01d3332de148b36181786b1146986
upstream: https://github.com/medadembha/mythical-agent-month/blob/main/skills/mythical-agent-month/references/calibration.md

````text
# Calibration

Defaults are someone else's. After 5-10 tasks, your own numbers win.

## Mode A log (developer + AI)

| Date | Task | Size | Risk | Est. build h | Actual build h | Est. test h | Actual test h | Decision wait (days) | Notes |
|------|------|------|------|--------------|----------------|-------------|---------------|----------------------|-------|

After 5-10 rows: personal build multiplier = Σ actual build ÷ Σ estimated build. Same for test. Use them in later estimates and say so in Assumptions.

## Mode B log (autonomous agents)

Generate it instead of typing it:

```bash
python3 scripts/calibrate.py ~/.claude/projects/<project>/<session>/subagents --tasks tasks.json --csv runs.csv
```

`tasks.json` maps task ids to risk and size: `{"items":[{"id":"t1","risk":"high","size":"M"}]}`. Ids are matched inside the agent labels. The script only reads timestamps, labels, model names and token counts.

| Date | Task | Size | Risk | Model | Est. min | Actual min | Gate test commands | Retries | Output tokens | Notes |
|------|------|------|------|-------|----------|------------|--------------------|---------|---------------|-------|

Seed rows from the real run in `real-runs.md` (medians per group):

| Group | n | Actual min (median) | p75 | Test commands (median) | Output tokens (median) |
|-------|---|---------------------|-----|------------------------|------------------------|
| Code / high risk / big model | 54 | 30 | 39 | 19 | ~186k |
| Code / normal risk | 52 | 11 | 24 | 12 | ~44k |
| Code / low risk / small model | 17 | 3.5 | 8 | 8 | ~27k |
| Reviewer / big model | 39 | 8 | 12 | 1-2 reruns | |
| Phase check | 50 | 1-4 | 20 | full suites | |

## What to update, and where

| You measured | Put it in |
|--------------|-----------|
| Median minutes per size | `AGENT_MINUTES` in `scripts/totals.py`, or `minutes` per task in your JSON |
| Median per risk ÷ normal | `RISK_MULT` |
| Agent-hours ÷ busy hours | `machine.effective_parallelism` |
| Retry share + fix-up agents | `failure_tax` |
| Weekly % used ÷ agent-hours | `usage.weekly_pct_per_agent_hour` |
| All of the above done | `"calibrated": true`: the plan becomes likely, and the held-out warning goes away |

Add the run to `real-runs.md` so the next estimate has a reference case.
````

## File: skills/mythical-agent-month/references/heuristics.md
size: 6526
sha: a3b3e1cd6203d2ee0634384933b1d418c3afb368
upstream: https://github.com/medadembha/mythical-agent-month/blob/main/skills/mythical-agent-month/references/heuristics.md

```text
# Heuristics

Starting numbers only. Replace them with your own as soon as you have 5-10 finished tasks (see `calibration.md`).

## Size

| Size | Typical scope |
|------|---------------|
| XS | Config, copy, one-line fix, a flag. 1 non-test file. |
| S | One endpoint or component, following an existing pattern. 2-4 files. |
| M | A feature slice in one service: model + route + UI, or a migration. 5-12 files. |
| L | A feature across 2+ services, or a new pattern. 13+ files. |
| XL | Split it. |

## Mode A: developer + AI, hours

**Not measured.** These tables are inherited starting points, not data from a real run. Calibrate them after 5-10 tasks (see `calibration.md`).

Build with AI = prompting, reading the generated code, fixing and wiring it in. Not typing time.

| Size | Build [low, likely, high] h |
|------|------------------------------|
| XS | 0.25 / 0.5 / 1 |
| S | 1 / 2 / 4 |
| M | 3 / 6 / 10 |
| L | 8 / 14 / 24 |

Adjust build: unfamiliar codebase ×1.5 · no existing pattern ×1.3 · no AI ×2-3.

Review and test as a multiple of build: low risk 0.5× · normal 1× · high 2-3×. Add 2-4 h per extra service touched (integration).

Risk buffer on build + test: 10% when well known, 25% normal, 50% for many unknowns.

## Mode B: autonomous agents, minutes per task

**Measured on one run of 398 agent runs** (see `real-runs.md`): [p25, median, p90] of real-work code runs, normalised to normal risk. Each figure includes the agent's own gate tests (unit + related). They are not hand-tuned, but they all come from one project. In a held-out test they came out 24-37% low (see below).

| Size | Agent minutes, normal risk [low, likely, high] |
|------|-----------------------------------------------|
| XS | 2 / 4 / 15 |
| S | 3 / 5 / 25 |
| M | 5 / 10 / 35 |
| L | 7 / 12 / 40 |

Risk multiplier: low **0.3** · normal 1.0 · high **2.7**, the measured medians. High-risk tasks run more tests and get a bigger model that reads more.

**Size was a weak signal in run 1; risk was the strong one.** With size taken from the count of non-test files, medians barely moved from S to L, but high risk was 2.7× normal. If you have no better size signal, get risk right first.

| Agent kind | Real median | p75 | Max | Use |
|------------|-------------|-----|-----|-----|
| Code, high risk (big model) | 30 min | 39 | 112 | |
| Code, normal risk | 11 min | 24 | 62 | |
| Code, low risk (small model) | 3.5 min | 8 | 56 | |
| Reviewer agent (big model) | 8 min | 12 | 26 | [4, 8, 26] per reviewed task |
| Merge (scripted / small model) | <1 min | <1 | 28 | 1 min per task |
| Phase check (full suites + fix) | 4 min | 20 | 89 | 12 min per check (the mean) |

The long tail is real: about 1 task in 10 takes 3× the median. Ranges matter more than medians.

### Test-run cost

Gate tests are usually most of an agent's minutes. Rough model: **suites run × minutes per suite × (1 + rerun rate)**.

- Real medians: 19 test commands per high-risk task, 12 normal, 8 low.
- A full related-test run on a large Node backend took 5-15 min. Chunk it, or it hits tool timeouts (10 min is common).
- Never run two test processes in the same working tree if they share a temp DB or port.
- Cap concurrent test runs (test slots) by RAM: about 1 slot per 8-10 GB with in-memory databases.

### Parallelism

- **Cap** = CPUs − 2, or your tool's agent limit.
- **Effective** ≈ 0.3 × cap. One real run had a cap of 6, 3 test slots and per-repo merge locks, and averaged **1.8** agents busy.
- What eats parallelism:
  - tasks touching the same files (they must serialise);
  - test-slot queues;
  - merge locks per repo;
  - phase gates (everything waits for the slowest task in the phase);
  - usage brakes.
- **Wall-clock = max(critical path + phase checks, agent-hours ÷ effective parallelism).** If the critical path wins, split critical tasks; more agents won't help.
- Effective parallelism also drops late in a long run: in run 1 it was 1.7 for phases 0-3 and 1.4 for phases 4-9 (disk pressure, Docker restarts, usage brakes).

### Plan factor

Until you have your own run, the bold **plan** figure is likely × **1.3**. On run 1, the raw likely value came out 12% low in-sample and 37% low held-out; × 1.3 lands at +14% and −19%. Set `"calibrated": true` in the estimate JSON, or give per-task `minutes`, and the plan becomes likely and the held-out warning goes away.

### Failure tax

Add **15-25%** to agent-hours for retries (8-13% of tasks needed a second try), fix-up agents after a phase check fails, broken gates, timeouts and orchestration bugs. Use 25% for a first run of a new workflow script.

### Usage budget

- Agent-hours × **% of weekly limit per agent-hour**. Seed value: **0.6%** (64 agent-hours used about 35-40% of one weekly limit on a high-tier plan, with a big model on high-risk tasks).
- It changes a lot with plan tier and model mix, so calibrate it: note the % before and after a run.
- If the run needs more than what's left this week, the calendar includes waiting for the reset. Keep a brake: stop cleanly at a set %, put the running tasks back to todo, and resume after the reset.

### Machine profile

Disk and RAM end runs early. Budget 5-10 GB free disk for test databases and worktrees, and clean temp DB folders between phases. A frozen Docker or a full disk cost the real run several hours. Add them to the risk list on laptops.

### Post-build human costs (often forgotten)

| Item | Default |
|------|---------|
| Human skim per task commit | 2-5 min |
| Local setup: run migrations, seed demo data, test logins | 2-3 h |
| Bugs found while clicking through locally | 1-3 small fixes, ~30 min each |
| Owner decisions | see below |

## Decision waits (calendar days, never effort)

| Kind | Wait [low, high] |
|------|------------------|
| Already decided / in docs | 0 |
| Small (copy, default value) | 0.5 / 1 |
| Product rule (limits, pricing, UX) | 1 / 3 |
| Cross-team, legal, client sign-off | 3 / 10 |

Batch decisions into one session before the run. Agents can build with an ASSUMED default and log the question, so the run isn't blocked, but count the rework risk.

## No-AI comparison

**Unmeasured.** It's built from size and risk only, never from the AI-assisted hours in the input: (mode A build × 2-3 + mode A test × 1-1.5) × 1.1-1.2 coordination ÷ 6 focus hours. Both modes use this same baseline. Show it as a range, solo and for a team of 4. It's a comparison line, never the estimate or the headline; it sits on unmeasured mode A tables.
```

## File: skills/mythical-agent-month/references/real-runs.md
size: 4892
sha: c1bb6149526ae320e7bf6ae82492958c99050f04
upstream: https://github.com/medadembha/mythical-agent-month/blob/main/skills/mythical-agent-month/references/real-runs.md

```text
# Real runs

Reference cases with measured numbers. Add your own: one section per run, in the same shape.

## Run 1: multi-repo SaaS roadmap, autonomous build (2026)

**Scope:** plans, permissions, usage limits, billing and lifecycle for an existing multi-tenant SaaS.

- 7 repos: Node/Express API, Python AI service, three React front-ends, docs.
- 617 roadmap items, regrouped into **151 feature-sized tasks** in 9 phases. Grouping keeps one task = one feature in one repo; it cut the per-task overhead of 600+ tiny tasks.
- Scope rules: 106 tasks built; 45 deferred by the owner (out of scope for this release); 5 blocked on owner decisions.

**Setup:**

- one dependency-driven workflow script;
- one git worktree per lane, with a pool of 5 worktrees for the busiest repo;
- a file-conflict map so tasks on the same files never ran together;
- tests written first; per-task gate = unit tests + related tests;
- integration suites only at phase end;
- a big model with a reviewer agent on high-risk tasks, a small model on the rest;
- fast-forward merges behind a per-repo lock;
- limits: 6 agents max, 3 test slots, 10-min test timeout.
- Machine: one laptop (8 cores, low free disk), local Docker for DBs and cache.

**Measured** (from 398 subagent transcripts):

| Metric | Value |
|--------|-------|
| Agent-hours (all agents) | 64.2 |
| Wall-clock span | 36.5 h (35.3 h busy) |
| Effective parallelism | 1.82 (cap 6) |
| Code agents | 171 runs, 43 h; median 14 min for real work |
| Reviewer agents | 39 runs, 6.1 h, median 8 min |
| Merges | 96 runs, 2.2 h |
| Phase checks + final reviews | 50 runs, 7.6 h |
| Fix-up / orchestration agents | 25 runs, 5.2 h |
| Retries | 8-13% of tasks needed a second try |
| Critical path (model) | ~19 h over 32 tasks |
| Usage | ~35-40% of one weekly limit |
| Human after the build | ~3 h: migrations, seed data, test logins, 2 bug fixes |

**What a naive AI estimate said:** "about 5 months", i.e. 60-100 working days.

**How well the model fits, honestly:**

| Test | What it means | Agent-hours | Wall-clock |
|------|---------------|-------------|------------|
| In-sample fit | defaults measured on this whole run, then run on its own task graph (`examples/roadmap-106-tasks.json`) | 55.9 vs 64.2 real (**-13%**) | 31.1 h vs 35.3 h real (**-12%**) |
| **Held-out** | tables, risk multipliers, tax and parallelism fit on phases 0-3 only (66 tasks), then predict phases 4-9 (40 tasks) blind | 20.9 vs 27.6 real (**-24%**) | 12.4 h vs 19.8 h real (**-37%**) |

The in-sample row is a fit, not a prediction. The held-out row is the honest number, and it's still the same project, laptop and setup. Two things drove the miss:

- later phases were slower per task;
- effective parallelism fell from 1.7 to 1.4 as disk pressure, Docker restarts and usage brakes piled up.

The model leans optimistic. Plan on the upper half of its range until you have your own run. Method and numbers: `examples/holdout.md`.

**A second, independent run is the missing evidence.** If you run `scripts/calibrate.py` on your own build, please add it here.

**Incidents and what they cost:**

| Incident | Cost | Lesson |
|----------|------|--------|
| A loader dropped "blocked" statuses and a skip cascaded through dependents | ~2 h, and a re-run | Copy statuses exactly; "evidence pending" is not "blocked" |
| Lane-level locking serialised the busiest repo | Most of a phase at 1× parallelism | Use a worktree pool + a file-conflict map, not one lane per repo |
| Soft phase gates let tasks start before their base code existed | Retries | Keep hard deps on phase close |
| Related-test runs (245-339 suites) exceeded the 10-min tool timeout | Repeated gate failures | Chunk test runs; run long ones in the background |
| Reviewer fixes refused by a permission rule (`commit --amend`) | Re-runs | Reviewers add a separate fix commit |
| Integration regressions found only at phase end (8 suites, 3 real 500s) | 1 fix agent, ~1 h | Phase-end integration catches what per-task gates miss |
| Disk filled with 55 leftover in-memory DB folders (4 GB) | Test DB crashes, hours | Clean temp DB folders between phases; watch free disk |
| Docker froze under memory pressure | ~1 h | Budget RAM for test slots |

**Real bugs caught before merge:**

- a rollback that didn't roll back;
- a price-migration notice sent to the wrong group;
- lifecycle routes answering 500;
- an operator screen missing its DB model, found only during local click-through;
- role and filter endpoints returning 500.

All of them were in high-risk areas, which is why high-risk tasks keep the reviewer and the bigger test budget.

**Takeaways:**

1. Agents cut build time to hours; the calendar is set by tests, decisions and usage.
2. Expect effective parallelism of about 0.3 × the cap.
3. The human tail (local setup, click-through, decisions) is small in hours but sets the calendar.
```

## File: skills/mythical-agent-month/assets/portable-prompt.md
size: 2671
sha: c68c791a1cd9643e88f2f464851f4bd68878494f
upstream: https://github.com/medadembha/mythical-agent-month/blob/main/skills/mythical-agent-month/assets/portable-prompt.md

```text
# Portable prompt

Paste this into any assistant (ChatGPT, Gemini, Cursor rules, a system prompt) when you can't install the skill.

---

When I ask how long software work will take, don't estimate at human-team pace. I build with AI coding agents.

**First pick the mode:**

- **A, developer + AI**: I drive an assistant task by task. Estimate focus hours.
- **B, autonomous agents**: agents build tasks on their own, often in parallel. Estimate agent wall-clock, usage and the human calendar.

**For every task give:** size (XS/S/M/L; split XL), risk (low/normal/high; high = money, auth, permissions, data deletion, migrations, tenant isolation), open decisions as questions with owners, and for B the dependencies.

**Mode A numbers:**

- Build with AI, hours [low/likely/high]: XS 0.25/0.5/1 · S 1/2/4 · M 3/6/10 · L 8/14/24.
- Test = build × 0.5 (low), × 1 (normal), × 2-3 (high), + 2-4 h per extra service.
- Buffer: 10-50%.
- Effort days = total ÷ 6 focus hours.

**Mode B numbers:**

- Agent minutes per task, normal risk [low/likely/high]: XS 2/4/15 · S 3/5/25 · M 5/10/35 · L 7/12/40. Risk ×0.3 low, ×2.7 high.
- Reviewer agent on high-risk tasks: 8 min. Merge: 1 min. Phase check: 12 min.
- Failure tax: +15-25%.
- Agent-hours = Σ all of the above.
- Wall-clock = max(critical path + phase checks, agent-hours ÷ effective parallelism). Effective parallelism ≈ 0.3 × the agent cap, about 1.8 for 6 agents.
- Usage ≈ 0.6% of a weekly limit per agent-hour (calibrate).
- **Plan = likely × 1.3** until calibrated; make the plan number the bold one.
- Human: 2-5 min review per task + 2-3 h local setup.

**Use PERT** = (low + 4 × likely + high) / 6.

**Decision waits are calendar days, never effort:** 0 if decided, 0.5-1 small, 1-3 product rule, 3-10 cross-team. Calendar range = up front / batched (+ longest wait) / one by one (+ sum of waits). Add usage-reset waits if the run exceeds this week's budget.

**Output:**

- a bottom line;
- assumptions;
- a task table;
- a parts table (build or agent time, test or critical path, human hours, usage, waits);
- the calendar range;
- "unblock first" decisions;
- top 3 risks;
- confidence.

Show no-AI pace (from size and risk only: build × 2-3 + test × 1-1.5, +10-20%) only as a range on a comparison line, labelled unmeasured, never as the headline. Round hours to 0.5, days to 0.1. Never give one number without the breakdown.

Reference: a real 106-task, 7-repo build took 64 agent-hours and 35 h wall-clock, not the 60-100 days a naive estimate gave. These numbers come from that one run and ran 24-37% low in a held-out test, so plan on the upper half of the range until calibrated.
```

## File: README.md
upstream: https://github.com/medadembha/mythical-agent-month/blob/main/README.md

````text
# 🗿 Mythical Agent Month

<p align="center"><img src="assets/hero-v8.webp" alt="A developer texting their AI agent, a real moai at Rano Raraku. You: how long for the full roadmap? Agent: realistically? 3 months. You: bro we ship it today. Agent: …for a team of 4, right? You: you’re the team. all 6 of you. go. Agent: done, 106/106 tasks. Caption: took 35h. we’re calling that today" width="100%"></p>

**Your agent said 5 months. Agents built it in 35 hours.**

An estimation skill for Claude Code, Codex, Cursor, Gemini CLI and Copilot (plus a paste-in prompt for anything else) that stops AI from quoting human-team timelines for agent-built software.

> Brooks, 1975: *"Adding manpower to a late software project makes it later."*
> 2026: your agent still estimates like it's 1975.

---

## The problem

Ask an AI "how long will this roadmap take?" and you get "3-5 months", sprint plans, story points. That's human-team pace, learned from human tickets.

We ran the real thing: a **106-task, 7-repo SaaS roadmap** built by autonomous agents (worktrees, parallel lanes, tests first, reviewer agents, phase-end suites).

| | Naive AI estimate | Real run |
|---|---|---|
| Time | "about 5 months" (60-100 days) | **35.3 h** agent wall-clock |
| Agent-hours | - | 64.2 |
| Usage | - | ~35-40% of a weekly limit |
| Ready to merge | - | ~3 days |

The code wasn't the slow part. Tests, review, decisions and the usage limit were.

### How accurate is the skill? Honestly:

| Test | Raw "likely" wall-clock | **Plan** (likely × 1.3, the bold number it prints) |
|---|---|---|
| In-sample fit: defaults measured on this run, run on its own task graph | 31.1 h vs 35.3 h real (-12%) | **40 h (+14%)** |
| **Held-out:** fit on phases 0-3, predict phases 4-9 blind | 12.4 h vs 19.8 h real (-37%) | **16 h (-19%)** |

So it gets the **order of magnitude** right: hours, not months. The raw model **leans optimistic**, so until you calibrate, the number it prints in bold is the **plan** (likely × 1.3), with the likely value and the range beside it. It's still **n = 1**: one project, one laptop, one setup. The method is in [`examples/holdout.md`](examples/holdout.md). **A second, independent run is the missing evidence. Yours would help.**

## What it does

It never gives one big number. It separates:

- **Machine time**: agent wall-clock and agent-hours, using the task graph's **critical path** and the parallelism you really get.
- **Human effort**: prompting, review per commit, local setup, click-through.
- **Waiting**: decisions and usage-limit resets. They're calendar time, never effort.
- **Usage**: the % of your weekly limit, so you know whether the run fits this week.

There are two modes:

| Mode | When | Output |
|------|------|--------|
| **A: Developer + AI** | You drive an assistant task by task | Focus hours and days, with a calendar range |
| **B: Autonomous agents** | A plan split into tasks that agents build, often in parallel | Wall-clock, agent-hours, critical path, usage %, calendar to ready-to-merge |

Both modes show the no-AI pace as a **comparison line only**.

## Numbers from real runs, not vibes

The defaults are measured on **398 subagent runs from one real build**, not hand-tuned:

| Agent kind | Median | p75 |
|---|---|---|
| Code task, high risk (big model) | 30 min | 39 min |
| Code task, normal risk | 11 min | 24 min |
| Code task, low risk (small model) | 3.5 min | 8 min |
| Reviewer agent | 8 min | 12 min |
| Merge | <1 min | <1 min |

Lessons from that run that ended up in the model:

- **Effective parallelism ≈ 0.3 × your agent cap.** 6 agents gave about 1.8 agents of throughput once test slots, file conflicts and merge locks queued, and it fell to 1.4 late in the run.
- **Risk dominates size.** High-risk tasks (billing, auth, migrations) took 2.7× a normal one; size by file count barely mattered. High risk is also where every real bug was caught.
- **The failure tax is real: +15-25%** for retries, fix-up agents, broken gates and full disks.
- **The human tail is small in hours but sets the calendar:** decisions, migrations, local setup.

The full case study, with the incidents and what each one cost, is in [`references/real-runs.md`](skills/mythical-agent-month/references/real-runs.md).

## Install

**Claude Code plugin** (Claude Code 2.1.275 or later):

```
/plugin install mythical-agent-month --marketplace MedAdemBHA/mythical-agent-month
```

It also works with **any agent that supports the open [Agent Skills](https://agentskills.io) standard** (`SKILL.md`). One line:

```bash
curl -fsSL https://raw.githubusercontent.com/MedAdemBHA/mythical-agent-month/main/install.sh | bash -s -- all
```

Prefer not to pipe to bash? It only copies one folder, so do it by hand:

```bash
git clone --depth 1 https://github.com/MedAdemBHA/mythical-agent-month.git
cp -R mythical-agent-month/skills/mythical-agent-month ~/.claude/skills/   # or your agent's folder below
```

Or choose your agents, and add `--project` to install into the current repo instead of your home folder:

```bash
./install.sh claude codex --project
```

| Agent | Personal folder | Project folder |
|---|---|---|
| Claude Code | `~/.claude/skills/` | `.claude/skills/` |
| OpenAI Codex | `~/.agents/skills/` | `.agents/skills/` |
| Cursor | `~/.cursor/skills/` | `.cursor/skills/` |
| Gemini CLI | `~/.gemini/skills/` | `.gemini/skills/` |
| GitHub Copilot (VS Code) | `~/.copilot/skills/` | `.github/skills/` |
| claude.ai | upload `mythical-agent-month.skill` from [Releases](../../releases) in Settings → Capabilities → Skills | |
| Anything else (ChatGPT, Windsurf, custom agents) | paste [`portable-prompt.md`](skills/mythical-agent-month/assets/portable-prompt.md) into rules or the system prompt | |

Any other tool that reads `SKILL.md`: copy `skills/mythical-agent-month/` into its skills folder. The scripts need only Python 3.

Then just ask: *"how long will this take?"*, *"estimate this backlog"*, *"how long will this workflow run?"*, or paste an estimate to check.

## Try it

```bash
cd skills/mythical-agent-month
python3 scripts/totals.py ../../examples/agent-feature.json       # 8-task feature, agents
python3 scripts/totals.py ../../examples/dev-feature.json         # same feature, developer + AI
python3 scripts/totals.py ../../examples/roadmap-106-tasks.json   # the real 106-task run (anonymised)
```

You only need Python 3, with no dependencies. The output is Markdown; add `--json` for totals only. Sample outputs are in [`examples/`](examples/).

Mode B input, minimal:

```json
{
  "mode": "agent",
  "machine": {"parallel_agents": 6, "effective_parallelism": 1.8},
  "items": [
    {"id": "t1", "task": "Schema + migration", "size": "M", "risk": "high", "depends_on": []},
    {"id": "t2", "task": "API", "size": "L", "risk": "high", "depends_on": ["t1"]},
    {"id": "t3", "task": "UI", "size": "M", "risk": "normal", "depends_on": ["t2"]}
  ]
}
```

## Does the skill actually change answers?

[`examples/with-vs-without.md`](examples/with-vs-without.md) has one everyday prompt answered with and without the skill by Claude Code's own eval runner, both copied verbatim. Without the skill, Claude already calls a 6-week estimate too long. The skill's difference is structure: decision waits kept separate from effort, a calendar range, questions to unblock first, and per-task risk.

[`evals/`](evals/) holds 6 cases you can run yourself, including one where the skill must **not** apply (a team working without AI):

```bash
claude plugin eval . --runs 3      # with vs without the skill, scored by an LLM judge
```

## Calibrate with your own runs

My numbers come from my machine and my codebase, so yours will differ. Point the calibrator at your Claude Code subagent transcripts:

```bash
python3 scripts/calibrate.py ~/.claude/projects/<project>/<session>/subagents --tasks tasks.json
```

It's read-only: it uses timestamps, labels, model names and token counts, and prints no content. You get:

- real minutes per age
````
