SSD Nodes Learn Hosting plans →
Guides Matt ConnorBy Matt Connor

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 into layers and treats only the bottom layer as real work. 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. This guide is written against version 2.0.0, released 2026-08-10. 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, quoting "premature truncation of responses and partial compliance with multi-part requests" (its citation is arXiv 2512.20662). The same README states the design premise plainly: prose cannot enforce prose. 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 box has an evidence line 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 work is allowed to happen. From the method reference:

Split at natural joints, binary where natural joints allow, N layers deep.
Leaves are the only places real work happens; every layer above them is decomposition and integration.

A leaf is bigger than a bullet point. The reference sets a size floor:

A leaf is a real unit of work. Ten or more minutes of focused effort, one coherent deliverable, one gates file.

That floor 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 polish where polishing is free. The passes are the other reason a leaf needs a size floor. Four passes over a two minute change is theatre.

You pick the depth when you invoke the skill:

/unlazy tree 5 refactor the payment module

Plain 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 checked

The reference gives depth bands. tree 2 or 3 is a feature, a bug hunt or a document, worked solo in one session across 2 to 4 leaves. tree 4 or 5 is a subsystem, a refactor or a serious review, where 8 to 16 leaves is "past what one context holds well". tree 6 or 7 is an entire project, run in orchestrated mode with leaves mapped onto disjoint work units.

When you name no depth, the skill is told to "pick the smallest N whose leaves match the task's natural parts", and told explicitly not to go one deeper by default. 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: pending

CHECK is the command. EXPECT is the output that counts as a pass. EVIDENCE starts at pending and has to be replaced with what the command actually printed. The skill ships scripts/gate-check.mjs to scan those files and report which gates are still open, which means you can audit a run without reading the transcript.

The philosophy fits in one line, and SKILL.md writes it as one line:

A report is a set of claims backed by a ledger, never a vibe of completion.

The rule that follows is "no report until the ledger is full", together with a reporting rule that every number in a final summary is re-measured at report time or labelled unverified. A gate cannot close because the agent feels finished, because closing it means pasting output that 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:

Contracts before fan-out. Interfaces, data ownership, naming, error conventions go into PLAN.md before any 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. Branch gates exist for that moment: a branch's gates prove "children merged, interfaces match, end-to-end behavior works, no sibling regressions".

In orchestrated mode the driver hands each subagent the contract section of PLAN.md, not the whole file and not the driver's own history, plus that leaf's gates file verbatim. When the subagent returns, the driver re-runs the checks itself. A subagent that "checked its own boxes without evidence" is sent back with the specific unmet gates named.

Orchestration has a floor. Below roughly half an hour of real work the reference says to stay solo, because each subagent has to rebuild its understanding of the task from scratch, and 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/unlazy

Manual install is a clone into your agent's skills directory:

git clone https://github.com/Leonxlnx/unlazy ~/.claude/skills/unlazy
git clone https://github.com/Leonxlnx/unlazy ~/.codex/skills/unlazy

Then check that it landed:

ls ~/.claude/skills/unlazy/SKILL.md

The 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. The README's own install prompt ends with the same warning: "Do not tell me it is installed unless you have actually verified the file is on disk."

For a harness with no skill loader, paste the contents of SKILL.md into the system prompt or the rules file. That is the documented fallback, and it is why the method runs on Claude Code, Codex, Cursor and anything else that reads a plain markdown instruction file. 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 --uninstall

A Stop hook runs at the moment the agent tries to end its turn. This one scans the gates files and blocks the stop while gates are unmet, so the turn cannot end on an unchecked box. It reads files and makes no model calls, which is why the README says it costs zero tokens. For the general mechanism, and the other events you can attach to, see how Claude Code hooks fire around a turn.

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 lets it go with a warning instead of trapping it. An ABANDON: <gate> <reason> line is always honoured as an honest exit. Without those two escapes, a gate that is impossible in your environment would burn tokens until you killed the session yourself.

On Codex, Cursor or any other harness, install-hooks.mjs has nothing to install into. 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 the depth multiplier 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?

Depth is an effort multiplier, and effort is tokens. On a VPS running an agent against your own API key, that multiplier is money.

ChartEffort and cost multipliers reported by the unlazy authors, August 2026
The data behind this chart
[
  {
    "label": "Skill run vs no skill, output tokens",
    "low_multiplier": 1.6,
    "high_multiplier": 3.9
  },
  {
    "label": "tree 6 vs tree 3, total cost",
    "low_multiplier": 1.0,
    "high_multiplier": 1.5
  }
]

Those are the authors' figures from their own test, dated 2026-08-10. We have not reproduced them, so read them as a shape rather than a forecast. Solo discipline raised output to roughly 1.6 to 3.9 times the baseline, while moving from tree 3 to tree 6 inside one context added only 1.0 to 1.5 times, far short of the eight times you would expect from three more binary splits.

Deeper is not proportionally dearer because depth redistributes effort rather than adding contexts. The token-economy reference is blunt about where the real multiplier lives: "What multiplies cost is orchestration, and it should multiply it, because each leaf buys a fresh context." Solo mode multiplies output tokens inside one context. Orchestrated mode multiplies contexts, and every new context re-reads the contract and its gates file before it does anything useful.

There is a second cost that is easy to miss, and the same reference names it. One monolithic deep run in their test "consumed roughly 58 million cached input tokens" because a single ever-growing context carried everything. Cached input is cheaper per token, and at that volume it still lands on the invoice.

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 under half an hour of work, because subagent setup costs more there than the fresh context returns.
  • Install the Stop hook if you are on Claude Code. It is the one part of this that runs for free.
  • 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 publishes its own test, which is rarer than it should be. Their setup, quoted from the README: "two build-from-scratch tasks (a marketing site and a three.js solar system), three conditions each (no skill, tree 3, tree 6), one fresh folder and fresh session per run, same model, same prompt body. Every output was code-reviewed by independent agents, adversarially re-verified, and live-tested in a browser."

ChartPer-run counts claimed in the unlazy README, August 2026
The data behind this chart
[
  {
    "label": "Self-found defects fixed, skill runs",
    "low_count": 4,
    "high_count": 10
  },
  {
    "label": "Wrong numbers in report, skill runs",
    "low_count": 1,
    "high_count": 3
  },
  {
    "label": "Wrong numbers in report, baseline runs",
    "low_count": 0,
    "high_count": 0
  }
]

Read the middle row twice. In the authors' own test the skill runs fixed 4 to 10 defects the agent found by itself before delivery, and every skill run then shipped a final report holding 1 to 3 wrong numbers, against 0 in the baseline runs. More work produced better builds and worse summaries. That is the finding behind the ledger rule, and behind the instruction to re-measure every number at report time or mark it unverified.

One more of their results is worth keeping: "The only hard live failure was a baseline build, and its report claimed the case was handled." A confident summary sitting on top of a broken build is exactly what the gates are aimed at.

Now the limits. Six runs, two build tasks, one model, run and reported by the skill's own author. Nothing here is independent replication, and we are quoting it as the authors' claims as of 2026-08-10. 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 at natural joints across N layers, and only the leaves at the bottom count as work. The skill defines a leaf as ten or more minutes of focused effort with one coherent deliverable and one gates file, so a leaf you could finish in two minutes means the split went one layer too deep. Every layer above the leaves is decomposition and integration, and each branch carries its own gates that prove the children merged and the interfaces match. You choose the depth when you invoke it, for example tree 5, and the documented default is the smallest depth whose leaves are real units of work.

Does the unlazy skill work outside Claude Code?

Partly. The skill is plain markdown, so Codex, Cursor and anything that reads a SKILL.md or a system prompt can use the Depth Tree, the gates file, the runnable checks and the four passes per leaf. 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?

The authors report 1.6 to 3.9 times the output tokens of a no-skill run in solo mode, on top of a few hundred tokens of overhead for the gates file itself. Going deeper inside one context is close to free by comparison, about 1.0 to 1.5 times when moving from tree 3 to tree 6. Orchestrated mode is the expensive one, because every leaf buys a fresh context that re-reads the contract and its gates before working. The Stop hook adds nothing, since it only scans files. Those are the authors' figures as of 2026-08-10, not measurements we repeated.

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 gates files 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, since six consecutive blocked stops with no gate progress let the agent go with a warning, and an ABANDON: <gate> <reason> line ends the attempt on purpose.