AgentStack
SKILL verified Apache-2.0 Self-run

Ironlint Config

skill-ironlint-ironlint-ironlint-config · by ironlint

Authors, modifies, or removes checks in an ironlint .ironlint.yml. Use when the user says "add an ironlint check for X", "ban Y", "tighten <check-id>", "stop checking <check-id>", "remove <check-id>", "change the scope of a check", or asks how to write an ironlint config.

No reviews yet
0 installs
16 views
0.0% view→install

Install

$ agentstack add skill-ironlint-ironlint-ironlint-config

✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access No
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets No
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

Are you the author of Ironlint Config? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

Authoring ironlint checks

An ironlint policy lives in .ironlint.yml at the project root. A check is a file scope plus a shell command (or sequence of steps):

checks:
  no-debug:
    files: "**/*.ts"          # glob, or a list of globs
    run: "! grep -n 'DEBUG'"  # proposed content arrives on stdin; nonzero = block
  • files — the glob(s) the check watches. A bare pattern with no / (e.g. *.py) also matches at any depth.
  • run — a shell command handed to sh -c. Any nonzero exit (1–125) blocks the edit; exit 0 passes. 126/127/timeout are treated as a broken check, not a block.
  • steps — alternative to run: a sequence of {name, run} steps, all fed the same stdin. The first nonzero step blocks.
  • on — lifecycle events: [write] (default) fires per file on every agent write; [pre-commit] fires once before a commit (see ABI below). Use on: [write, pre-commit] to fire at both.
  • name — optional human-readable label shown in block messages.

ABI — what every check receives

  • $IRONLINT_FILE — absolute path of the single file under check (set for write; not set for pre-commit).
  • $IRONLINT_FILES — newline-joined list of all files under check (single entry for write; all staged files for pre-commit).
  • $IRONLINT_ROOT — project root (the check's cwd).
  • $IRONLINT_EVENTwrite or pre-commit.
  • $IRONLINT_TMPFILEwrite only, set only when your run mentions it: an absolute path to a temp file holding the proposed content, placed beside $IRONLINT_FILE with the same extension and auto-cleaned. Use it for tools that need a real file on disk (Biome, ESLint file-mode, tsc, ruff) instead of stdin. Unset on pre-commit (files are already on disk at $IRONLINT_FILES).
  • stdin — proposed post-edit file content (write) or empty (pre-commit).

Read proposed content from stdin, not from $IRONLINT_FILE. On harnesses that gate before the write lands (e.g. codex, pi), the file on disk still holds the OLD content, so reading it misses the very change you mean to check. Use $IRONLINT_FILE to hand a tool a filename (e.g. a linter's --stdin-filename), never as the content source.

On block, the check's combined stdout+stderr becomes the message the agent sees, so make the command print why it blocked.

Check patterns

Ban a pattern (grep, reads stdin). With nonzero-blocks, ! grep is the natural idiom — grep exits 0 on a match (which ! flips to 1, blocking) and exits 1 when clean (which ! flips to 0, passing):

  no-console-log:
    files: ["src/**/*.ts", "src/**/*.tsx"]
    run: "! grep -nE 'console\\.log\\('"

Wrap a linter (stdin). Feed the proposed content to a linter. Most linters exit nonzero on findings, which blocks directly:

  ruff-check:
    files: ["**/*.py"]
    run: "ruff check --quiet --stdin-filename \"$IRONLINT_FILE\" -"

Wrap a file-oriented linter (temp file). Tools that won't read stdin cleanly get a real path:

  biome-check:
    files: ["src/**/*.{ts,tsx,js,jsx}"]
    run: "npx @biomejs/biome check \"$IRONLINT_TMPFILE\""

Limitation: $IRONLINT_TMPFILE has a synthetic name (ironlint-tmp-…), so tools that select behaviour by filename glob — e.g. ESLint overrides scoped to *.test.ts, or Biome include/ignore patterns — won't match it the way they'd match the real file. Language detection (by extension) and nearest-config resolution (the temp file sits beside $IRONLINT_FILE) do work. When a tool needs the real filename for its config, pass $IRONLINT_FILE for that and $IRONLINT_TMPFILE only for the content.

Multi-step check. Use steps when you want to run multiple commands in sequence — all must exit 0:

  ts-quality:
    files: "src/**/*.ts"
    on: [pre-commit]
    steps:
      - name: typecheck
        run: "tsc --noEmit"
      - name: no-any
        run: "! grep -n ': any' $IRONLINT_FILES"

Multi-line scripts. Use a YAML block scalar so newlines survive — a plain or folded (>) scalar collapses them and can turn the whole script into one comment that silently passes:

  guard:
    files: "*.rs"
    run: |
      grep -q 'FORBIDDEN' && exit 1
      exit 0

Pre-commit check (staged files). Runs once before a commit, receiving all staged matching files via $IRONLINT_FILES:

  no-secrets:
    files: "**/*"
    on: [pre-commit]
    run: "detect-secrets scan $IRONLINT_FILES"

Disable a check for a file

Add # ironlint-disable: anywhere in the file to suppress that check for the whole file:

# ironlint-disable: no-console-log
console.log("debug only")

Process

  1. Read .ironlint.yml to see existing checks (if none exists, scaffold one with ironlint init).
  2. Draft the check: files scope + a run command that exits nonzero to block.
  3. Build two fixtures: a dirty file the check should block, and a clean one it should pass.
  4. Test each by feeding the fixture's content on stdin and isolating the check:

``bash ironlint check --file dirty.py --check ruff-check < dirty.py ; echo "dirty exit: $?" # expect nonzero ironlint check --file clean.py --check ruff-check < clean.py ; echo "clean exit: $?" # expect 0 ``

  1. Verify the check exits nonzero on dirty input and 0 on clean input.
  2. If both hold, write the check into .ironlint.yml.
  3. Run ironlint trust to re-bless the config — edits invalidate the trust fingerprint, so checks refuse to run until you do.

Test before write

Always test the check against a fixture BEFORE writing to .ironlint.yml. A check that doesn't exit nonzero on dirty input is worse than no check — it gives false confidence. A check that exits nonzero on clean input blocks every edit in scope.

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet — be the first.

Versions

  • v0.1.0 Imported from the upstream source.