skill
you-are-here
You are here: project state, wrap-then-/clear, a tiny per-repo brain, and hands-free runs until the PR is green. For Claude Code. Stdlib Python; macOS, Linux, Windows.
Set up
Skills are installed by placing their folder where your agent loads skills.
The download comes from github.com/ARYN26/you-are-here itself, not from our server, so what you get is exactly what its author published.
Install instructions come from the README
README
synced Oct 26, 2026you are here
Opus 5.5 high | 142k | 5h 31% | wk 48% (pace 52%) | checkout/payment | PR#12 | CHECKOUT P2/4
yah is a Claude Code plugin that shows which plan, phase, PR and next step you're on and tells you when to wrap (write the next step down, commit, then /clear), because short sessions that start from written-down state cost far less than long ones that rediscover it.
Why
- You lose your place. A new session does not know your plan, phase, PR or next step, so it re-reads long docs to find out.
- Sessions run long with no signal to stop. Opus 5.5, Sonnet 5 and Fable have a native 1M context window on every plan, and auto-compact fired at about 967k (observed in Claude Code 2.1.x). Nothing stops a session at 400k.
- Idle resumes cost a full cache rewrite. Resuming after more than an hour idle rewrites the whole prompt cache.
- Project facts get rediscovered. Plan state holds open work, not durable facts like "production deploys only from main". Each new session finds them again, in tokens and turns.
The author measured one week of their own usage (2026-09-14 to 09-23, one Max 20x account, about $2,600 at API prices):
| Where it went | Share |
|---|---|
| Main thread | 59% |
| Workflow (ultracode) agents | 30% |
| Subagents | 11% |
The expensive part was one long session, not parallelism. 95% of Fable spend was a single main-thread session that ran at 400k to 970k context on xhigh and max effort, and auto-compacted 6 times. Other findings:
- 23 resumes after more than an hour idle, each rewriting the whole cache.
- Sessions started from the home folder, so project memory never loaded. Agents re-read big docs to orient, about 41k tokens in one start.
- Finding "which PR and phase am I on" took 14 lookups.
- Review workflows ran 23 to 30 agents over a handful of files.
This is one person's week, not a benchmark. yah makes the habits that avoid it visible: one task per session, state written down, and a clear signal to wrap.
What you get
A statusline, three hooks, ten skills, three agents and an optional run driver with two hooks of its own. Stdlib Python, MIT licensed.
| Piece | What it does | What it costs you |
|---|---|---|
| Statusline | One line: model and effort, context (green, amber, then red with "wrap"), 5-hour and weekly use with pace (wk green when catch_up_pct points or more under it), branch, PR, plan phase, items waiting on you, and "cache cold" after an hour idle. | About 35–70 ms per refresh on Windows, depending on the machine, and 55 ms in WSL (median of 25 runs), run locally. It never runs git, gh or bd. The model does not see it. |
| SessionStart hook | Injects up to 6 lines of state (branch, plan, phase, NEXT, top PR, PROD), plus one stack line per plan phase (status, branch, PR and what it changes once merged), at startup, /clear, compact and resume, and asks the model to restate phase, NEXT and what waits on you in one line before its first tool call. A NEXT older than later commits on the phase branch is flagged /yah:wrap first. If the plan or a CLAUDE.md names another plugin's /x:wrap, /x:where and so on, the block maps them to yah's. | About 125 tokens (495 characters in the S7 test run), plus at most 120 characters per plan phase, plus about 40 when it maps another plugin's names, on every turn: it stays in the prompt, so it is part of the per-turn total in the listing row below. It also runs git, plus gh pr list (over the network), and bd list only in a repo with .beads/, before the session starts; a slow gh or bd can add up to about 8–10 s. |
| Context guard | A UserPromptSubmit hook. It nudges once at the wrap mark, once at wrap now, once per session on a premium model, once a day when weekly use runs ahead of pace, once a day when it runs catch_up_pct points or more behind, and once per session when the session runs an older yah than the one installed, and once per session with codex on, saying what goes to GPT. It never blocks. | One local Python run per prompt. A short message only when a nudge fires. |
| Brain recall | A UserPromptSubmit hook. On a session's first prompt it injects the brain notes that match the prompt, the phase and your changed files. | 0 when the repo has no brain folder. Otherwise once per session, capped at about 2.5k tokens, usually a few hundred. Recall over 100 notes took about 80–130 ms. |
/yah:where | The full view in up to 15 lines: branch (with no upstream, how far ahead of its base), plan, phase, NEXT and whether commits have made it stale, what waits on you, the PR stack and the PROD warning. With a plan it then adds the phase map: the stack with each phase's after line, and the current phase's file tree. | Runs git, plus gh if installed, and bd only in a repo with .beads/. The output enters your context. |
/yah:auto | The launcher's first prompt, so a session starts without you typing. It reads the injected state and runs the step it calls for. An open plan phase starts yah run --plan --detach (autopilot, which goes on after the session closes); /yah:auto here does the step hands-on through /yah:start instead. It reports a live run, and for one that ended offers a rerun, /yah:deep or hands-on work. It asks a NEEDS-HUMAN question, writes the answer into NEXT and starts the run again, checks a PR that waits on you, fixes failing checks or review comments, tracks a newly approved plan with /yah:phases, sends a hard question to /yah:deep on any tier, and ends with /yah:wrap. With no plan it asks what to build; it never invents a task. | One turn to pick the step, then that step's own cost. Hidden from the model, so no listing cost. |
/yah:start | Starts a task: restates the task, phase and first step from the injected state before any tool call, runs one recall on the task's key nouns, allows at most one targeted search, then makes the edit. Offers to create a brain folder if there is none. | One turn plus the recall output. |
/yah:wrap | Ends a task. Rewrites NEXT in STATE.md, ticks off finished items, writes at most one brain note, commits WIP on the feature branch, stamps NEXT with that commit and saves durable lessons to memory. When the phase is done it runs a review if available, pushes, opens the PR with the phase's map in its description and claims the next phase. Ends with "Safe to /clear", and with a plan phase open, says /yah:auto hands it to autopilot. | One turn in your session. Writes in your repo. |
/yah:phases | Turns an approved plan into phases in STATE.md. | One turn. Writes in your repo. |
/yah:tree | The phase map: /yah:tree plan stacks the phases on their bases with status, PR and what each changes once merged; /yah:tree P<n> adds that phase's file tree, from its branch diff once it has commits, else from the plan's Files: block. The same map shows in plan mode before you approve, in each phase PR's description and in /yah:where. | Runs git, plus gh unless --no-gh. Hidden from the model, so no listing cost. |
/yah:deep | Sends one self-contained hard question to Fable in a forked agent (high effort, read-only, 300 words or fewer). Works on every tier: when the account cannot use Fable, Claude Code runs the agent on the session's model. | Fable usage. See the plan table. |
/yah:gpt | Opt-in (setup.py --codex). Sends multi-source web research, a read-only review of the repo, a UI mockup brief or a UI screenshot critique to GPT through OpenAI's codex CLI in a forked agent, and returns a short answer plus the path of the full report (and of each mockup PNG). See Claude + GPT. | Your ChatGPT plan's Codex allowance, not Claude usage, beyond the forked agent's few turns. Off by default. |
scout agent | Read-only lookups on Sonnet at low effort. Answers in 150 words or fewer. | Sonnet tokens instead of main-thread tokens. |
yah run and /yah:resume | Chains fresh headless sessions, one bounded slice each, until the phase's PR is open and green, then stops; with --plan, through every open phase. The merge is yours unless you turn on auto-merge. See Hands-free runs. | Your normal plan usage: one full session per iteration, each capped by --max-budget-usd. |
| PostToolUse guard | The context guard again after each tool call, so wrap nudges reach a headless session, which has only one prompt. | Only inside yah run iterations: one local Python run per tool call. Interactive sessions never run it. |
| Push guard | A PreToolUse hook on Bash and PowerShell that denies force pushes, pushes to protected branches and merges. See Rails. | Only inside yah run iterations: one local Python run per Bash call. Interactive sessions never run it. |
| Quality profile opt-in | Max 20x only, offered by /yah:setup: ultracode on in every session with workflows capped at medium size, a once-per-session sizing rule that names each job's model and effort from roles, and in yah run high effort plus one critic and one judge per phase. See Quality profile. | About 165 tokens once per session. The rest is the profile's own spend: xhigh effort, workflow agents, and the critic and judge sessions. |
| Skill and agent listing | The short descriptions Claude Code lists so the model knows these exist, each 92 characters or fewer. /yah:auto, /yah:resume and /yah:setup are hidden from the model. | Measured in one clean A/B pair against a no-plugin session: +593 tokens per turn in total. Of that, the skill listing is about 125 tokens (493 characters), the agent listing about 75 (299 characters) and the SessionStart block about 125; the other ~270 were not attributed (likely wrapper text and noise). Since that run the SessionStart block gained its restate rule (104 characters, about 26 tokens) and the wrap description 7 characters. If you append RULES.md through setup, add about 425 tokens (about 1,705 characters) per turn. |
/yah:setup and the yah launcher | Sets the statusline and your tier. Optionally adds a yah <project> shell function that cds into a project and starts claude on /yah:auto; yah run goes to the run driver. | Changes statusLine in settings.json, after a backup. Each step asks first. |
Install
/plugin marketplace add ARYN26/you-are-here
/plugin install yah@you-are-here
/yah:setup
A plugin cannot set the statusline, so /yah:setup does it. It asks your tier, shows a dry run, and applies only after you say yes. Then it offers the quality profile on max20, auto-update (see below), auto-merge for yah run, the yah launcher, and to append RULES.md to ~/.claude/CLAUDE.md (about 425 tokens on every turn). Each step needs your yes.
You can also run setup from a terminal (use python on Windows):
python3 "$HOME/.claude/plugins/marketplaces/you-are-here/scripts/setup.py" --tier max5 --dry-run
Flags: --tier pro|max5|max20|api, --dry-run, --uninstall, --python CMD, --launcher bash|zsh|fish|powershell|cmd (prints the snippet), --install-launcher RCFILE (a .cmd path, or a folder on Windows, gets a whole yah.cmd), --install-rules [FILE] (appends RULES.md as a marked block; default CLAUDE.md in the Claude config folder), --ultracode (opt-in, runs on its own: turns on the quality profile and changes nothing else), --auto-update (opt-in, runs on its own: turns on Claude Code's auto-update for yah's marketplace and changes nothing else), --auto-merge (opt-in, runs on its own: sets auto_merge in config.json and changes nothing else; see auto-merge) and --yes (no prompts).
Updating
yah sets no version number, so every commit to main counts as a new version. Claude Code does not auto-update third-party marketplaces unless you turn it on, and a plugin author cannot change that default. /yah:setup offers to turn it on for you (setup.py --auto-update), or do it yourself: /plugin → Marketplaces → you-are-here → Enable auto-update. Without that, update by hand with claude plugin update yah@you-are-here (or /plugin → Installed → yah → Update now), then run /reload-plugins or start a new session. /clear is not enough: a session keeps the yah it loaded until one of those, so yah tells you once per session when a newer one is installed. The statusline and the launcher run from the marketplace clone, so they pick up the update too.
Running a fork of yah, or another plugin with the same hooks? Disable it while yah is installed (/plugin disable <name>); otherwise every hook and skill listing runs twice.
Requirements
- Claude Code: tested with 2.1.280.
yah runneeds a version that supports--permission-prompts. - macOS: needs
python33.9+, from the Xcode Command Line Tools or Homebrew. Without the Command Line Tools,/usr/bin/python3opens an install dialog, so setup times out its probe and tells you to runxcode-select --installorbrew install python. zsh gets the launcher. - Linux: needs
python33.9+. bash gets the launcher. - Windows: needs Python 3.9+ from python.org or winget, plus Git for Windows. Claude Code runs hooks in Git Bash there. Setup tries
python, thenpy -3, thenpython3, becausepython3on Windows is often the Microsoft Store stub. PowerShell gets the launcher. cmd.exe loads no profile, so for cmd setup writes ayah.cmdinto a folder on PATH instead (next toclaudeby default):--install-launcher <folder>\yah.cmd. After Ctrl+C in Claude, cmd may ask "Terminate batch job (Y/N)?"; that is cmd, not yah. Without Git Bash, Claude Code falls back to PowerShell for hooks, and yah's hooks cannot run there (the statusline still works). Setup warns when it cannot find Git Bash. - Optional:
ghadds the PR lines, andyah runneeds it to follow the PR. Plan state lives in aSTATE.mdfile in the repo, so there is nothing to install (see Plan state: STATE.md). A repo that already uses beads can keep it (see If you already use beads).
The daily loop
- Start in the project. Run the launcher:
It cds into the repo and startsyah shopclaudewith/yah:autoas the first prompt, so there is nothing to type: it starts or reports the detachedyah runfor an open phase (yah shop hereworks hands-on instead), asks aNEEDS-HUMANquestion, checks a PR that waits on you, or, with no plan, asks what to build.yah shop add Apple Pay to the payment formhands it that task instead. Flags go straight toclaudewith no prompt, e.g.yah shop --resume <id>. Runyahalone to list projects. If two repos share a folder name,yah NAMElists both and refuses; give one a key underprojectsin config.json. Starting from the home folder means project memory does not load. The SessionStart hook tells the model where you are. - The step runs through the yah skills. A tiny task (a few lines in one or two files, no design choice) runs in the session:
/yah:autosays so in one line and calls/yah:start. Any other task, even one PR, goes to plan mode (see Autopilot)./yah:autoalso calls/yah:phaseswhen a new plan is approved,/yah:deepfor a hard question and/yah:wrapat the end. You can call any of them yourself:
It restates the task, phase and first step before any tool call, recalls the brain notes that apply, does at most one targeted search, then edits. Typing the task plainly works too: the first prompt gets brain recall either way./yah:start "add Apple Pay to the payment form" - Work one task.
- Wrap when the statusline says wrap:
When a plan phase is still open, wrap starts the detached/yah:wrapyah run --planitself and says the session can close. It does not when NEXT waits on you (NEEDS-HUMAN:or a(you)phase), a run is already live or the tree is dirty; then/clear. After a tiny task, wrap sets NEXT back to the open phase's step, so the plan picks up again. - Resume. A started run needs nothing from you: close the session. Otherwise the fresh session after
/cleargets PLAN, PHASE and NEXT injected, so it starts on the next step without reading docs. Type/yah:auto; from a terminal,yah shopsends it for you. If the statusline says "cache cold",/clearbeats resuming the old session.
A new task while another plan has an open phase and no run is live? The new task goes first. The open plan is parked: its phase goes back to [ ] with a Parked: NEXT was ... line under it. When the new plan's last phase closes, wrap claims the parked phase again, and the new PR's merge becomes a (you) follow-up. The next yah <project> hands the parked phase to a run.
A new multi-phase plan was just approved? Run /yah:phases before its first phase. Want steps 2 to 5 repeated without you? See Autopilot.
Autopilot
You decide at the start; the rest runs without you.
- Give it the task.
yah shop add Apple Pay and refunds, oryah shopand answer what to build. Every task that is not tiny goes to plan mode, one PR or several. Claude explores, then drafts one phase or stacked phases, each with a done-when, a branch and a base. It sends the draft to/yah:deep, which lists the decisions and risks the plan leaves open. - Answer everything once. Before it shows the plan, Claude asks you every one of those decisions, a few questions at a time, and writes the answers under
## Decisionsin the plan file. Then it draws the phase map under## Mapat the end of the plan, so the approval view shows each phase's stack line, what it changes once merged and its file tree. A headless session can still stop with aNEEDS-HUMANquestion, but only for what nobody could foresee. - Approve the plan.
/yah:phaseswrites it to STATE.md and/yah:autostartsyah run --plan --detach. The session can close; the run goes on in fresh headless sessions, one phase after another (seeyah run). - PRs. With auto-merge off (the default), each green PR waits for you and the next phase stacks on its branch. With auto-merge on, the run merges each green PR it opened and builds the next phase on where it merged.
- Check in.
yah shopor/yah:whereshows the RUN line. While the run lives,/yah:autoonly reports it and offers to end it. When it stops you get a desktop notification, and/yah:autoasks itsNEEDS-HUMANquestion and starts it again, or for a run that stopped offers a rerun,/yah:deepon why, or hands-on work.
yah shop here opts out at the start: an open phase runs in the session through /yah:start, as in the daily loop. Its /yah:wrap still hands the rest of the plan to a run.
Aim and bets
yah asks why before it spends a run, in at most three questions. A tiny task skips all three, and a given task or a NEXT skips the first two.
- The aim, once per project, when there is no plan and nothing to continue: "Who is this project primarily for, and what should it help them accomplish?" Claude drafts 2-3 answers as job stories,
Help [primary user] [outcome] when [situation], from the README's first 40 lines and the PROD line only. The answer goes into STATE.md asAIM: <sentence>under its title, and shows at every session start and in/yah:where. Decline it and yah writesAIM: noneand never asks again. - The pick, each time there is no plan and no NEXT:
/yah:autoranks the## Follow-upsagainst the AIM in impact (H/M/L) and effort (S/M/L) buckets, judged only from each item's own text and quoting the words each rests on. A blocker comes first; an item whose effort the text does not give becomes a discovery task, never a guess. You get three rows,A/B/C | id title | outcome | impact/effort | evidence | done-when, with A recommended;autotakes A, and Other names a new task. With no follow-ups it asks what to build or fix. - The bet, in plan mode: the plan file gets a
## Betwith the outcome (tied to the AIM), non-goals,appetite: $<X> and <H>h(from past runs, else $7 and 0.6h a phase) and twostop if <signal> by <checkpoint>lines./yah:deepruns a pre-mortem on the plan to find them. The last planning round asks "Is worth , done when , stopping if ?": run, shrink (cut phases and ask again) or skip (drop the plan). A build session that sees a stop-if fire stops withNEEDS-HUMAN: stop-if hit: <which>, <evidence>.yah runenforces the appetite: the plan's spend is the cost and wall-clock hours of every run on that plan file, and reaching either part stops the run with exit 9. Each run log starts with aplan <file> | before $<X> and <H>hline, so the newest log holds the whole spend even after older logs are pruned. Only one run at a time may work on a plan file, across checkouts and worktrees, so no two runs start from the same spend; a second is refused (exit 5). runs from before this line count toward no plan. No## Bet, or noappetite:in it, means no limit.run.py --appetite-hint <phases>prints the default: the median cost and time per finished phase over past run logs.
Sources: job stories (Intercom) and Lean Canvas for the aim; coarse impact/effort buckets with quoted evidence in place of RICE or WSJF, which need numbers a backlog line cannot give; Shape Up's appetite, Gary Klein's pre-mortem and Annie Duke's kill criteria for the bet.
The brain
Plan state (STATE.md) holds open work and is rewritten every session. Durable facts, such as "Vercel builds production only from main" or "the API rate-limits at 10 rps, batch writes", live nowhere, so each session rediscovers them. The brain is a folder of one-fact notes in your repo, docs/brain by default (brain_dir in config). It is plain markdown: no database, no embeddings, no MCP server. The folder opens as an Obsidian vault.
Start one with /yah:start "<task>". If the repo has no brain folder, it says so once and offers brain.py init, which creates the folder with README.md, _pending.md and INDEX.md. It never creates one unasked. Every brain feature stays silent in a repo without the folder.
A note is <brain_dir>/<slug>.md:
---
title: Vercel deploys only from main
tags: [deploy, vercel]
paths: ["vercel.json", ".github/**"]
status: active
source: PR #41, 2026-09-20
---
Vercel builds production only from main; previews come from PR branches.
Optional detail. Links: [[preview-env-vars]].
- The slug is lowercase
a-z,0-9and dashes, 60 characters or fewer. - Frontmatter is flat
key: value, with lists as[a, b]. No nesting and no multi-line values. - The first body line is the TL;DR, 200 characters or fewer.
[[slug]]links another note. pathsare globs (**means any depth). A note whose glob matches a file changed on your branch ranks higher.
Rot rules
| Rule | How it works |
|---|---|
| At most one note per wrap | /yah:wrap asks whether the session established a durable fact or decision a future session would otherwise rediscover. Progress goes in NEXT and preferences go in memory. It runs brain.py find first, then updates, supersedes or adds, and commits the note with the WIP commit. |
| A source is required | A PR, commit sha, issue, URL, path/to/file:line, or user, YYYY-MM-DD. Without one, brain.py new appends the note to _pending.md instead, for you to accept or drop (brain.py pending lists them). |
| Supersede, never delete | brain.py new --supersedes <old-slug> marks the old note status: superseded with superseded_by. |
| INDEX.md is generated | Rewritten after every write, sorted by slug, never hand-edited. Each rewrite warns about missing sources, broken links and a superseded_by that points nowhere. |
What gets injected, and when. On the first prompt of a session, a UserPromptSubmit hook ranks the active notes and injects the top 5 TL;DRs with their sources, up to 10 more slugs and the pending count. Later prompts in that session get nothing. A repo with no brain folder does not use up the session's recall, so a brain made mid-session still gets one. Slash commands are skipped, and the first plain prompt after them still gets recall; /yah:start and /yah:resume run their own. The block is capped at recall_max_chars (10,000 characters, about 2.5k tokens) and is usually a few hundred tokens:
[yah] brain: 3 of 18 notes match "add Apple Pay to the payment form" (docs/brain, full list in INDEX.md)
- stripe-webhooks-idempotent: Stripe retries webhooks; handlers dedupe on event.id. (PR #31, 2026-09-02)
- payment-form-tests-use-test-clock: E2E tests pin time with a Stripe test clock. (tests/e2e/pay.spec.ts:14)
- no-client-secret-in-logs: Never log a PaymentIntent client_secret. (user, 2026-09-10)
1 unreviewed note in docs/brain/_pending.md
Ranking is word overlap, not semantic search. The title counts 3, tags 2, the TL;DR 1, and the current phase and NEXT 1.5 against the title and tags. Words are lightly stemmed (pushes, pushed and pushing all match push), and short terms like PR, UI, CI and DB count. A paths glob matching a changed file (git diff <base>...HEAD plus git status, 3 s timeout each) adds 4, or 2 when no word matched, and a link to or from a top-5 note adds 1 to a note that already matches. A note whose words never come up will not surface; INDEX.md is the full list. Claude runs brain.py for you: recall, find, new, index, init and pending, each with --cwd DIR. brain.py writes only inside the brain folder.
Hands-free runs: yah run
Claude Code cannot /clear itself or start a new session from inside one. No hook, skill or tool can. So the wrap, clear, continue loop needs an outside driver, and yah run is that driver. Run it in a terminal, or start it from a session with --detach:
yah run [TARGET] [--plan] [--cwd DIR | --project NAME] [--iterations N] [--budget USD] [--model M] [--plugin-dir DIR] [--dry-run] [--detach]
yah run --stop [--cwd DIR | --project NAME]
yah run --spend [DAYS]
Without the launcher, run python3 "$HOME/.claude/plugins/marketplaces/you-are-here/scripts/run.py" with the same arguments (python on Windows). Try --dry-run first.
| Argument | Meaning |
|---|---|
TARGET | P<n> (a plan phase), #<pr>, or empty for the current phase. Shells treat # as a comment, so pass 12 or '#12'. A P<n> with no such phase is refused (exit 5). An empty TARGET is pinned to the current phase at start, so a wrap that claims the next phase cannot move the run. |
--plan | Go on past exit 0: once the phase's PR is open and green (or merged) and the phase is closed, run the next open phase, until none is left. TARGET must be P<n> or empty; an empty one works from a trunk checkout too, since the plan names the phase. See Whole plans. |
--cwd DIR, --project NAME | The repo to run in. Default: the current folder. --project refuses (exit 5) when two known repos share the name; use --cwd then. |
--iterations N | Max sessions per phase. Default run_iterations, 8. |
--budget USD | --max-budget-usd per session. Default run_budget_usd, by tier (below). |
--model M, --plugin-dir DIR | Passed to claude. Without --plugin-dir, a run.py started from a yah checkout (not from plugins/cache or plugins/marketplaces) passes --plugin-dir <checkout> itself, so each session has /yah:resume. --dry-run prints which one it used. |
--dry-run | Prints the resolved argv, the DENY list, the caps and what it would do now. Spawns nothing, but still calls gh. |
--detach | Runs in the background and returns once the run has started (exit 0), or with the run's own exit code if it stopped first. On Windows it has no console window, so closing the terminal or ending the Claude Code session does not end it; elsewhere it gets its own session, so SIGHUP never reaches it. Its output goes to <data dir>/runs/<project>-<time>.out beside the .log. |
--spend [DAYS] | Prints what runs cost over the last DAYS days (default 7, today included, local dates), one row per day with a session or a stop: builds and reviews (critiques and judges) apart, each as its dollars and its sessions by model (? for an iteration line from before the model tag), the sessions run in catch-up, and the stop codes as <exit>: <count>. A total row follows, with the runs that stopped and any log with no stop line yet, then usage-log.csv's <day> wk <n>% pace <n>% rows for those days. Read-only: it takes no lock, needs no plan and works inside a run's own session. /yah:deep and /yah:gpt costs are not in the logs, and past the 20 newest runs a log is pruned after 31 days. |
--stop | Ends the run going in this checkout: the driver, the session it is in and every process under them. The pid file then says exit 130, "ended by yah run --stop", so the RUN line shows the run ended. A session cut off mid-edit can leave uncommitted work in the tree. With no live run it says so and exits 0. /yah:auto offers it when a session starts in a checkout a run is working in. |
The loop. Each iteration runs one headless session in the repo:
claude -p "/yah:resume P2 build" --permission-mode auto --permission-prompts none --disallowedTools <DENY...> \
--max-budget-usd 10 --output-format stream-json --verbose \
--settings '{"hooks":{"PreToolUse":[...push_guard.py],"PostToolUse":[...context_guard.py]}}'
/yah:resume orients with where.py and brain recall, gets on the phase branch (its instructions rule out trunks and PROD), does one bounded slice toward NEXT, runs the tests, follows /yah:wrap and ends with a YAH-RESULT: line. A decision that needs you becomes NEXT = NEEDS-HUMAN: <question>. Before and after each iteration, run.py reads the PR (gh pr view, then gh pr checks, required checks first) and the phase (where.py). Pending checks are polled every 30 s for up to run_checks_wait_minutes. Failing checks make the next slice fix-checks, which reads the failing CI logs. A CHANGES_REQUESTED review newer than the head commit makes it address-review. With the quality profile on, a judge that blocks makes it fix-findings.
Stop rules. Checked before and after each iteration. The first match wins:
| Exit | When |
|---|---|
| 6 | The PR was merged or closed. With --plan, a merged PR whose phase is closed moves on to the next phase instead. |
| 8 | With auto_merge on, where 0 would stop: the PR met every auto-merge rule and yah merged it, "merged by yah". With --plan, the run goes on to the next phase instead. |
| 0 | The PR is open, its checks pass (or it has none), no CHANGES_REQUESTED review is newer than the head commit, and the phase is closed (or TARGET was a PR). "The merge is yours." With the quality profile on, the judge runs first. With auto_merge on, it also says which merge rule was not met. With --plan: no open phase is left, "plan done", with each phase's PR. |
| 2 | The last session needs you: it ended in an error (a timeout included), a permission was denied during it, it ended needs-human or blocked, or it ended without a YAH-RESULT: line (usually the plugin was not loaded). Also a failed auto-merge step. The denial or question is printed. |
| 3 | Stalled: HEAD and NEXT unchanged for 2 iterations in a row. |
| 4 | The iteration cap, or run_total_hours of wall clock. |
| 7 | Weekly usage at or over run_week_stop_pct, or more than pace_slack points ahead of pace. On the other side of pace, catch_up_pct points or more under it, the quality profile's catch-up spends the rest of the week instead. |
| 9 | The plan's spend reached the dollars or the hours of the appetite: in its ## Bet, "appetite reached: $ of $". Checked before every session, critiques and fix slices included, so a restarted run stops before its first one. The judge of an open, green PR still runs. |
| 5 | Refused: not a git repo, on a trunk or the PROD branch with no TARGET, claude not on PATH, gh missing, an invalid TARGET, a P<n> with no such phase, an unknown or ambiguous project, or no way to name the branch the PR targets (no base in the plan, no open PR, no origin/HEAD and no prod in config), so it cannot be protected. That last check also runs before each iteration. Also another run already going in this checkout (below), or a start or --stop from inside a run's own session (--dry-run still works there). |
| 1, 130 | run.py itself failed, or you pressed Ctrl-C or ran yah run --stop. |
One run per checkout. A run holds a lock on <data dir>/runs/<project>-<hash>.pid (<project>-<hash>@<worktree>.pid in a linked worktree; the hash keeps two repos with one folder name apart), a JSON file with its pid, target, log and, once it stops, its exit code and reason. A second run in the same checkout is refused while the first lives. The OS drops the lock when the driver dies, so a pid file whose lock is free is a run that ended, even after a crash or a reboot. /yah:where, the session-start block and the statusline show it as the RUN line: while it runs, its target and the log's last line; once it ends, its exit code and reason (for 3 days), or died when it was killed before it could say.
Whole plans: --plan
yah run --plan keeps going where a plain run stops. When the phase's PR is open and green (or merged) and its phase is closed, it pins the next open phase and runs that. It stops with exit 0, "plan done", when no open phase is left in the plan it started on (another ## Plan: below is not run). It stops with exit 2 when the next phase is marked (you), or when the finished phase's last session asked for you or hit a denial. Unless auto_merge is on, it never merges: each green PR waits for you, and the finished phase's branch is protected for the rest of the run.
A new phase's base comes from the plan. There are two exceptions, and in both /yah:resume gets base=<branch> and writes it to the phase line:
- If the plan's base is another phase's branch whose PR has merged, the phase builds on where that PR merged, since the branch may be gone.
- If the phase has no base, it stacks on the phase the run just finished, while that PR is open.
The iteration cap is per phase. run_total_hours and the weekly pace hold for the whole run. --dry-run prints the phase order with each base.
Auto-merge: opt-in
Off by default: a run stops at a green PR and the merge is yours. /yah:setup offers to turn it on (setup.py --auto-merge, which sets auto_merge: true in config.json). Only a JSON true counts; "true" or 1 leaves it off. /yah:where then shows auto-merge: on on a green phase PR instead of merge: you and its gh pr merge <N> --merge command.
With it on, the driver merges, never the model: gh pr merge stays on the DENY list and the push guard still denies it in every session. The driver merges only when all of these hold:
- at least one check ran, and every check passed;
- GitHub says it is
MERGEABLE, with merge stateCLEANorHAS_HOOKS; - it is not a draft;
- no CHANGES_REQUESTED review is newer than the head commit;
- you opened it: its author is your
ghuser; - it is the PR of the plan phase the run is on;
- it does not target another phase's branch (a stacked PR waits until the PR below it merges and it is retargeted);
- the last session did not end in an error, a denial,
needs-humanorblocked.
It reads the PR again once its checks pass and judges only that read, since the wait for checks can be long: a review, a draft or a new commit that lands during the wait stops the merge.
Then, in this order: gh pr merge <N> --merge --match-head-commit <sha> (a merge commit, never a squash, and only if the head has not moved); each open PR based on the merged branch is retargeted to the merged PR's base; the merged branch is deleted on GitHub, never a protected one. Retargeting comes first because GitHub closes a PR whose base branch is deleted, which is also why it never passes --delete-branch. The run stops with exit 8, "merged by yah"; with --plan it goes on, and the next phase builds on the merged PR's base. A rule not met leaves the PR to you (exit 0 says which), and a failed merge step stops the run with exit 2.
Turned on after a stacked plan finished. A plan run with auto-merge off leaves a stack of green PRs, each on the phase below it. yah run --plan then finds no open phase, says "plan done" and merges nothing. Merge the stack bottom-up, one plain run per phase: yah run P1 finds P1 closed and its PR green, so it starts no session (with the quality profile on, the judge runs first), merges it with exit 8 and retargets P2's PR to P1's base. Then yah run P2, and so on up the stack. Out of order, yah run P2 stops with exit 0 and says its PR targets another phase's branch.
Critic and judge: quality profile
With the quality profile on (ultracode: true in config.json), a run adds two read-only reviews to each phase, on roles.critic: Fable at high effort by default, or GPT when codex is on:
- Critique, before the phase's first build, when the phase has no PR and its branch is not on origin.
/yah:resume P2 critiquereads the code the phase will touch and writes at most 300 words: what will break, what is missing, and the order to build in. The answer is saved asruns/<run>-P2-critique.md, and the next build prompt ends withcritique=<path>. That build folds it in and logs each change it makes to the plan as aDecided:line. A phase that already has a PR or a pushed branch gets no critique, so a restarted run does not pay for a second one; nor does a phase whose NEXT isNEEDS-HUMAN:, since its build stops there. - Judge, once the PR is open and green and the phase is closed: where the run would stop with exit 0 or auto-merge.
/yah:resume P2 judgereadsgh pr diffand reports only the defects it can prove and that should block the merge: wrong behavior, data loss, a security hole, or a broken or weakened test.judge passlets the run stop or merge as usual.judge block <n>saves the findings asruns/<run>-P2-judge.mdand runs onefix-findingsslice on them, even at the iteration cap. Then the loop goes on as usual (checks, reviews, stop rules), with no second judge, so a judge can hold a merge back by one slice, never for good.
Each runs once per phase per run, with Edit, Write, NotebookEdit, git commit and git push denied on top of the DENY list, and under the same push guard, --max-budget-usd and run_iteration_minutes as a build. No judge runs after a session that stopped for you, since the run stops there anyway, nor once run_total_hours has passed. A judge that blocks after a build that ended in an error or without a YAH-RESULT: line still gets its fix slice: the PR was green, so that ending stopped nothing. A critique or judge that fails (an error, a timeout, or not the YAH-RESULT: line it should end with) is logged as skipped, and the run goes on without it.
Catch-up. Before every critique, build and judge, the run reads the week: the same weekly % and pace the exit-7 stop uses, from the last session's stream, else from limits.json. A reading past its reset counts as none. When the week is catch_up_pct (20) points or more under pace, the pool would go unspent, so the run turns catch-up on and says so once, with the gap and the hours to the reset. In catch-up each build runs one effort step higher (high becomes xhigh) with 1.5 times its --max-budget-usd ($15 on max5), since a build at xhigh costs more and a session that ends on its budget stops the run. With a codex critic, each phase's critique moves to roles.premium (Fable at high effort), even with codex down; the judge stays GPT, because it gates the merge and is the other model family. A Claude critic already spends the pool, so its critique is unchanged. Catch-up turns off, and says so, once the gap closes or the reading goes unknown. With the profile off, nothing changes.
The critic's bar. Before each review, a Claude critic reads its model's own weekly pool, such as seven_day_fable, if Claude Code ever sends one; today it sends only the weekly bar, so that is the one it reads. At critic_week_skip_pct (50%) or more, the session runs on roles.judge (Opus at high effort) instead. Only with no reading at all does it log bar unknown and run on the critic. To move both off Fable for good, set roles.critic.
GPT critic. With codex on, roles.critic defaults to codex high, unless you set it yourself. The critique and judge then run as codex.py review in a read-only sandbox, not as /yah:resume sessions. GPT gets no plan tools, gh or network there, so run.py writes its brief to runs/<run>-P2-critique-brief.md or -P2-judge-brief.md: the phase's plan section and the plan's Decisions, or the PR's diff. They run at codex_effort on codex_model, have no Claude bar, and log $0, since they spend your ChatGPT plan's weekly allowance instead. A codex call that fails or hits its limit reruns that review on roles.review_fallback (Opus at high effort) and turns codex off for the rest of the run. A brief that cannot be built (no plan section, no diff) sends only that one review to roles.review_fallback.
Log lines. The console shows each one as it starts. The console and the .log show how it ended: model and effort, why that model, cost, then its result and file, or why it was skipped:
[yah] catch-up on: 44 pts under pace (52% used, 96% of the week gone, 7h to reset): builds at xhigh with a $15 budget, critique on fable high
[yah] critique P2: /yah:resume P2 critique on fable high (catch-up: 44 pts under pace)
[yah] critique P2: fable high (catch-up: 44 pts under pace), $0.62, critique-done, youarehere-20260926-113655-P2-critique.md
[yah] iteration 1: $1.25, 38 turns, opus xhigh, progress, HEAD 5c591ee, NEXT P2: ...
[yah] judge P2: /yah:resume P2 judge on opus high (week 55%, at or over 50%: roles.judge)
[yah] judge P2: opus high (week 55%, at or over 50%: roles.judge), $1.10, judge block 2, youarehere-20260926-113655-P2-judge.md
[yah] judge P3: fable high (week 40%), $0.40, skipped: it ended with YAH-RESULT: blocked dirty tree
[yah] critique P4: codex.py review on codex high (GPT, no Claude bar)
[yah] critique P4: codex high (GPT, no Claude bar), $0.00, critique-done, youarehere-20260926-113655-P4-critique.md
Each one's raw stream goes to runs/<run>-P2-critique.jsonl or -P2-judge.jsonl, and --dry-run prints a critic line: what it would critique or judge now, and on which model.
Costs. Each critique or judge is a full session, billed like an iteration and capped by the same --max-budget-usd. On Fable it counts against Fable's own usage bar. They do not count toward --iterations, and the stop line counts them apart: Cost $8.40 over 5 iterations, plus $1.72 over 2 critic/judge sessions. A phase's ceiling is about (iterations + 3) × budget: its iterations, one critique, one judge and one fix-findings slice. run_total_hours and the weekly stop are checked before a critique and before the fix slice. The judge runs only where the run would stop anyway. yah run --spend shows a week of these by day, builds and reviews apart and by model.
Rails. Every iteration gets two layers. Neither is a sandbox (see Limits). run.py never passes --bare, bypassPermissions or --dangerously-skip-permissions. Protected branches are main, master, your trunks (default also develop and dev), the branch your prod text names, and, with no config needed, what where.py infers from git alone: the plan's phase bases, the branch open PRs land on (cached, so a closed PR still counts), origin/HEAD, and on a work branch the nearest branch on its first-parent chain, the one it was cut from (a branch merged into it, like a docs PR, is not one). When that chain holds only trunks, the nearest branch merged into it is protected too: a base synced in with git merge looks just like a merged docs PR to git. The set only grows during a run, including the base of the PR it follows. No session can merge; with auto_merge on, the driver merges between sessions (see Auto-merge).
-
Push guard.
scripts/push_guard.py, a PreToolUse hook on Bash and PowerShell, added through--settingsfor run iterations only. It parses each command, includinggit -C path push,git -c key=value push,cd x && git pushand combined short flags like-uf, and denies:- force pushes,
+refspecs,--mirror,--all,--delete/-d,:branchdeletes, wildcard refspecs and--prune; - any push whose destination is a protected branch;
- a bare
git pushorgit push origin HEADwhile the current branch is protected; gh pr merge, merges throughgh api, andgh repo delete.
It also checks commands inside
bash -candeval. Agit pushit cannot parse is denied. When a push is denied, the session ends withYAH-RESULT: blocked push deniedand the run stops (exit 2). - force pushes,
-
DENY list. The second layer: glob patterns passed as
--disallowedTools, which--dry-runprints in full. The PowerShell tool is turned off entirely, since its commands would bypass Bash patterns. The patterns cover force pushes (git push --force*,-f*,*--force*,* -f*, any+),gh pr merge*,gh api *merge*,gh repo delete*, the delete, mirror, all and prune flags, and for each protected branch B:git push * B,* B *,* HEAD:B*,* *:B*and*refs/heads/B*.
Caps. All are config.json keys:
| Key | Default | Meaning |
|---|---|---|
run_iterations | 8 | Max sessions per phase. |
run_budget_usd | pro 5, max5 10, max20 15, api 5 | --max-budget-usd per iteration, from your tier. |
run_iteration_minutes | 45 | Wall clock per iteration, or the time left in the run if that is less. At the cap the whole process tree is killed. |
run_total_hours | 6 | Wall clock for the whole run. |
run_checks_wait_minutes | 30 | How long to wait for pending PR checks. |
run_week_stop_pct | 80 | The weekly usage % that stops a run. |
Logs and notifications. The console shows one line per tool call and a summary per iteration: cost, turns, result, HEAD and NEXT. The data folder keeps runs/<project>-<YYYYmmdd-HHMMSS>.log (those summaries and the stop reason) and runs/<project>-<YYYYmmdd-HHMMSS>-<n>.jsonl (iteration n's raw stream), for the 20 newest runs; an older run keeps its .log alone for 31 days, so --spend still counts it. The .jsonl files hold every tool input and output of the session, including any secret it read, such as a .env file. On stop it prints the reason, the PR URL, the total cost, the iteration count and the log path, rings the terminal bell, and sends a desktop notification: osascript on macOS, notify-send on Linux, a PowerShell balloon tip on Windows. Notification failures are ignored.
Limits, plainly
- It spends your normal plan usage. Each iteration is a full Claude Code session that counts against your 5-hour and weekly limits. On an API key it is billed per token.
--max-budget-usdis Claude Code's own per-session cap on the cost it computes. yah passes it through, and the costs yah prints are that same figure. A run's ceiling is about iterations × budget, for example 8 × $10 with themax5preset.- It feeds other people's text to an unattended session. fix-checks and address-review read PR comments, review text and CI logs.
/yah:resumeis told to treat them as data, but that is an instruction, not a guarantee. Runyah runonly on repos where you trust everyone who can comment or push. - The rails are not a sandbox. The push guard parses Bash commands and the DENY list matches patterns. A push run from inside a script or another program is a command neither one sees, so it gets past both. Turn on branch protection for your trunk and prod branches: no force pushes, no direct pushes, PRs required.
- A denial ends the run after that session. Runs use auto permission mode, where a classifier reviews actions, with prompts denied. A denied action, a push-guard or DENY hit included, is refused but does not stop the session; when the session finishes, the run stops with exit 2. Auto mode must be available for your account and model; a session that starts in another mode is killed at once and the run stops with exit 2, rather than burn a session on denials.
- The weekly-pace stop needs a reading. It uses the rate-limit event in the session's stream, else the statusline's last reading (
limits.json, if under 6 h old). With neither, it logs "pace unknown" and does not stop on pace.
Recommended settings per plan
| Plan | Claude Code included? | Main model | Effort | Fable | Parallel agents / ultracode | yah tier preset (amber / wrap / wrap now) |
|---|---|---|---|---|---|---|
| Free | No | n/a | n/a | n/a | n/a | n/a |
| Pro ($20/mo, $17 yearly) | Yes | Sonnet 5 for most work; Opus 5.5 for hard steps* | Medium or lower | Needs extra-usage credits | Avoid* | pro 100k / 120k / 160k |
| Max 5x ($100/mo) | Yes | Opus 5.5 or Sonnet 5* | Medium* | Up to 50% of the weekly cap, own usage bar. Only via /yah:deep* | Only for genuinely parallel work* | max5 120k / 150k / 200k (default) |
| Max 20x ($200/mo) | Yes | Opus 5.5* | High, or the quality profile (ultracode by default) via the opt-in* | Up to 50% of the weekly cap, own usage bar. Only via /yah:deep, plus the profile's per-phase critic and judge in yah run* | Ultracode workflows at medium size, for genuinely parallel work* | max20 150k / 200k / 260k |
| Team standard ($25/mo, $20 yearly) | Yes | Sonnet 5 for most work | Medium or lower | Via credits | Avoid* | max5* |
| Team premium ($125/mo, $100 yearly) | Yes | Sonnet 5 for most work; Opus 5.5 for hard steps* | Medium* | Up to 50% | Only for genuinely parallel work* | max5* |
| Enterprise | Yes | Sonnet 5 for most work; Opus 5.5 for hard steps* | Medium* | Premium seats up to 50%; standard seats use credits | Only for genuinely parallel work* | max5* |
| API key | Pay per token (Opus 5.5 is $4/$20 per MTok) | Sonnet 5 for most work | Medium or lower | Pay per token | Agent teams use about 7x the tokens | api 80k / 100k / 150k |
Cells marked * are the author's judgement calls. Prices are as of September 2026: plans from claude.com/pricing, API from the API pricing page. Everything else comes from the sources below.
- Official cost advice:
/clearbetween tasks (/compactis itself a large request), Sonnet for most work, lower effort, subagents for long output, and trim MCP servers and CLAUDE.md. Agent teams use about 7x the tokens. - Effort levels are low, medium, high, xhigh and max. Opus 5.5 defaults to medium.
- Limits: all subscription plans have a rolling 5-hour window plus a weekly cap, shared with claude.ai.
- Statusline usage numbers (5h and wk) come from Claude Code's
rate_limits. Observed in Claude Code 2.1.x: it appears only for Pro and Max subscribers, after the first response, and never for API keys. - Tier presets are starting points, not official numbers. There is no official mapping for Team or Enterprise, so start at the default and adjust.
Sources, as of September 2026: claude.com/pricing, support articles 15424964, 11049741 and 17007452, and the Claude Code docs on model config, statusline and costs.
Quality profile
The quality profile has Opus do the work at high effort with ultracode on, and gives Fable two jobs only: critic of each phase's plan, and judge of what should block its merge. Ultracode runs the main thread at xhigh effort and lets Claude orchestrate workflows of parallel agents. It gives the best results on a Max 20x plan, but a workflow can burn more tokens than doing the same work in the conversation. /yah:setup on max20 offers the profile as an opt-in (setup.py --ultracode, which runs on its own and leaves the statusline alone). That sets:
ultracode: trueinsettings.json, so every session starts with it on;workflowSizeGuideline: "medium", so workflows stay under 10 agents;ultracode: truein yah'sconfig.json, which turns on the profile:- Once per session: questions, single-file edits and small reviews stay in the main thread. A workflow is only for genuinely parallel work, with one agent per independent unit, and the model and effort for lookups, mechanical stages, and research and judges come from
roles.roles.premiumand a Claude critic stay out of workflows unless a workflow role uses the same model. Before a Workflow call, Claude gives one line with its agent count and rough $ cost. A workflow reuses one schema across its agents and passes on the branch and PROD rules. One verifier per finding, and reports of 1,500 characters or fewer. - When weekly use runs ahead of pace: keep workflows under 5 agents, and suggest
/effort highfor work that is not parallel. Changing effort does not rewrite the cache. - When weekly use runs behind pace by
catch_up_pct(20) points or more, once a day and on its own flag (an over-pace morning and an under-pace evening each nudge once): what is unspent at the reset is lost, so today/yah:deepfor any hard question (not on Pro, where Fable takes extra-usage credits), a suggested/effort xhighfor work that is not parallel, and workflows up to the size guideline. This nudge and the greenwkalso show with the profile off, without the workflow clause.yah run's own sessions skip it; the run catches up itself. - In
yah run: child sessions start with--effortfromroles.main, and its model unless you pass--model. Each phase gets one critique of its plan before the build and one merge-blocker judge on its green PR, onroles.critic. When the critic's weekly bar is atcritic_week_skip_pct(50%) or more, both run onroles.judgeinstead. When the week iscatch_up_pct(20) points or more under pace, catch-up builds one effort step higher with a bigger budget and, with a GPT critic, puts each critique onroles.premium. See Critic and judge. With the profile off,yah runpasses no--effortand runs no critic or judge.
- Once per session: questions, single-file edits and small reviews stay in the main thread. A workflow is only for genuinely parallel work, with one agent per independent unit, and the model and effort for lookups, mechanical stages, and research and judges come from
Roles are "model effort" strings in config.json:
| Role | Default | Used for |
|---|---|---|
main | opus high | yah run build sessions |
scout | sonnet low | lookups in workflows |
mechanical | opus medium | mechanical workflow stages |
judge | opus high | research and judges in workflows; the critic and judge when the critic's bar is high |
critic | fable high, or codex high with codex on | yah run's per-phase critique and judge |
review_fallback | opus high | a GPT critique or judge whose codex call failed |
premium | fable high | the critique in catch-up with a GPT critic; kept out of workflows; codex leaves it alone |
Set only the role you want to change: {"roles": {"critic": "opus high"}} moves the critic and judge off Fable. Effort must be low, medium, high or xhigh; max, junk or a missing value falls back to that role's default. /yah:deep stays on Fable either way, because its agent file pins the model.
The critic's bar. The statusline saves every extra rate_limits pool, such as a per-model weekly bar, into limits.json under pools. yah looks for a pool whose key contains the critic's model name, such as seven_day_fable. That key name is a guess until Claude Code is seen sending one. When no pool matches, the bar counts as unknown, which is treated as under 50%.
The wrap marks stay at 150k / 200k / 260k. Workflow agents run in their own contexts, so the main thread stays short. yah run sessions inherit ultracode too, and each one is still capped by --max-budget-usd. --uninstall puts the previous values back, in config.json too.
Claude + GPT
yah can split the work across two subscriptions: a Claude plan (the author uses Max 5x) and a ChatGPT plan with Codex (the author uses Pro $100). Claude plans and builds. GPT critiques and judges yah run's phases, does multi-source web research, draws UI mockups and critiques UI screenshots. A second model family also catches what a same-family reviewer misses.
| Job | Who | How |
|---|---|---|
| Planning, building, fixing | Claude (roles.main) | Your sessions and yah run build slices |
| Single lookups | Claude | The main thread or the scout agent |
| Multi-source web research | GPT | /yah:gpt research <question>, which Claude reaches for on its own once codex is on |
| Read-only review on request | GPT | /yah:gpt review <brief>, or the Codex plugin's /codex:review |
| UI mockups | GPT | /yah:gpt mockup <brief>: GPT's image tool draws them, and codex.py copies each PNG next to the report as <stamp>-mockup-<n>.png |
| UI screenshot critique | GPT | /yah:gpt critique <brief> --url <page> shoots the page at 375x812 and 1440x900 in headless Edge or Chrome ($YAH_BROWSER to pick one); or pass PNG paths instead of --url. Ranked issues back |
yah run critique and judge | GPT | With the quality profile on, roles.critic defaults to codex high; see GPT critic |
| One hard question | Fable | /yah:deep only |
The month budget. Claude's weekly pool is the scarce one, so it goes to building; the statusline's wk bar and pace show where it stands. GPT's weekly Codex allowance pays for reviews, research and images. OpenAI does not publish the numbers; run /status in codex to see yours. Image turns burn several times what text turns do.
Rules Claude follows with codex on. Once per session, with or without ultracode, the context guard tells Claude: send multi-source web research to /yah:gpt research as a self-contained question, and keep a single lookup in Claude; on UI work, run /yah:gpt mockup, build, then /yah:gpt critique --url; with the quality profile on, yah run's critiques and judges are GPT's; use Fable only through /yah:deep; and a GPT finding is a claim to prove in the code or with a test before fixing it. With your own Claude model in roles.critic, it leaves out the line about run reviews. RULES.md, if you append it through setup, holds the same rules plus one more: never enable the Codex plugin's review gate.
Setup.
- Install and sign in to the codex CLI:
npm install -g @openai/codex, thencodex login. - Run
/yah:setupand say yes to GPT, or runsetup.py --codex. It checks the login, makes one small live call, then setscodex: trueinconfig.json.--uninstallputs the old value back. - Optional, for interactive reviews: OpenAI's Codex plugin,
/plugin marketplace add openai/codex-plugin-cc, then/plugin install codex@openai-codex. Never run/codex:setup --enable-review-gate: that gate is a Stop hook that can loop Claude and Codex and drain both plans.
The keys are codex, codex_model, codex_effort, codex_timeout_minutes and roles.review_fallback; see Config. Every codex call runs in a read-only sandbox, and yah never gives GPT your gh or network in a run review.
What it reads, writes and never does
Reads
- Claude Code's statusline JSON on stdin,
.git/HEAD, the where cache and the session transcript (the statusline's idle time, the guard's context size). git, plusghwhen installed, in the current repo (where.py), andbdonly in a repo with.beads/.STATE.mdorNOW.mdat the repo root, or the main checkout's from a linked worktree.- The brain folder, plus
git diff --name-onlyandgit statuswhen a note haspaths(recall). config.jsonin the data folder, andsettings.jsonduring setup.
Writes on its own: only the data folder. That is ~/.claude/you-are-here/, or $CLAUDE_CONFIG_DIR/you-are-here/ when that variable is set.
| File | What it is |
|---|---|
config.json | Optional config, see below |
where-<project>.json | The last where.py result for a project, read by the statusline and the home view. A repo not registered in projects gets where-<name>-<8-hex path hash>.json, so two repos with the same folder name don't collide |
state-<session>.json | The statusline's latest numbers, read by the context guard |
guard-<session>.json, guard-daily.json | Flags so each nudge fires once |
limits.json | The latest 5-hour and weekly numbers, plus any extra pools such as a per-model weekly bar under pools, written by the statusline when they change, read by yah run |
recall-<session>.flag | Marks that first-prompt recall already ran |
runs/ | yah run logs, the 20 newest runs, plus older .log files for 31 days |
usage-log.csv | One row per day: date, time, five_hour_pct, week_pct, week_pace_pct, model |
setup-state.json | What setup changed, so --uninstall can undo it |
state-*, guard-* and recall-* files older than 3 days are deleted.
Writes in your repo only when you ask. That means /yah:wrap, /yah:phases, a yes to a brain folder in /yah:start, and yah run, whose sessions follow /yah:wrap. The run driver itself writes nothing in the repo. The wrap skill tells Claude to commit only on the feature branch and never to commit .env* files.
Network. yah's scripts make no network calls of their own and send no telemetry. The only network traffic is gh (if installed) reading PRs and checks, and the push and PR that /yah:wrap makes when a phase is complete, in your session or in a yah run session. With auto_merge on, the yah run driver also merges, retargets and deletes a branch through gh.
Pushes and merges. In an interactive session, "push only the feature branch, never a trunk or PROD, never merge" is an instruction in the /yah:wrap skill, not a block. The hard blocks, the push guard and the DENY list, exist only inside yah run. Either way, turn on branch protection. yah merges only when you opt in with setup.py --auto-merge, and then only the yah run driver merges, never the model (see auto-merge).
Never
- blocks a prompt
- merges a PR, unless you turn on auto-merge. Even then only the
yah rundriver merges, never the model, with a merge commit (never a squash), and it never deletes a protected branch. - changes your model, effort, permissions, hooks or env settings. Setup never does, except
ultracodeandworkflowSizeGuidelinewhen you opt in with--ultracode.yah runpasses its permission mode, DENY list, push guard and PostToolUse guard as flags to its own child sessions only, plus--effortand--modelfromrolesonly with the quality profile on.
Setup touches only:
statusLineinsettings.json, after savingsettings.json.bak-yah-YYYYmmdd-HHMMSS. The old value goes intosetup-state.json.config.jsonin the data folder (the tier, andultracodeorauto_mergeif you opt in).- With
--ultracodeonly:ultracodeandworkflowSizeGuidelineinsettings.json, after a backup. The old values go intosetup-state.json. - With
--auto-updateonly:autoUpdate: trueon yah'sextraKnownMarketplacesentry insettings.json, after a backup (the entry is added with the source Claude Code recorded if it is missing). The old value goes intosetup-state.json. - With
--auto-mergeonly:auto_merge: trueinconfig.json. The old value goes intosetup-state.json. - Optionally, your shell rc (a block between
# >>> you-are-here >>>and# <<< you-are-here <<<) and~/.claude/CLAUDE.md(RULES.md appended in a marked block). Each happens only after your yes. Setup never rewrites an rc file that isn't valid UTF-8; it prints the snippet for you to paste instead.
Hooks. Claude Code runs hooks in sh on macOS and Linux and in Git Bash on Windows, so one POSIX command covers all three:
python "${CLAUDE_PLUGIN_ROOT}/scripts/where.py" --brief 2>/dev/null || python3 "${CLAUDE_PLUGIN_ROOT}/scripts/where.py" --brief 2>/dev/null || py -3 "${CLAUDE_PLUGIN_ROOT}/scripts/where.py" --brief
Windows has python. macOS and Linux fail on it instantly and fall through to python3. Every script catches all errors and exits 0, so a fallback never runs twice. SessionStart has a 20 s timeout, and the two UserPromptSubmit hooks (guard and recall) have 10 s each.
Files. Stdlib Python 3.9+, under 3,000 lines in scripts/.
| File | Role |
|---|---|
scripts/yahlib.py | Shared helpers: data folder, config and tier presets, git lookup, JSON io, the plan-state shape |
scripts/where.py | Builds the where view from git, STATE.md and gh, and tells /yah:phases and /yah:wrap where the plan is written |
scripts/phasemap.py | The phase map behind /yah:tree: the phase stack, and a phase's file tree from the plan's Files: block or its branch diff |
scripts/beads.py | The beads adapter, only for a repo that already uses beads: reads .beads/ into the same shape as STATE.md |
scripts/statusline.py | The statusline. Never runs git, gh or bd |
scripts/context_guard.py | The nudges: UserPromptSubmit, and PostToolUse inside yah run |
scripts/brain.py, scripts/recall_hook.py | The brain (recall, find, new, index, init, pending) and first-prompt recall |
scripts/run.py | yah run |
scripts/push_guard.py | The PreToolUse push guard inside yah run |
scripts/setup.py | Setup and --uninstall |
hooks/hooks.json | SessionStart and UserPromptSubmit wiring |
skills/*/SKILL.md | /yah:auto, /yah:where, /yah:start, /yah:wrap, /yah:phases, /yah:tree, /yah:deep, /yah:resume, /yah:setup |
agents/scout.md, agents/deep.md | The two agents |
RULES.md | Optional CLAUDE.md snippet |
Plan state: STATE.md
yah keeps plan state in STATE.md (or NOW.md) at the repo root: plain markdown, nothing to install, and git is its history. /yah:phases writes the plan section and /yah:wrap keeps it true.
For larger repos:
- Worktrees share one plan. A linked worktree without its own STATE.md reads the main checkout's, and
/yah:wrapwrites there, so parallel sessions and agents in worktrees see the same plan and none of them loses its NEXT when its worktree is removed. - The branch is the claim. A phase's
| branchsays who holds it: a session on another branch getsphase branch is X, you are on Y. - Finished work leaves.
/yah:wrapdeletes finished follow-ups, and a plan whose phases are all done once none of its PRs is open. Git, the PRs and the plan file keep the history.
## Plan: Checkout rewrite (docs/plans/checkout.md)
- [x] P1 Cart API | branch checkout/cart | PR #11
- [~] P2 Payment form | branch checkout/payment | base checkout/cart | PR #12
- [x] Card element
- [ ] Apple Pay button
- [ ] P3 Emails
## Follow-ups
- [ ] Approve the payment copy (you)
- [~] Flaky e2e test on Safari
## 2026-09-23
- Next: Wire the Stripe element into PaymentForm.tsx, then run the e2e test.
- Phases are the outermost checkbox lines in a
## Plan:section.[x]is closed,[~]or[>]is in progress, and[ ]is open. Exactly one outermost[~]is the current phase. - Fields are
branch X,base XandPR #N, separated by|or·. The label isP<n>, and the id isSTATE.md:<line>. - An indented checkbox line under a phase is a sub-task: not a phase, and not counted in done/total.
- A
[~]line anywhere else (a sub-task, or under## Follow-upsor another section) is work in progress, not a phase: with no plan,/yah:wherelists it as a DOING row. Open[ ]lines that are neither phases nor(you)lines are open tasks: with no plan, the full view showsTASKS <N> open, no plan (/yah:phases after a plan is approved). - With several
## Plan:sections, yah follows the one with a phase in progress, else the first with an open phase. A finished plan can stay below the next one. - An open checkbox line that ends in
(you), after the title or after the fields, waits on you wherever it is in the file (code blocks aside):/yah:wherelists it asSTATE.md:<line>and the statusline counts it. Follow-ups go under## Follow-upsas checkbox lines, not prose. - The current phase's NEXT is the
- Next:line of the newest dated entry. An untracked STATE.md stamps it with a- At: <sha>line under it, which/yah:wrapwrites; a tracked one is stamped by its own last non-merge commit on the branch, so merging the base does not restamp it. Merge commits never count as work NEXT predates. If the phase base is gone (merged and deleted), commits on any other branch are left out instead. - In the plan file, a
### P<n>section may carry anAfter it merges:line and aFiles:block (+ path — notenew,~changed,-removed,> old -> newrenamed), which the phase map draws: in plan mode under## Map, in each phase PR's description (a<!-- yah:map -->section that/yah:wrapand a run keep up to date), in/yah:whereand in/yah:tree. Both are optional: without an after line the stack shows the phase's done-when, and without aFiles:block the planned tree comes from paths in bolded bullets. Once a phase has commits, its tree is its branch diff, with the plan's notes kept. - Dated entries without a plan section still show as STATE and NEXT.
- An
AIM: <sentence>line outside dated sections and code blocks is the project's aim (the first one wins);/yah:whereand the session-start block show it, andAIM: noneshows nothing./yah:wrapand/yah:phasesnever move or rewrite it. /yah:wrapkeeps only the 5 newest dated entries.
If you already use beads
yah never needs beads, and beads shows nothing STATE.md does not. A repo that already has .beads/ at its root can keep it: with bd found, /yah:phases writes the plan as one epic with one child bead per phase, and /yah:wrap keeps them true. They run bd by the full path where.py finds: on PATH, or where Homebrew, pipx and the Windows installer put it. yah runs bd only in a repo with .beads/, and a BEADS_DIR that points outside the repo turns it off until you unset it.
- A phase's NEXT is the first line of its notes, so a run pinned to that phase resumes from it.
/yah:whereshows the current phase's, or the next one's when none is running. - A bead labelled
humanwaits on you, and so does a(you)line in STATE.md. - With no plan epic, open beads count toward the same
TASKSrow, and in-progress beads show as DOING. - If STATE.md or NOW.md also has a plan, STATE.md wins, and
/yah:wherewarns:! beads epic <id> ignored: STATE.md has a plan.
Config
config.json in the data folder. Every key is optional.
{
"tier": "max5",
"amber": 120000, "wrap_soon": 150000, "wrap_now": 200000,
"pace_slack": 15,
"premium_models": ["fable", "mythos"],
"recent_days": 14,
"brain_dir": "docs/brain", "recall_max_chars": 10000,
"roles": {"critic": "opus high"}, "critic_week_skip_pct": 50,
"projects": {"shop": {"path": "/Users/me/code/shop", "prod": "main deploys on push. PRs only.", "trunks": ["main", "release"]}}
}
| Key | Meaning |
|---|---|
tier | pro, max5 (default), max20 or api. Sets the three context marks from the presets in the plan table, and the yah run budget. |
amber, wrap_soon, wrap_now | Override the preset. Context turns amber at amber, red with "wrap" at wrap_soon, and the guard nudges again at wrap_now. The guard re-arms below amber. |
pace_slack | How many points the weekly % may run ahead of pace before the once-a-day nudge, or before yah run stops. |
premium_models | Model ids or names that get a red tag in the statusline and a once-per-session nudge. |
auto_merge | Default false. Set by setup.py --auto-merge. Only a JSON true turns it on; then yah run merges a green phase PR it opened. See auto-merge. |
ultracode | Default false. Set by setup.py --ultracode; only a JSON true turns it on. Turns on the quality profile: the once-per-session workflow sizing rule, the pace nudge toward smaller workflows, and in yah run the --effort, critic and judge. |
roles | "model effort" per job: main, scout, mechanical, judge, critic, review_fallback and premium. Set only the roles you change; the rest keep their defaults (see the roles table). Effort is low, medium, high or xhigh; max or junk falls back to the role's default. |
critic_week_skip_pct | Default 50. With the profile on, when the critic's weekly bar (its model's own pool if Claude Code sends one, else the week) is at this % or more, yah run's critic and judge run on roles.judge instead. With a codex critic, only catch-up changes the model. |
catch_up_pct | Default 20. With the profile on, when the week is this many points or more under pace, yah run goes into catch-up: builds one effort step higher with 1.5 times the budget and, with a codex critic, each critique on roles.premium. With the profile on or off, interactive sessions get a once-a-day nudge to spend freely, and the statusline's wk turns green. Junk, or 0 or less, falls back to 20. |
roles.premium | Default fable high. The model catch-up spends and the workflow sizing rule keeps out of workflows. Codex does not change it. |
codex | Default false. Set by setup.py --codex once a signed-in codex CLI answers a smoke call; only a JSON true turns it on. Turns on /yah:gpt and makes GPT the default roles.critic. See Claude + GPT. |
codex_model | Default gpt-6.1-sol. The model every codex call passes with -m. |
codex_effort | Default high. Passed as -c model_reasoning_effort on every codex call, since Codex's own default for Sol is low. |
codex_timeout_minutes | Default 15. Wall clock per codex call; /yah:gpt passes 570 s, under the Bash tool's 10-minute cap. |
recent_days | How far back the home view looks for repos yah has seen. |
brain_dir | The brain folder, relative to the repo root. Default docs/brain. |
recall_max_chars | Cap on the recall block. Default 10,000 characters, about 2.5k tokens. |
run_* | The yah run caps. See Caps. |
projects | Optional. The home view lists these plus any repo yah saw in the last recent_days. No registration is needed. |
path | Where yah <project> goes. |
prod | The warning shown as the PROD line. yah run also denies pushes to the branches it names: each backticked word, and each other word that is a local or origin branch (origin/release and a sentence-case "Release" both name release), so prose like "Public repo" names none. Without it, where.py infers the branch open PRs land on, shows it as PROD when it is not an ordinary trunk, and /yah:wrap and yah run protect it. |
trunks | Long-lived branches, never treated as stacking targets. Defaults: main, master, develop, dev. |
FAQ
Common objections, one line each
- "Why not ccusage, claude-hud or ccstatusline?" They show your session; yah shows your project (phase, NEXT, PR) and drives wrap then
/clear. Run ccusage alongside; Claude Code has one statusline slot, so with another statusline yah's hooks and skills still work but the context guard has no numbers. - "Unattended auto mode is YOLO." It stops when a PR is open and green, has no merge step unless you opt in (then the driver merges, never a session), hard-blocks merges, trunk pushes and force pushes inside runs, stops after any denial, and assumes branch protection. Not for repos with untrusted commenters.
- "Bloat?" Measured +593 tokens per turn against a no-plugin session (skill listing, agent listing and the SessionStart block), plus about 380 if you append RULES.md. Per prompt, two local script runs of about 35–70 ms that add nothing unless a nudge fires; recall adds its block once. The brain and
yah runcost nothing until you use them. Separately, claude.ai connectors can change their tool descriptions between sessions, which rewrites the prompt cache whatever plugins you run. - "Auto-memory or
/compactalready does this." Memory holds your preferences; the brain holds repo facts, in the repo, reviewable in PRs, and loads only the few that match, once per session. - "$2,600 in a week is a you problem." Yes. The fix it argues for is free: write NEXT down,
/clear, one task per session.
Why not just /compact?
The official cost advice is /clear between tasks, because /compact is itself a large request. The author's costliest session auto-compacted 6 times and kept going. /yah:wrap writes what the next session needs (NEXT, the PR, the phase) into STATE.md, and the SessionStart hook injects it after /clear.
Why plain markdown for the brain, not a vector store or a memory server? The notes live in your repo, so they are reviewed in PRs, diffed and grepped, and they open in Obsidian. Recall is local keyword overlap plus changed-file globs, once per session, with no extra process. The trade-off is that it misses notes whose words never come up; INDEX.md is the full list.
Does it change my settings?
Only statusLine, after a timestamped backup, with the old value recorded. If you already have a statusline, setup shows it and replaces it only after your yes. It never touches model, effort, permissions, hooks or env, except the two ultracode keys when you pass --ultracode and yah's marketplace autoUpdate when you pass --auto-update. --uninstall puts the old values back. yah run passes --effort to its own sessions only with the quality profile on.
Why Python?
Stdlib only, so there is nothing to install beyond Python itself. macOS ships python3 3.9 with the Xcode Command Line Tools, so the code avoids 3.10+ syntax. The same files run on macOS, Linux and Windows, and you can read all of them in one sitting.
Does it work in the Desktop app or on the web? The statusline is a CLI feature. Hooks and skills load wherever plugins load, but that is untested.
Is Fable worth it?
The author's view: for one hard, self-contained question, yes, which is what /yah:deep is for. As the main model on a long session, the author's data says no: that one session was 95% of their Fable spend. The quality profile uses it the same way: one short read-only critique and one judge per phase in yah run, on Opus instead once Fable's bar reaches 50%. On Max plans Fable can use up to half of the weekly cap (it has its own usage bar). On Pro it needs extra-usage credits.
Will this help on Pro?
It cannot raise your limits. It shows your 5-hour and weekly use against pace, and the pro preset says wrap at 120k. The official advice matters most on Pro: Sonnet 5 for most work, lower effort and /clear between tasks. yah makes the last one a habit.
Uninstall
Undo setup first, while the script is still on disk. On Windows, use python instead of python3:
python3 "$HOME/.claude/plugins/marketplaces/you-are-here/scripts/setup.py" --uninstall
This restores your previous statusline (or removes yah's if there was none), and removes the launcher and RULES.md blocks (and a yah.cmd it wrote) if setup added them. Then remove the plugin and the marketplace:
/plugin uninstall yah@you-are-here
/plugin marketplace remove you-are-here
Uninstall leaves the data folder, including yah run logs (which can hold secrets a session read), and prints its path. Delete it if you want. On macOS and Linux:
rm -rf ~/.claude/you-are-here
On Windows (PowerShell):
Remove-Item -Recurse -Force "$HOME\.claude\you-are-here"
If you pasted RULES.md into a CLAUDE.md by hand, remove it by hand. Brain folders in your repos are yours, and uninstall leaves them. If you set $CLAUDE_CONFIG_DIR, use it in place of ~/.claude above.
Credits and license
The ideas came from comments on r/ClaudeAI and r/ClaudeCode:
- u/AncileBanish: "1 session = 1 task", write state down, start fresh.
- u/Schadz: one coordinator, narrow workers with model and effort pinned in agent files, short reports. "Parallelism doesn't save tokens."
- u/No-Needleworker5295: a handoff at each pass boundary, and a context guard around 250k.
- u/torvalds75: state in a queryable per-task record, and the current ticket in the statusline.
MIT. See LICENSE.