The unlazy skill and its Depth Tree method
How the unlazy skill stops an agent declaring done early: the Depth Tree, gates files, the PLAN.md contract, install steps, and what the depth costs you.
What the unlazy skill does
The unlazy skill is an agent skill built to stop one failure: a coding agent that reports the work as done before the work is done. Its core is the Depth Tree, a method that splits a task along its real boundaries and gives every leaf its own acceptance gates. Version 2 moved the enforcement out of prose and into files, so the agent has to prove completion against a list of runnable commands instead of asserting it.
It is published by Leonxlnx at github.com/Leonxlnx/unlazy under the MIT license. There is no tagged release to pin: as of 2026-10-11 the repo's tags and releases lists are both empty. This guide was first written against the 2.0.0 source milestone dated 2026-08-10. On 2026-10-11 we re-checked it against the current source on main. The CHANGELOG labels that source "Unreleased, target 2.1.0" and says it does not claim a Git tag or GitHub Release for 2.1.0. Running the install command today gets you that newer source, not 2.0.0. Skills in this area change quickly, so read the repo's CHANGELOG before you copy any of this into a setup you leave running.
A skill here means the usual thing: a SKILL.md file that the harness loads into the model's context when the task matches its description. If that mechanism is new to you, start with what an agent skill is and how a harness loads one. unlazy is plain markdown plus a few Node scripts, so it needs no server and no API key of its own.
Why agents stop at 80 percent and drop your third instruction
The behaviour has a shape you can recognise. You ask for four things. The reply covers the first, the second and the fourth. The closing summary lists all four as complete. Nothing threw an error, so nothing flagged it, and you find the gap a week later.
The unlazy README grounds this in published work on model laziness. It cites arXiv 2512.20662 for the finding that "Detailed multi-part prompts still see partial compliance and premature truncation in tested models". The gates reference states the design premise plainly: "The rules above are prose, and prose is the layer this project already treats as weakest." Telling an agent to try harder is more prose, added to the same context that produced the shortfall.
That is why version 2 keeps its state in files. A checkbox in GATES.md sits outside the model's discretion. Either the gate has evidence under it or it does not, and a script can tell you which without asking the agent.
The Depth Tree, layer by layer
The Depth Tree is decomposition with a rule about where the splits are allowed to fall. From the method reference:
Split only at real domain, component, or verification boundaries. Binary splits are optional.
Make layer 1 the requested task.
The leaves carry the deliverables. Every layer above them integrates and verifies what its children return.
A leaf is bigger than a bullet point. The reference sizes it by outcome, not by the clock:
Make each leaf one coherent deliverable.
Merge tiny adjacent leaves; split a leaf that hides several independent outcomes.
That rule is what keeps a deep tree from turning into busywork. If a leaf reads "rename the variable", it fails the test, and the split above it went one layer too far.
Each leaf then runs four passes: implement it completely with no placeholders, re-read it the way a domain expert would, hunt for defects, then apply polish where polishing is cheap, repeating until a full improvement pass finds nothing. The passes are the other reason tiny leaves get merged. Four passes over a two minute change is theatre.
You pick the depth when you invoke the skill:
/unlazy tree 5 refactor the payment modulePlain language works too, because the skill's description matches on intent rather than on a slash command:
tree 3 build the landing page and do not stop until every gate is checkedEarlier versions of this guide quoted depth bands with a leaf count for each depth. The current method reference has no leaf counts at all, and it says: "Do not treat depth as an arithmetic promise about effort or tokens." Only the qualitative guidance is left: "Use a shallow tree or solo ledger for a feature, contained bug hunt, or document." An orchestrated tree is for cases where several coherent deliverables benefit from fresh contexts or independent ownership. A deeper tree is justified only when its additional branches correspond to real integration boundaries.
When you name no depth, the reference says to "choose the smallest tree that exposes every independent deliverable and integration point". When you do name a number that does not fit the work, it tells the agent to say so rather than pad: "If the requested depth would create filler leaves, state the mismatch and use the closest honest decomposition." Depth describes the work, so inflating the number does not buy quality.
What a gates file looks like
Before any work starts, the agent writes acceptance criteria to a gates file. Each gate is a checkbox with a command under it.
# Gates: pricing section
- [ ] G1: three tiers render with real copy
CHECK: node check.js pricing --tiers
EXPECT: 3/3 tiers ok
EVIDENCE: pending
- [ ] G2: annual toggle changes both price and label
CHECK: node check.js pricing --toggle
EXPECT: toggle ok
EVIDENCE: pendingCHECK is the command. EXPECT is the output that counts as a pass, and a pass also requires the command to exit 0. EVIDENCE starts at pending. After a passing run, the checker fills it in with an output fingerprint rather than the raw output. A manual gate has no command, so for that one you record the smallest fact that proves the outcome. The skill ships scripts/gate-check.mjs to do this. With --status it reports which gates are still open without running a command or changing a file, so you can audit a run without reading the transcript. It only runs ledger commands when you pass --approve, so read every command and every script it calls before you pass it. A separate scripts/gate-lint.mjs checks the quality of a ledger without running anything.
The reporting rule in SKILL.md fits in one line:
Do not compose a done report while any required gate is unmet, abandoned, deferred, or awaiting an owner decision.
Alongside it, the agent is told to "re-measure every number and completion claim immediately before reporting." A gate cannot close because the agent feels finished. Closing it takes a run whose output either matches EXPECT or does not.
Write gates a stranger could run. "Looks good" is not a check. test -s dist/index.html && echo ok printing ok is a check, because it fails loudly on an empty or missing file.
The PLAN.md contract, before any parallel work
Once a tree is wide enough that leaves run in separate contexts, those leaves stop sharing assumptions. The method reference puts a contract in front of the fan-out: "Fix contracts before fan-out." The plan lists every required outcome in PLAN.md, "then record interfaces, formats, shared assumptions, error conventions, naming, and ownership before a leaf starts."
The reason is concrete. Two subagents each told to "add error handling" will invent two different error shapes, and both leaves pass their own gates, because each one is locally correct. The failure appears only where they meet. That meeting point is the job of the layer above them, and the orchestration reference spells it out: "Reverify the children, then run interface, end-to-end, and regression checks."
In orchestrated mode the driver is told to "Give each leaf only the shared contract, its exact ownership and dependencies, its own ledger" and to "not leak unrelated leaf histories." Each leaf ledger declares the paths it may write, and those OWNS paths must not overlap with any other leaf dispatched at the same time. When a subagent returns, the driver must "re-run the returned leaf's runnable gates, including already checked gates", because --status alone is not re-verification. A leaf whose boxes were ticked without real evidence does not survive that re-run.
Orchestration has a floor. The orchestration reference says to "Stay solo when one focused context can implement and verify the task without hiding independent deliverables." Each subagent has to rebuild its understanding of the task from scratch, so on a small task that setup costs more than the fresh attention buys.
How do you install the unlazy skill?
The supported path is the skills CLI:
npx skills add Leonxlnx/unlazyAdd -g for a user-level install or --all for every agent the CLI detects. That command installs whatever is on main today. There is no tagged release, so the README tells you to pin an exact commit if you need an install that will not change underneath you.
Manual install is a clone into your agent's skills directory:
git clone https://github.com/Leonxlnx/unlazy ~/.claude/skills/unlazygit clone https://github.com/Leonxlnx/unlazy ~/.codex/skills/unlazyThen check that it landed:
ls ~/.claude/skills/unlazy/SKILL.mdThe path printing back means the file is on disk. No such file or directory means the clone went somewhere else, usually because the skills directory did not exist under the name you assumed and git created a new one. Do not take the agent's word for it either. An agent that says the skill is installed has not shown you the file. The checker and the optional hook need Node 16 or newer, and they use no third-party runtime packages.
As of 2026-10-11 the README documents two harnesses: Claude Code, where you invoke the skill as /unlazy, and Codex CLI, where it is $unlazy. It documents no route for harnesses without a skill loader, so pasting SKILL.md into another tool's rules file is untested. If you want to know what makes a SKILL.md load reliably in the first place, writing your own agent skill covers the frontmatter and the description matching that decide whether it fires at all.
Does the Stop hook work outside Claude Code?
No, and this is the part to be precise about. Everything above is instructions, and instructions can be ignored. The one piece of structural enforcement is a Stop hook, and Stop hooks are a Claude Code feature.
node <path-to-skill>/scripts/install-hooks.mjs # this project only (settings.local.json)
node <path-to-skill>/scripts/install-hooks.mjs --global # every project
node <path-to-skill>/scripts/install-hooks.mjs --uninstallA Stop hook runs at the moment the agent tries to end its turn. This one scans the current session's ledger and dispatch state and blocks the stop while gates are unmet, so the turn cannot end on an unchecked box. It does not run the checks, and it makes no model calls of its own. It is not free, though. The token-economy reference notes that "A block causes another agent continuation, which does consume model work." For the general mechanism, and the other events you can attach to, see how Claude Code hooks fire around a turn. The README asks you to install the hook only with the user's consent. It also asks you to keep .claude/settings.local.json, .unlazy/ and .unlazy-hook-state.json in your ignore rules.
It has a release valve, which matters more than it sounds. If the agent makes no gate progress across six consecutive blocked stops, the hook releases it instead of trapping it, and edits that only touch metadata do not reset that count. An ABANDON: <gate> <reason> line also lets the session end, but as a visible handoff rather than a pass. The abandoned gate is reported as a non-successful result, not as finished work. Without those two escapes, a gate that is impossible in your environment would burn tokens until you killed the session yourself.
On Codex or any other harness, install-hooks.mjs has nothing to install into, because it only writes Claude settings files. You still get the gates file and the runnable checks, with nothing structural stopping the model from ending the turn early. There, the gates file is a document you have to read.
unlazy or ponytail: which one do you want?
These two skills trended in the same season and pull in opposite directions on volume, which makes them easy to confuse.
ponytail makes the agent behave like a senior developer whose first question is whether the code needs to exist at all. It cuts scope, prefers the standard library, and shrinks the diff. unlazy assumes the scope is already agreed and pushes effort up until every part of it is finished and proven.
So pick by the failure you are actually seeing. If your agent turns a small feature into a framework, you want the ponytail skill and its lazy senior developer persona. If your agent leaves the third item of a four-part request undone and then reports success, you want unlazy.
Running both is possible, and the order matters. Settle the scope with ponytail's question first, then hand the agreed scope to unlazy's gates. Do it the other way round and you build a tree of leaves for work that ponytail would have deleted, then pay for the extra effort on all of it. That ordering is my recommendation, not a documented integration between the two projects.
What does the depth cost on a VPS-hosted agent?
Effort is tokens, and on a VPS running an agent against your own API key, tokens are money. How much unlazy adds is a question the project now declines to answer with a number.
Earlier versions of this guide charted output-token and cost multipliers from the authors' six-run comparison. The authors have since withdrawn those figures. references/token-economy.md now says the raw prompts, traces, outputs and scoring records behind them are missing from the repository, "so those numbers are not reproducible here", and adds: "Do not use them as product guarantees." The method reference goes further: "Do not treat depth as an arithmetic promise about effort or tokens." We have removed the numbers rather than repeat figures their own authors no longer stand behind.
What the reference still says about cost is directional. Its opening advice is to "Move repeated, deterministic verification into commands and keep orchestration context narrow." Solo mode spends extra output tokens inside one context. Orchestrated mode adds contexts, and every new context reads the contract and its own ledger before it does anything useful. The reference warns in both directions: "Do not orchestrate a task that one focused session can implement and verify cleanly." It also warns against keeping an entire build in one context just to avoid subagent overhead when the leaves and contracts are clear.
Four settings follow from this:
- Pick the smallest depth whose leaves are real units of work, then stop. Depth you do not need is spend you do not need.
- Stay in solo mode when one focused session can build and verify the task, because subagent setup costs more there than the fresh context returns.
- Install the Stop hook if you are on Claude Code. The hook makes no model calls of its own, but each block sends the agent back to work, and that work is billed.
- Set a hard spend ceiling at the account level before you start anything long.
That last point is the honest one. A skill designed to refuse early stops is, by design, a skill that keeps working. Budgets and alerting are a separate job from prompting, and keeping an agent's cost under control on a VPS covers the caps worth having in place first.
What the authors measured, and what it proves
The repo used to publish its own test, which is rarer than it should be. It has since walked that test back, which is rarer still. The README now says only that "Earlier README versions also cited a six-run internal comparison" and that "The raw artifacts needed to reproduce those exact ratios and counts are not in this repository". Its advice: "Treat the results as historical design input, not a benchmark guarantee."
The setup survives in research/validation-protocol.md: two build tasks, three conditions each (no skill, tree 3, tree 6), and one fresh folder and session per run. The protocol calls it a "maintainer-run exploratory comparison". It says the token ratios, self-found defect counts, live failure and report-number errors it produced cannot be reproduced or audited from the repository. It also says the comparison must not be described as proof that unlazy causes a specific improvement or cost multiplier. Earlier versions of this guide charted the per-run counts from that test. With the authors' withdrawal, we have removed them.
One design lesson outlived the numbers. The rule to "re-measure every number and completion claim immediately before reporting" is still in SKILL.md, and the gates template warns against copying a supplied number into EXPECT as its own proof. A confident summary sitting on top of a broken build is exactly what the gates are aimed at.
Now the limits. As of 2026-10-11 there is no published result left to weigh, only the method and a protocol for a proper rerun. Test it on your own work instead: run the same task twice, once plain and once with a gates file, then count the gates that closed with evidence you can re-run yourself. That count is the only number in this area that belongs to you.
FAQ
What is the Depth Tree in the unlazy skill?
It is a decomposition method. A task splits only at real domain, component or verification boundaries, layer 1 is the requested task, and each leaf is one coherent deliverable with its own gates. Tiny adjacent leaves get merged, and a leaf that hides several independent outcomes gets split again. Every layer above the leaves integrates and verifies: it re-checks the children, then runs interface, end-to-end and regression checks. You choose the depth when you invoke it, for example tree 5. With no depth named, the skill picks the smallest tree that exposes every independent deliverable and integration point.
Does the unlazy skill work outside Claude Code?
Partly. The skill is plain markdown, and the README documents Codex CLI alongside Claude Code, so the Depth Tree, the gates file, the runnable checks and the four passes per leaf work there. The current docs do not cover other harnesses. The hard enforcement is different. The Stop hook that blocks the end of a turn while gates are unmet is a Claude Code feature, installed with node <path-to-skill>/scripts/install-hooks.mjs. Everywhere else nothing structurally prevents the model from ending its turn early, so you are the one who reads the gates file and sends it back.
How much does the unlazy skill add to my token bill?
Nobody can give you a reliable figure today. The authors' earlier token ratios came from six runs that cannot be reproduced. The current docs say not to use them as product guarantees, and not to treat depth as an arithmetic promise about effort or tokens. The direction is still clear. Solo mode adds output inside one context. Orchestrated mode adds a fresh context per leaf, which reads the contract and its ledger before working. The Stop hook makes no model calls of its own, but every block sends the agent back to work. Measure it on your own task against your own billing.
Should I use unlazy or ponytail?
Match the skill to the failure in front of you. ponytail is for an agent that writes too much, since it plays a senior developer who asks whether the code needs to exist and reaches for the standard library first. unlazy is for an agent that finishes too little of what you asked, since it forces decomposition and refuses to close a gate without evidence. If you want both, settle the scope with ponytail first, then hand that scope to unlazy, so you never pay an effort multiplier on work that should have been deleted.
Why does my agent still stop early after installing unlazy?
Check four things. First, confirm the skill is on disk with ls ~/.claude/skills/unlazy/SKILL.md, because a clone into a directory that did not exist is the common miss. Second, confirm a gates file was written before the work started, because the hook scans the session's ledger and an absent GATES.md gives it nothing to block on. Third, confirm where the hook was installed: the plain install-hooks.mjs run writes to this project's settings.local.json only, so another project needs --global. Fourth, remember the release valve is working as designed. Six consecutive blocked stops with no gate progress release the agent, and an ABANDON: <gate> <reason> line deliberately ends the attempt as a visible handoff that is not a success.