| name | scripts-workflow |
| description | Use when adding/editing scripts under scripts/. Covers layout conventions, shell rules, output contracts, validation. |
Scripts workflow
Discovery: the repo entry is mise and root mise.toml (list: mise tasks); avoid making people read every scripts/*.sh to find usage. When you add a script, register the task in mise.toml and keep the underlying dispatcher mapping in sync. Layout (first tier): scripts/check/ (static, non-destructive), scripts/gate/ (pass/fail), scripts/gen/ (refresh tracked generated artifacts), scripts/run/ (execute/measure), scripts/report/ (human-facing formatting), scripts/perf/ (benchmarks), scripts/dev/ (local setup), scripts/lib/ (sourced helpers only; not executed). Deprecated top-level names may remain as compatibility wrappers during migration. Harness baseline: mise run gate-all inventories toolchain + P0 checks and runs the rest of the project gates; Rust warnings are errors via RUSTFLAGS=-D warnings; clippy runs as cargo clippy --all-targets -- -D warnings.
Table of Contents
Mise: auto-execute after making changes (required)
Automatically execute the following after making script changes. Use mise as the primary repo entry. mise run <task> is optional sugar for the same tasks.
- Always:
mise run check scripts (plus mise run fmt if the script is invoked from tests or the diff touches Rust)
mise run check after touching issues paths or task dispatch
- For coverage/ CI scripts: also run the same command family you would run in
scripts docs (e.g. mise run reference-coverage with a small limit when that script supports it)
mise tasks to confirm your new mise run <task> appears after you add it to mise.toml
- Auto-commit changes after verification passes (commit message based on change description)
Mise / Entry Point Rules
mise is the canonical executable entrypoint.
Do not document or recommend direct dispatcher invocation in Markdown.
Required rules:
- When adding a command, register it in all applicable places:
mise.toml
- the underlying dispatcher mapping
- docs / skills that mention the command
- CI workflow path filters if the command affects CI behavior
- Do not document direct calls to implementation files unless the file is intentionally public.
- Prefer:
mise run check issues
- Avoid:
python scripts/check/issue-health.py
- After task or script command changes, run:
mise run check scripts
mise run check
- After adding a
mise.toml task, run:
Migration / Old Reference Rules
Script migrations must remove stale command references in the same change.
Before finishing any script rename, .sh to .py migration, or manager command rename, run:
rg 'scripts/check_.*\.sh|update_issue_index|issue-queue\.py|update-issue-index\.sh|fixture-differential\.sh|check_fast_gate\.sh|check_manifest_imports\.sh' .
If any hit remains, classify it explicitly:
- valid compatibility wrapper
- historical note in completed issue
- stale reference to fix now
Do not leave stale references in:
.agents/skills/**
.agents/prompts/**
.github/workflows/**
.githooks/**
README.md
AGENTS.md
issues/open/**
issues/index.md
Issue / Index Script Rules
Issue queue scripts are infrastructure-critical. Do not let checker and generator drift.
Required rules:
- Shared parsing/rendering must live in
scripts/lib/.
scripts/check/issue-health.py and scripts/gen/update-issue-index.py must use the same parser and table renderer.
mise run update-issue-index -- --check must fail if generated table content differs, not only if IDs are missing.
mise run check issues must verify:
- duplicate IDs
- open/done conflicts
- missing dependencies
- stale generated index
- missing repo-owned backticked paths
reference/** paths are external corpus references, not normal repo-owned paths. Do not fail issue health solely because reference/** is not cloned.
- YAML issue frontmatter support is limited to the documented single-line format unless a real YAML parser is introduced.
Allowed issue frontmatter shape:
---
id: 026
title: "Migrate backend module to backend-wasm crate"
type: refactor
area: backend
class: implementation-ready
priority: P1
depends_on: [024, 025]
---
Unsupported unless explicitly implemented:
depends_on:
- 024
- 025
Repo Root and Script Location Rules
Repo-root mistakes are high-risk.
Required rules:
- Every script must resolve repo root from its own file location or use manager-provided repo root.
- Scripts under
scripts/check/, scripts/gate/, scripts/gen/, scripts/run/, scripts/report/, scripts/perf/, scripts/dev/ must not assume they are one level below repo root.
- For shell scripts under
scripts/<tier>/foo.sh, use:
repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
cd "$repo_root"
- For shell scripts under
scripts/foo.sh, use:
repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
cd "$repo_root"
- For Python scripts, use
Path(__file__).resolve().parents[N] and verify the expected root contains README.md or .git.
scripts/lib/ files are helpers. They are imported or sourced, not executed directly.
Use this skill only for scripts/ changes.
This skill owns shell script behavior, reliability, CLI contract, and machine-readable output stability.
It does not own fixture content, fixture naming, fixture migration, or fixture path taxonomy.
Scope
In scope:
- scripts/**/*.sh and
mise.toml maintenance
- script usage header updates
- script option parsing
- script reliability and reproducibility improvements
- coverage / benchmark / regression gate script behavior
- reporter script output stability
- reference-suite runner behavior
- CI-facing output contracts
Out of scope:
- editing fixture files under fixtures/**
- renaming fixture directories or files
- changing fixture taxonomy
- changing TestRecord status semantics
- changing docs policy without updating the script contract that consumes it
Use fixtures-workflow together with this skill when a script change requires fixture path migration or fixture reference synchronization.
Core Rules
- Keep
set -e or stricter existing options intact.
- Prefer
#!/usr/bin/env bash plus set -euo pipefail for scripts that use bash arrays, mapfile, [[ ]], associative arrays, or process substitution.
- Prefer POSIX-safe shell only when the script is already POSIX-compatible.
- Quote paths and variables.
- Resolve
repo_root from the script location, then cd "$repo_root" before project-relative access.
- Do not rely on the caller's current working directory.
- Do not hardcode absolute project paths.
- Validate required tools with
command -v before first use when missing tools would produce confusing failures.
- Keep stdout stable when it is consumed by CI, JSONL parsers, markdown table parsers, or other scripts.
- Send human progress logs to stderr when stdout is machine-readable.
- If behavior, options, defaults, or output format change, update the usage header in the same file.
- If a docs page documents the script command or output contract, update that docs page in the same change.
- If a contract (e.g., manifest schema, JSON format, TestRecord schema) changes, update consuming scripts in the same commit to avoid schema/script mismatch.
Fixture Boundary Rules
Scripts may consume fixtures.
Scripts must not become the source of truth for fixture taxonomy.
Allowed:
- iterating over
fixtures/** for smoke or differential runs
- selecting a small representative fixture set for validation
- compiling/running fixture files by stable semantic path
- producing TestRecord entries for fixture cases
Restricted:
- adding new fixture paths inside scripts
- renaming fixture paths inside scripts
- changing fixture directory categories
- silently replacing old fixture paths with new ones
- encoding milestone-style fixture group names such as
m1, m2, stream-g
When fixture paths are touched or fixture references are changed, run the fixture reference update pass from fixtures-workflow in the same change:
- crates/cli/tests/**
- scripts/**
- docs/**
- TestRecord suite strings and related metadata
Recommended searches before finalizing a script that references fixtures:
fixtures/
fixtures/<changed-dir>
"<changed-dir>/"
TestRecord
suite
case
Input Selection Rules
- Sort discovered files before iteration.
- Use stable locale-sensitive behavior explicitly where needed, for example
LC_ALL=C sort.
- Validate numeric options such as
--limit, --sample, and --jobs.
- Make sampling deterministic unless the usage header explicitly documents randomness.
- For parallel runners, preserve deterministic output ordering or document that output ordering is intentionally nondeterministic.
- Never let skipped or missing directories silently look like success unless the usage header documents that behavior.
- For reference suites, distinguish:
- repository-owned fixtures under
fixtures/**
- external reference corpora under
reference/**
- generated artifacts under
artifacts/**
Output Contract Rules
Machine-readable output is a compatibility contract.
For JSONL TestRecord output:
- one JSON object per line
- no progress logs on stdout
- include at least
suite, case, target, status
- include
reason and tracking for unsupported, blocked, and skip-with-reason
- do not invent status strings outside the canonical schema
- do not collapse
unsupported, blocked, and fail into one bucket
- preserve field names unless all consumers are updated in the same change
For markdown coverage tables:
- preserve marker comments such as
<!-- coverage-table:start -->
- preserve column order unless all readers are updated
- preserve numeric columns as parseable integers or decimals
- avoid presentation-only formatting in machine-parsed cells
For human reports:
- keep generated file paths explicit
- include enough reproduction command text to rerun the same sample
- do not mix policy text with generated measured results
Temporary File and Artifact Rules
- Use
mktemp -d for temporary work directories.
- Always install a cleanup trap.
- Quote cleanup paths in traps.
- Write generated persistent results under
artifacts/ or a user-provided output path, not under fixtures/.
- Do not mutate fixture files during script execution.
- Do not rely on
/tmp layout except through mktemp or ${TMPDIR:-/tmp}.
- Make check modes non-mutating, or restore files before exit.
- For benchmark or coverage scripts, record enough metadata to reproduce the run:
- command
- suite
- limit/sample
- target
- runner
- timestamp
- git commit when available
Hermeticity and Reproducibility Rules
- Prefer repository files, declared reference directories, and generated build outputs over network access.
- Do not fetch external resources from scripts unless the script is explicitly an installer/fetcher and documents it.
- Do not depend on user-specific global state without a clear preflight error.
- Do not require untracked local files unless the usage header names them.
- Avoid ambient environment variables. When used, document them in the usage header.
- Prefer explicit CLI flags over hidden environment behavior.
- Keep test and coverage scripts re-runnable from a clean checkout after documented setup.
Regression Gate Rules
Regression gates must fail on real regressions and avoid hiding coverage debt.
Required behavior for gates:
- fail if executed count decreases
- fail if fail count increases
- warn or fail explicitly when unsupported/blocked increases, according to the documented policy
- never count
unsupported, blocked, or skip-with-reason as pass
- print the compared baseline and current files when failing
- exit nonzero on gate failure
- keep error messages stable enough for CI logs and reviewers
Script Change Classification
Before editing, classify the script change:
- syntax-only cleanup
- option parsing change
- output format change
- fixture consumption change
- reference-suite selection change
- coverage/gate policy change
- benchmark measurement change
- generated artifact update
Use the strictest relevant validation group below.
Validation
Always run the smallest valid set, but never stop at syntax-only checks.
For any script change:
mise run check scripts
bash -n <touched-shell-script>
mise run check
For manager, issue, or generated-index scripts:
mise run update-issue-index -- --check
mise run check issues
mise run check
For CI workflow changes:
mise run check
mise run gate-fast
For coverage/reference/test262 scripts:
mise run update-coverage-matrix -- --check
mise run check coverage -- <base-doc> <current-doc>
mise run test262 -- --sample 1 --jobs 1
For scripts that produce JSONL/TestRecord:
mise run check records -- <file.jsonl>
For scripts that consume fixtures:
mise run check fixtures
mise run gate-fast
For Rust-impacting script changes:
mise run fmt
cargo nextest run
Common Traps
- Script update silently changes stdout format
- Human logs are printed into JSONL stdout
- Usage header no longer matches actual options
#!/bin/bash is used when repo convention expects #!/usr/bin/env bash
- POSIX-safe claim is made while using bash-only syntax
local is used outside a function
- Arrays or associative arrays are added without bash shebang
grep -P is introduced without portability consideration
find output is not sorted
- Unquoted paths break on spaces
- Temporary files are written into the repository root
- Check mode leaves generated files modified
- Fixture paths are changed only in scripts, not tests/docs/TestRecord metadata
- Fixture directory rename leaves old suite strings
- Coverage count improves because unsupported/blocked grew
- Reference corpus missing locally is treated as all-pass
- Parallel jobs produce nondeterministic machine-readable output
- Benchmark script changes measurement conditions without recording metadata
mise.toml task exists but the underlying dispatcher mapping is missing
- docs/CI/hooks call
mise but only direct implementation entrypoints were tested
.sh script is migrated to .py but workflow path filters still watch the old .sh
- checker and generator parse the same file with different logic
- issue index check only checks ID presence, not table content drift
reference/** is treated as required repo-owned content
repo_root is computed as scripts/ instead of repository root
source scripts/lib/common.sh is relative to the wrong tier directory
replace_generated_block() drops final newline and causes endless stale-index diffs
- generated block marker absence is ignored
- syntax check passes but representative runtime command was never executed
- run report directory is created but no machine-readable command result is captured
Related Skills
- fixtures-workflow: for fixture path updates when scripts reference fixtures
- docs-workflow: for documentation updates when script contracts change
- issues-workflow: for tracking script behavior changes
Output Checklist
- Which script files changed
- Script change classification
- Behavior delta before/after
- Output contract delta, or
none
- Fixture/reference path delta, or
none
- Docs/usage header updates
- Commands run for validation
- Generated artifacts changed, or
none
- Remaining risks