Routine-authoring guidelines + a skill-owned routine-structure check - #177
Merged
Conversation
Capture the routine-authoring guidelines that emerged from designing a daily coverage-improvement routine as a lean prose spec bracketed by pre/post scripts: - bracket the judgment step between a precondition gate (fail → skip) and a postcondition validator (fail → terminal, never retried), and size the gate to the cost asymmetry; - state in prose every expectation a hard check enforces, so a check backstops what the agent already holds instead of surprising it; - extract a step to a script only when it consolidates a whole deterministic decision — otherwise the split is indirection; - keep the job (feedback loop + judgment criteria) in the prose the agent reads, not buried in an executed-but-unread script, and audit a prose split clause-by-clause so no instruction is lost. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019iJfy6YPtnTvvRGPsUYvYY
Tighten the "Structuring a routine as prose + scripts" subsection and lead it with the concrete layout — a routine is a dev/routines/<name>/ folder whose standard entry point is routine.md, beside the preconditions.sh/postconditions.sh it invokes by path. Trim each of the four rules for brevity. Enforce the wiring with a new universal `routine-structure` check (inert until a routine.md exists): a routine.md invocation that resolves to no script is blocking; a script the entry point never invokes, a script with no shebang, and phase scripts in a folder with no routine.md entry point are flagged. Red-first fixture tests cover each; the full check suite stays green and the check is clean on a real routine. Refs #178 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019iJfy6YPtnTvvRGPsUYvYY
A skill defines an action, so the test-the-world check that validates that action's result belongs beside the SKILL.md, not in the universal pack. Add skill-owned check discovery — skills/registry.mjs picks up any skills/<name>/checks.mjs (default export = array of rules), run/list/stop-hook all include them, always-on and inert-until-applicable like universal checks — and relocate routine-structure (check + test + checks.mjs manifest) into skills/unattended-agents/, reverting its universal-pack registration. CI now runs skill-co-located tests (skills/*/*.test.mjs); a runner test proves a skill check is discovered, run, and listed through the CLI. Accept the check module's shared import of checks/lib the same way the packs/ acceptance does, and document skill-owned checks in checks/DESIGN.md. Refs #178 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019iJfy6YPtnTvvRGPsUYvYY
A skill check has no declaration gate: the engine runs it on every repo and every sweep, including ones where the skill's action never happened. So its run must detect relevance first — cheaply, specifically, returning [] when the artifact is absent — or it fires false findings on every unrelated repo the corpus is mounted in. Make this explicit where check authors and readers look: the "Adding a rule" guide (checks/README.md), the skill-owned-checks design note (checks/DESIGN.md), and routine-structure's own header (which models the gate: no routine.md ⇒ empty routineDirs ⇒ no-op). Refs #178 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019iJfy6YPtnTvvRGPsUYvYY
Audited every existing check against skill-ownership now that skills can carry checks. Verdict: none is a mis-placed skill check. routine-structure is the only one whose checked artifact exists solely because a skill's discrete action ran; squash-merge-history / claude-md-length / file-placement / generated-merge-driver name a skill in `doc` but inspect artifacts every repo has, and the gha/aws-sam/ cer checks are declaration-gated technology packs. Codify the discriminator so the misleading `doc`-points-at-a-skill signal can't cause future mis-placement: classify by what the artifact IS (universal / declared-technology / created-only- by-a-skill-action), not by which doc teaches the fix. Refs #178 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019iJfy6YPtnTvvRGPsUYvYY
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Three coupled changes:
skills/unattended-agents/SKILL.md— a tightened "Structuring a routine as prose + scripts" subsection, led by the folder/naming convention.routine-structurecheck — living inskills/unattended-agents/, with its test and manifest beside it.Closes #178
The convention + guidelines
A routine is a folder —
dev/routines/<routine-name>/— withroutine.mdas the standard entry point, beside thepreconditions.sh/postconditions.shit invokes by path. Four rules: bracket the agent's judgment between the two scripts asymmetrically (precondition fail → skip; postcondition fail → terminal, never retry); state inroutine.mdevery expectation a check enforces; extract a script only when it consolidates a whole deterministic decision; keep the job in the prose, not in a script's comments.Skill-owned checks (the placement fix)
A skill defines an action, so the test-the-world check validating that action's result belongs beside the SKILL.md, not in the universal pack. This adds that capability:
skills/registry.mjsdiscovers anyskills/<name>/checks.mjs(default export = array of rules) structurally, mirroringpacks/registry.mjs.checks/run.mjsloads and runs skill rules alongside pack rules, includes them in--list; the Stop hook inherits them (it shells out torun.mjs). Skill checks are never declared and always run (like universal), each inert until its artifact exists.skills/*/*.test.mjs); a runner test proves a skill check is discovered, run, and listed through the CLI.checks/DESIGN.md.routine-structurenow lives inskills/unattended-agents/(check +routine-structure.test.mjs+checks.mjs), reverting its earlier universal-pack registration.The check (
routine-structure)Inert until a
routine.mdexists. Assertions:bash …/x.shinvocation inroutine.mdresolving to no file;preconditions.sh/postconditions.shbut noroutine.mdentry point;Full suite 81/81 green, conformance sweep clean (the check module's shared
checks/libimport is accepted the same way thepacks/acceptance handles it), and the check runs clean against a real routine.Provenance
Distilled from a session that iteratively designed a daily fallback-coverage routine, each guideline corresponding to a wrong turn corrected. Deduped against the existing
unattended-agentsbullets; kept project-agnostic.🤖 Generated with Claude Code
https://claude.ai/code/session_019iJfy6YPtnTvvRGPsUYvYY