Align
Agent skills that drive the Hydrant ticket lifecycle from your AI harness. Stack-agnostic, MCP-pure, MIT-licensed.
npx -y skills add Background-Craft/hydrant-skills --skill alignAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Scan the user's codebase, ask up to five clarifying questions, and write a fenced Alignment block into AGENTS.md that the Hydrant lifecycle skills (`/go`, `/prep`, `/preflight`, `/yeet`) read for stack-specific behavior. Use when the user asks for `/align`, says "align hydrant-skills", wants the lifecycle skills tuned to this codebase's conventions, or runs the install for the first time.
SKILL.md
12.5 KB, ~3.1k tokens by cl100k_base, as published. Nobody here has run it
Align
/align is a one-time (re-runnable) tune. It records the conventions of this codebase — branch strategy, single-file test command, PR flow, merge policy, branch naming, package manager, lint/typecheck commands — into a fenced Alignment block in AGENTS.md. Lifecycle skills read that block to adapt their behavior. Without it they fall back to safe defaults.
What this skill produces
A single fenced block in AGENTS.md:
<!-- BEGIN: hydrant alignment -->
## Hydrant alignment
<!-- Generated by /align. Re-run /align to update. Manual edits inside this fence are preserved on re-run only when /align prompts before overwriting. -->
- package-manager: pnpm
- single-file-test-cmd: pnpm test {file}
- lint-cmd: pnpm lint
- typecheck-cmd: pnpm tsc --noEmit
- branch-strategy: feature-branches
- branch-naming: hyd-{number}-{slug}
- pr-flow: same-repo
- merge-policy: review-required
<!-- END: hydrant alignment -->
Stable keys (do not invent new ones without coordinating with the lifecycle skills):
package-manager—npm|pnpm|yarn|bun|pip|uv|poetry|cargo|go|nonesingle-file-test-cmd— runner-specific command with the literal token{file}where the path is substituted (e.g.pnpm test {file},pytest {file},cargo test --test {file})lint-cmd— full command, no substitution (e.g.pnpm lint,ruff check)typecheck-cmd— full command, no substitution (e.g.pnpm tsc --noEmit,mypy .); usenoneif the language isn't statically typedbranch-strategy—trunk-based|feature-branches|gitflowbranch-naming— pattern with{number}and{slug}placeholders (e.g.hyd-{number}-{slug},feat/{slug}); usenoneif there's no conventionpr-flow—same-repo|fork-and-prmerge-policy—review-required|self-merge
Lifecycle skills look up by key. If a key is missing, the consumer falls back to its own default and prints a one-line nudge to re-run /align.
Workflow
Run these phases in order. Skip later phases only when justified by what an earlier phase found.
Phase 1: Detect
Walk the repo root with whatever filesystem tools the harness exposes. Do not run network calls. Do not modify any file in this phase.
Read each of these if it exists, in this order. Stop reading a category as soon as you have a confident signal — don't keep digging.
- Stack and package manager
package.json→ Node project. CheckpackageManagerfield,engines, then look forpnpm-lock.yaml/yarn.lock/bun.lockb/package-lock.jsonto disambiguate.pyproject.toml→ Python. Check[tool.poetry]vs[tool.uv]vs[tool.pdm]; check foruv.lock/poetry.lock.Cargo.toml→ Rust + cargo.go.mod→ Go.Gemfile→ Ruby + bundler.composer.json→ PHP.pubspec.yaml→ Dart. Be willing to recordpackage-manager: noneif nothing matches.
- Test, lint, typecheck commands
- From
package.jsonscripts: atestscript implies the runner; look forlint,format,typecheck,tscscript aliases. - For Python:
pytest.ini/pyproject.toml [tool.pytest]/ atests/directory → pytest.mypy.ini/[tool.mypy]→ mypy.ruff.toml/.ruff.toml/[tool.ruff]→ ruff. - For Rust/Go:
cargo test/go test ./...are the defaults; do not ask. - For typed Node: presence of
tsconfig.json→tsc --noEmitis the typecheck.
- From
- CI configuration
.github/workflows/*.ymlfor required-status-check signals (helps infermerge-policy)..github/PULL_REQUEST_TEMPLATE.mdandCODEOWNERS→ presence of either is a strong signal formerge-policy: review-required.
- Branching
git branch -a(or whatever the harness exposes for listing branches) — look at the last 10–20 branches. If most match a pattern likehyd-123-fooorfeat/some-thing, propose that asbranch-naming.- If only
main/masterand short-lived feature branches exist that get merged quickly → suggesttrunk-based. - Long-running
develop/release/*branches → suggestgitflow.
- Repo topology
- Existing remote(s) from the git config. If
originpoints at a personal fork while another remote points at the upstream, that's a strong signal forpr-flow: fork-and-pr.
- Existing remote(s) from the git config. If
- Polyglot monorepo check
- If you found more than one primary stack manifest at the repo root or in obvious workspace dirs (
packages/*/package.json,services/*/Cargo.toml, etc.), do not silently pick one. Treat this as a polyglot case and follow the polyglot path in Phase 2.
- If you found more than one primary stack manifest at the repo root or in obvious workspace dirs (
Record what you found as a structured intermediate (in working memory; do not write to disk yet):
detected:
package-manager: pnpm (confident — pnpm-lock.yaml present)
single-file-test-cmd: ? (npm scripts have `test: vitest`, but single-file form unclear)
lint-cmd: pnpm lint (confident — scripts.lint present)
typecheck-cmd: pnpm tsc --noEmit (confident — tsconfig.json present)
branch-strategy: feature-branches (likely — many short-lived `feat/*` branches)
branch-naming: feat/{slug} (likely — 8/10 recent branches match)
pr-flow: same-repo (confident — single origin remote)
merge-policy: review-required (likely — CODEOWNERS present)
Distinguish confident (a manifest or lockfile says so) from likely (a heuristic). Only confident values bypass the interview.
Phase 2: Interview
Ask at most five questions, only for fields that aren't confident. Skip fields that are confident. Skip the interview entirely if everything is confident.
Each question should:
- State your recommendation up front — derived from the detection step.
- Show a short rationale.
- Offer the user a chance to override.
Use whatever your harness's structured-question affordance is. If it doesn't have one, ask in a numbered list and accept either short numeric answers or freeform overrides.
The five canonical questions, in priority order:
- Single-file test command (skip if confident)
- Recommendation:
<runner> {file}filled in from the detected runner (vitest {file},pytest {file},go test ./{file}, etc.). - Why: lifecycle
/preflightruns this on the changed file when it can.
- Recommendation:
- Branch strategy (skip if confident)
- Recommendation: based on how recent branches look.
- Options: trunk-based, feature-branches, gitflow.
- Branch naming (skip if confident)
- Recommendation: most-common pattern observed, with
{number}/{slug}placeholders. - Allow
noneif the user has no convention.
- Recommendation: most-common pattern observed, with
- PR flow (skip if confident)
- Recommendation:
same-repoif there's one origin;fork-and-prif you saw an upstream remote distinct from origin.
- Recommendation:
- Merge policy (skip if confident)
- Recommendation:
review-requiredif CODEOWNERS or required checks exist;self-mergeotherwise.
- Recommendation:
After answers come back, also resolve lint-cmd, typecheck-cmd, and package-manager from detection. If any of those are still unknown after detection, fall back to recording none rather than asking — they aren't worth a question slot.
Phase 2-bis: Polyglot monorepo path (only if Phase 1 flagged it)
You have two options. Pick one and confirm with a single yes/no question. Do not write per-workspace blocks unless the user opts into them.
-
Option A — primary workspace: tell the user "I see Node + Python here. I'll record alignment for the Node workspace and skip Python — that's the simplest path. Want me to do that?" If yes, return to the normal Phase 2 with the chosen stack.
-
Option B — per-workspace blocks: write multiple fenced blocks in
AGENTS.md, each labeled with a relative path:<!-- BEGIN: hydrant alignment workspace=apps/web --> ... <!-- END: hydrant alignment workspace=apps/web --> <!-- BEGIN: hydrant alignment workspace=services/ingest --> ... <!-- END: hydrant alignment workspace=services/ingest -->Each block uses the same stable keys. Lifecycle skills resolve which block applies by walking up from the file under edit until they find a block whose
workspace=prefix matches.
When in doubt, pick Option A. Per-workspace blocks add real complexity for the consumer; only use them when the user explicitly wants them.
Phase 3: Write
Now write to AGENTS.md at the repo root.
- If
AGENTS.mddoesn't exist: create it with a top-level# Agentsheading and the Hydrant alignment block as the first section. Do not pull in any other content. - If
AGENTS.mdexists and contains a<!-- BEGIN: hydrant alignment -->fence: replace only the fenced region (inclusive of both sentinels). Do not touch any line outside it. Do not reorder or reflow surrounding content. - If
AGENTS.mdexists but has no fence: append the fenced block at the end of the file, separated from prior content by a single blank line. - If the existing fence is a polyglot multi-block setup: only update the block whose
workspace=matches the workspace you ran against. Leave the others untouched.
Manual-edit safety. If you detect that the existing fence has a comment line like # manually edited or the body is no longer key-value formatted (free-form text), pause and ask the user before overwriting:
"The existing alignment block has been hand-edited. Overwriting would lose those edits. Do you want to overwrite, merge (keep edited values where present), or abort?"
Only proceed once the user picks one.
The block format inside the fences:
## Hydrant alignment
<!-- Generated by /align. Re-run /align to update. -->
- package-manager: <value>
- single-file-test-cmd: <value with {file} placeholder>
- lint-cmd: <value>
- typecheck-cmd: <value>
- branch-strategy: <value>
- branch-naming: <value with {number}/{slug} placeholders>
- pr-flow: <value>
- merge-policy: <value>
Always emit the keys in this order. Always include all eight keys, even if a value is none — consumers parse by key, missing keys force them to fall back blindly.
Phase 4: Confirm
Print a short summary back to the user:
- Where the block was written (
AGENTS.md, plus workspace label for polyglot). - The eight key/value pairs.
- A one-line "next steps" pointer:
Lifecycle skills (/go, /prep, /preflight, /yeet) will pick these up automatically. Re-run /align any time the conventions change.
Do not run any test, lint, or typecheck command as part of /align. Writing the block is the only side effect this skill is allowed to have.
Edge cases
- No package manifest at all (raw shell scripts repo). Phase 1 records
package-manager: none. Phase 2 still runs but recommendsnoneforsingle-file-test-cmd,lint-cmd, andtypecheck-cmd; user can override. - Empty repo (no commits, no files beyond
.git). Detection finds nothing. Tell the user "this repo doesn't have enough signal yet — come back after you've added a manifest or a couple of files," and exit without writing. - AGENTS.md is huge or owned by a different convention. Don't reformat. Only the fenced region belongs to
/align. If there's no fence, append; never insert mid-document. - User runs
/alignfrom a subdirectory of a monorepo. Resolve the repo root (walk up to the nearest.git); always write toAGENTS.mdat the repo root, not the subdir. AGENTS.mdis a symlink or read-only. Stop, tell the user, do not silently fail.
What this skill never does
- Modify any file other than
AGENTS.md. - Run tests, lint, build, or typecheck as part of
/align. - Make network calls.
- Call any
mcp__hydrant__*tool —/alignis purely a local-codebase scan. - Overwrite a hand-edited fence without prompting.
- Lock the user in. The block is plain markdown; the user can edit any value any time.
Why this matters
The lifecycle skills (/go, /prep, /preflight, /yeet) are stack-agnostic by design. Without an Alignment block they ask the user the same questions every invocation or fall back to the safest-but-clunkiest defaults. /align records those answers once so they don't have to be asked again.
Drift is the user's friend. The block is markdown — they edit it, we read it, no schema enforcement beyond the consumer's tolerance for missing keys.