Anti-laziness skill for AI agents. Core: the Depth Tree method, which splits a task N layers deep and gives every leaf the full time budget of the whole task, so effort multiplies with depth. Grounded in 2025-2026 research on model laziness, underthinking and premature completion.
3,224
stars
46
commits
JavaScript
primary language
Sep 3, 2026
updated
Completion discipline for substantial AI-agent work, backed by runnable gates.
Write the acceptance ledger first. Execute reviewed checks. Reverify returned work. Report only what the evidence supports.
Quick start | Gate contract | Orchestration | Security | Research
The current source targets 2.1.0. It is not identified here as a tagged GitHub release. Pin an exact commit when you need an immutable installation. See CHANGELOG.md for the unreleased change set.
Use the skills CLI for supported agents:
npx skills add Leonxlnx/unlazy
Add -g for a user-level install or --all for every detected agent.
Manual locations:
Claude Code: ~/.claude/skills/unlazy
Codex CLI: ~/.codex/skills/unlazy
Clone the repository into the relevant directory. Invoke it as /unlazy where slash skills are supported, $unlazy in Codex, or by a natural-language trigger from the skill description.
The core is SKILL.md. The checker and optional hook require Node 16 or newer and use no third-party runtime packages.
Ask for substantial work with an explicit trigger:
/unlazy tree 5 refactor the payment module and verify every migration path
For a solo task, copy templates/gates-leaf.md to GATES.md, replace every placeholder, and inspect it without executing commands:
node <path-to-skill>/scripts/gate-check.mjs --status GATES.md
--status is the only mode that is always non-executing. On a new oracle with no exact approval record, a normal run prints its resolved command, expectation, working directory, shell, and PATH without executing it:
node <path-to-skill>/scripts/gate-check.mjs GATES.md
Do not treat normal mode as a permanent dry run: once the exact oracle is approved, normal mode can execute it.
CHECK: lines are shell code. After reading every command and called script, approve and run the ledger:
node <path-to-skill>/scripts/gate-check.mjs --approve GATES.md
Re-run all runnable gates, including gates already marked complete:
node <path-to-skill>/scripts/gate-check.mjs --reverify GATES.md
Use --help for the complete current CLI.
# Gates: pricing behavior
- [ ] G1: pricing fixtures render the expected tiers
CHECK: node scripts/verify-pricing.mjs
EXPECT: pricing verification passed
EVIDENCE: pending
- [ ] G2: checkout integration succeeds from its package
CHECK: node scripts/verify-checkout.mjs
EXPECT: checkout verification passed
CWD: packages/checkout
EVIDENCE: pending
A runnable gate passes only when its process exits 0 and EXPECT: matches combined output. Evidence records the resolved shell, resolved working directory, exit status, a short PATH fingerprint, the match result, and a SHA-256/byte-count fingerprint of successful output. Raw successful output is neither echoed nor persisted. The pre-execution transcript shows the resolved PATH, capped for display. Old evidence is not re-execution; parent verification uses --reverify.
The parser rejects zero-gate ledgers, duplicate ids, incomplete runnable gates, invalid expectations, and abandonment with a missing reason or unknown gate id. It ignores fenced examples, preserves CRLF or LF when updating, and inserts a missing evidence line when needed. A valid abandonment is terminal handoff rather than success: the checker exits 1 with HANDOFF REQUIRED, and Stop allows exit while reporting qualified ids.
The checker can prove only the command oracle you declare. It cannot infer that an English title and arbitrary shell code mean the same thing. Good gates therefore:
EXPECT:Use the advisory, non-executing scripts/gate-lint.mjs to catch mechanically weak ledger patterns; add --strict when warnings should fail. Full specification: references/gates.md.
The checker uses --shell first, then UNLAZY_SHELL, then Node's platform default shell. That default is /bin/sh on Unix and process.env.ComSpec on Windows with the platform fallback. Checks inherit the launch environment, including PATH.
This matters on Windows: a checker launched from Git Bash can see Unix-like tools that the same checker launched from PowerShell does not. --shell changes the interpreter; it does not install grep, tail, tr, or other external programs. Portable examples call repository-owned Node scripts.
Parent re-verification should use the same declared shell and required toolchain. A shell or PATH mismatch is a failed verification to resolve, not successful evidence.
Approval records live under ~/.unlazy/approved by default. UNLAZY_APPROVAL_DIR may select another owner-private real directory, but its canonical target must remain outside the checked repository. Symlinked stores and linked, replaced, or non-private records fail closed. Each record is specific to the absolute ledger and gate, exact CHECK: and EXPECT:, resolved CWD: and shell, timeout, output and regex limits, regex worker limits, platform, and full inherited PATH. Editing any bound input requires approval again.
Approval is consent, not a sandbox. Approval storage is a canonical, owner-private directory outside the repository; records are accepted only as single-link private regular files. Approval does not hash called scripts, fixtures, dependencies, or other transitive inputs, and --status/Stop do not revalidate old evidence. Reinspect changed dependencies and run --reverify; see SECURITY.md for the bounded digest pattern when user-designed dependency identity is needed. Checks run with ambient filesystem, environment, credential, and network access. Scopes and ownership leases coordinate cooperating processes but do not restrict what a process can read or write.
For work that needs fresh contexts, create one scoped pipeline under .unlazy/<scope>/:
.unlazy/<scope>/PLAN.md
.unlazy/<scope>/GATES.md
.unlazy/<scope>/gates/leaf-*.md
.unlazy/<scope>/gates/node-*.md
The driver rereads the current request and maintains a revisioned contract inventory that maps each independently required outcome or acceptance-changing constraint to an owner and observation. It fixes interfaces, dependencies, conventions, and file ownership before dispatch. Leaves use declared WAITING, READY, IN-FLIGHT, VERIFIED, or ABANDONED states. Branches use OPEN, VERIFIED, or ABANDONED.
Ready leaves may run together only after each declares complete, disjoint, repository-relative OWNS: paths and claims them:
node <path-to-skill>/scripts/gate-check.mjs --scope api --leaf leaf-1.2.1 --claim
Lease matching is conservative and may reject a safe-looking pair. It is a coordination guard, not write isolation. Use separate worktrees for colliding worktree-local output, and configure separate cache locations when cache writes can conflict.
Dispatch is rolling: when a verified leaf unblocks another, start the newly ready leaf without waiting for unrelated work. Gate checks remain sequential by default. --jobs <N>, where N is an integer from 1 through 64, is an opt-in rolling limit for independent checks and keeps reporting in ledger order.
For every independent READY set, open a native launch wave, record each host agent handle, and seal before the first wait. If a partial launch cannot recover, use the audited abandon --reason transition; never invent a handle or delete state. Read references/method.md, references/orchestration.md, references/dispatch.md, and references/parallel.md before parallel fan-out.
gate-check.mjs --scope <id> reduces the scope's ledgers and dispatch waves together. It prints ALL MET only when every gate is met and every wave is complete; an abandoned wave remains a non-successful HANDOFF REQUIRED outcome.
The hook scans the current session's resolved ledger and dispatch state and returns Claude Code's documented top-level decision: "block" response while gates remain unmet or launch waves remain incomplete. It does not execute checks. Its own session-keyed progress guard releases after six consecutive blocks without semantic gate/dispatch progress; metadata-only edits do not reset it. Abandonment stays visible as an explicit bounded handoff in pure, mixed-blocking, and final-release messages, without echoing free-form reasons.
Install only with the user's consent:
node <path-to-skill>/scripts/install-hooks.mjs
node <path-to-skill>/scripts/install-hooks.mjs --scope api
node <path-to-skill>/scripts/install-hooks.mjs --uninstall
Default installation writes .claude/settings.local.json. Keep that file, .unlazy/, and .unlazy-hook-state.json in the project's ignore rules. --shared writes absolute Node and hook-script paths into project settings, so it is usually not portable and can expose local directory names. --global writes the current user's Claude settings.
The installer preserves unrelated hooks, refuses malformed settings shapes, and identifies moved unlazy entries without depending on the install directory name. It writes settings atomically and creates <settings-file>.unlazy.bak beside an existing settings file before replacing it.
The unreleased 2.1.0 source integrates the useful parts of community PRs while repairing their edge cases:
--reverify, explicit --approve, and fail-closed exit-plus-EXPECT success--shell and UNLAZY_SHELL, with pre-execution PATH disclosure and resolved shell, CWD, exit, match, and successful-output fingerprint evidence--jobs, sequential by defaultContributor history and pull-request links are recorded in CHANGELOG.md.
SKILL.md core instructions and mode routing
SECURITY.md CHECK, shell, approval, hook, and lease threat model
agents/openai.yaml skill UI metadata
references/gates.md strict format, approval, shell, and authoring rules
references/method.md Depth Tree decomposition method
references/orchestration.md states, rolling dispatch, and verification hierarchy
references/dispatch.md native launch waves, host adapters, and recovery
references/parallel.md scope and lease coordination limits
references/token-economy.md attention and verification cost discipline
research/validation-protocol.md historical limitations and rerun protocol
templates/ plan, leaf, and branch ledger templates
scripts/ checker, linter, dispatch recorder, installer, and Stop hook
tests/ deterministic behavior and regression tests
Run the repository's complete test command:
npm test
Research supports the failure modes that motivate explicit structure; it does not prove that unlazy produces a fixed improvement.
14.8% of checkpoints. Checkpoint success is not task completion (SlopCodeBench).Wait multiple times when the model tries to stop; it is not a claim that one token always improves work (s1).196.5 day overall P50 doubling-time fit and 130.8 days for the post-2023 fit. The shorter figure must not be described as the all-years estimate (METR Time Horizon 1.1).Earlier README versions also cited a six-run internal comparison. The raw artifacts needed to reproduce those exact ratios and counts are not in this repository. Treat the results as historical design input, not a benchmark guarantee. The limitations and a protocol for a defensible rerun are in research/validation-protocol.md.
Ordered by the most recent public version or publication date known on 2026-08-23. Undated material appears last.
Issues and pull requests are welcome. Read CONTRIBUTING.md and SECURITY.md. Behavioral claims need current, directly supporting sources; executable changes need regression coverage.
JavaScript
100.0%
Anti-laziness skill for AI agents. Core: the Depth Tree method, which splits a task N layers deep and gives every leaf the full time budget of the whole task, so effort multiplies with depth. Grounded in 2025-2026 research on model laziness, underthinking and premature completion.
3,224
stars
46
commits
JavaScript
primary language
Sep 3, 2026
updated
Completion discipline for substantial AI-agent work, backed by runnable gates.
Write the acceptance ledger first. Execute reviewed checks. Reverify returned work. Report only what the evidence supports.
Quick start | Gate contract | Orchestration | Security | Research
The current source targets 2.1.0. It is not identified here as a tagged GitHub release. Pin an exact commit when you need an immutable installation. See CHANGELOG.md for the unreleased change set.
Use the skills CLI for supported agents:
npx skills add Leonxlnx/unlazy
Add -g for a user-level install or --all for every detected agent.
Manual locations:
Claude Code: ~/.claude/skills/unlazy
Codex CLI: ~/.codex/skills/unlazy
Clone the repository into the relevant directory. Invoke it as /unlazy where slash skills are supported, $unlazy in Codex, or by a natural-language trigger from the skill description.
The core is SKILL.md. The checker and optional hook require Node 16 or newer and use no third-party runtime packages.
Ask for substantial work with an explicit trigger:
/unlazy tree 5 refactor the payment module and verify every migration path
For a solo task, copy templates/gates-leaf.md to GATES.md, replace every placeholder, and inspect it without executing commands:
node <path-to-skill>/scripts/gate-check.mjs --status GATES.md
--status is the only mode that is always non-executing. On a new oracle with no exact approval record, a normal run prints its resolved command, expectation, working directory, shell, and PATH without executing it:
node <path-to-skill>/scripts/gate-check.mjs GATES.md
Do not treat normal mode as a permanent dry run: once the exact oracle is approved, normal mode can execute it.
CHECK: lines are shell code. After reading every command and called script, approve and run the ledger:
node <path-to-skill>/scripts/gate-check.mjs --approve GATES.md
Re-run all runnable gates, including gates already marked complete:
node <path-to-skill>/scripts/gate-check.mjs --reverify GATES.md
Use --help for the complete current CLI.
# Gates: pricing behavior
- [ ] G1: pricing fixtures render the expected tiers
CHECK: node scripts/verify-pricing.mjs
EXPECT: pricing verification passed
EVIDENCE: pending
- [ ] G2: checkout integration succeeds from its package
CHECK: node scripts/verify-checkout.mjs
EXPECT: checkout verification passed
CWD: packages/checkout
EVIDENCE: pending
A runnable gate passes only when its process exits 0 and EXPECT: matches combined output. Evidence records the resolved shell, resolved working directory, exit status, a short PATH fingerprint, the match result, and a SHA-256/byte-count fingerprint of successful output. Raw successful output is neither echoed nor persisted. The pre-execution transcript shows the resolved PATH, capped for display. Old evidence is not re-execution; parent verification uses --reverify.
The parser rejects zero-gate ledgers, duplicate ids, incomplete runnable gates, invalid expectations, and abandonment with a missing reason or unknown gate id. It ignores fenced examples, preserves CRLF or LF when updating, and inserts a missing evidence line when needed. A valid abandonment is terminal handoff rather than success: the checker exits 1 with HANDOFF REQUIRED, and Stop allows exit while reporting qualified ids.
The checker can prove only the command oracle you declare. It cannot infer that an English title and arbitrary shell code mean the same thing. Good gates therefore:
EXPECT:Use the advisory, non-executing scripts/gate-lint.mjs to catch mechanically weak ledger patterns; add --strict when warnings should fail. Full specification: references/gates.md.
The checker uses --shell first, then UNLAZY_SHELL, then Node's platform default shell. That default is /bin/sh on Unix and process.env.ComSpec on Windows with the platform fallback. Checks inherit the launch environment, including PATH.
This matters on Windows: a checker launched from Git Bash can see Unix-like tools that the same checker launched from PowerShell does not. --shell changes the interpreter; it does not install grep, tail, tr, or other external programs. Portable examples call repository-owned Node scripts.
Parent re-verification should use the same declared shell and required toolchain. A shell or PATH mismatch is a failed verification to resolve, not successful evidence.
Approval records live under ~/.unlazy/approved by default. UNLAZY_APPROVAL_DIR may select another owner-private real directory, but its canonical target must remain outside the checked repository. Symlinked stores and linked, replaced, or non-private records fail closed. Each record is specific to the absolute ledger and gate, exact CHECK: and EXPECT:, resolved CWD: and shell, timeout, output and regex limits, regex worker limits, platform, and full inherited PATH. Editing any bound input requires approval again.
Approval is consent, not a sandbox. Approval storage is a canonical, owner-private directory outside the repository; records are accepted only as single-link private regular files. Approval does not hash called scripts, fixtures, dependencies, or other transitive inputs, and --status/Stop do not revalidate old evidence. Reinspect changed dependencies and run --reverify; see SECURITY.md for the bounded digest pattern when user-designed dependency identity is needed. Checks run with ambient filesystem, environment, credential, and network access. Scopes and ownership leases coordinate cooperating processes but do not restrict what a process can read or write.
For work that needs fresh contexts, create one scoped pipeline under .unlazy/<scope>/:
.unlazy/<scope>/PLAN.md
.unlazy/<scope>/GATES.md
.unlazy/<scope>/gates/leaf-*.md
.unlazy/<scope>/gates/node-*.md
The driver rereads the current request and maintains a revisioned contract inventory that maps each independently required outcome or acceptance-changing constraint to an owner and observation. It fixes interfaces, dependencies, conventions, and file ownership before dispatch. Leaves use declared WAITING, READY, IN-FLIGHT, VERIFIED, or ABANDONED states. Branches use OPEN, VERIFIED, or ABANDONED.
Ready leaves may run together only after each declares complete, disjoint, repository-relative OWNS: paths and claims them:
node <path-to-skill>/scripts/gate-check.mjs --scope api --leaf leaf-1.2.1 --claim
Lease matching is conservative and may reject a safe-looking pair. It is a coordination guard, not write isolation. Use separate worktrees for colliding worktree-local output, and configure separate cache locations when cache writes can conflict.
Dispatch is rolling: when a verified leaf unblocks another, start the newly ready leaf without waiting for unrelated work. Gate checks remain sequential by default. --jobs <N>, where N is an integer from 1 through 64, is an opt-in rolling limit for independent checks and keeps reporting in ledger order.
For every independent READY set, open a native launch wave, record each host agent handle, and seal before the first wait. If a partial launch cannot recover, use the audited abandon --reason transition; never invent a handle or delete state. Read references/method.md, references/orchestration.md, references/dispatch.md, and references/parallel.md before parallel fan-out.
gate-check.mjs --scope <id> reduces the scope's ledgers and dispatch waves together. It prints ALL MET only when every gate is met and every wave is complete; an abandoned wave remains a non-successful HANDOFF REQUIRED outcome.
The hook scans the current session's resolved ledger and dispatch state and returns Claude Code's documented top-level decision: "block" response while gates remain unmet or launch waves remain incomplete. It does not execute checks. Its own session-keyed progress guard releases after six consecutive blocks without semantic gate/dispatch progress; metadata-only edits do not reset it. Abandonment stays visible as an explicit bounded handoff in pure, mixed-blocking, and final-release messages, without echoing free-form reasons.
Install only with the user's consent:
node <path-to-skill>/scripts/install-hooks.mjs
node <path-to-skill>/scripts/install-hooks.mjs --scope api
node <path-to-skill>/scripts/install-hooks.mjs --uninstall
Default installation writes .claude/settings.local.json. Keep that file, .unlazy/, and .unlazy-hook-state.json in the project's ignore rules. --shared writes absolute Node and hook-script paths into project settings, so it is usually not portable and can expose local directory names. --global writes the current user's Claude settings.
The installer preserves unrelated hooks, refuses malformed settings shapes, and identifies moved unlazy entries without depending on the install directory name. It writes settings atomically and creates <settings-file>.unlazy.bak beside an existing settings file before replacing it.
The unreleased 2.1.0 source integrates the useful parts of community PRs while repairing their edge cases:
--reverify, explicit --approve, and fail-closed exit-plus-EXPECT success--shell and UNLAZY_SHELL, with pre-execution PATH disclosure and resolved shell, CWD, exit, match, and successful-output fingerprint evidence--jobs, sequential by defaultContributor history and pull-request links are recorded in CHANGELOG.md.
SKILL.md core instructions and mode routing
SECURITY.md CHECK, shell, approval, hook, and lease threat model
agents/openai.yaml skill UI metadata
references/gates.md strict format, approval, shell, and authoring rules
references/method.md Depth Tree decomposition method
references/orchestration.md states, rolling dispatch, and verification hierarchy
references/dispatch.md native launch waves, host adapters, and recovery
references/parallel.md scope and lease coordination limits
references/token-economy.md attention and verification cost discipline
research/validation-protocol.md historical limitations and rerun protocol
templates/ plan, leaf, and branch ledger templates
scripts/ checker, linter, dispatch recorder, installer, and Stop hook
tests/ deterministic behavior and regression tests
Run the repository's complete test command:
npm test
Research supports the failure modes that motivate explicit structure; it does not prove that unlazy produces a fixed improvement.
14.8% of checkpoints. Checkpoint success is not task completion (SlopCodeBench).Wait multiple times when the model tries to stop; it is not a claim that one token always improves work (s1).196.5 day overall P50 doubling-time fit and 130.8 days for the post-2023 fit. The shorter figure must not be described as the all-years estimate (METR Time Horizon 1.1).Earlier README versions also cited a six-run internal comparison. The raw artifacts needed to reproduce those exact ratios and counts are not in this repository. Treat the results as historical design input, not a benchmark guarantee. The limitations and a protocol for a defensible rerun are in research/validation-protocol.md.
Ordered by the most recent public version or publication date known on 2026-08-23. Undated material appears last.
Issues and pull requests are welcome. Read CONTRIBUTING.md and SECURITY.md. Behavioral claims need current, directly supporting sources; executable changes need regression coverage.
JavaScript
100.0%