Skip to content
Back to skills

Authoring Guardrails

ASecurity

Use when adding, fixing, or turning off a guardrail in a project that has sloprail installed — a rule under .sloprail/ that refuses an agent's action. Covers the three natures (file-guard, gate, context), their YAML, the flat event model, the check contract, and how to prove a rule actually fires.

  • 2 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added October 9, 2026
ai-agentsgobashrailsgit

Security analysis

A100/100

Pro scans all 13 files and shows the line behind each finding

Scanned October 9, 2026

npx -y skills add sloprail/sloprail --skill authoring-guardrails --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Authoring Guardrails?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Authoring Guardrails
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/sloprail-authoring-guardrails/badge)](https://www.skillsdirectory.com/skills/sloprail-authoring-guardrails)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: authoring-guardrails
description: Use when adding, fixing, or turning off a guardrail in a project that has sloprail installed — a rule under .sloprail/ that refuses an agent's action. Covers the three natures (file-guard, gate, context), their YAML, the flat event model, the check contract, and how to prove a rule actually fires.
---

# Authoring guardrails

A guardrail is a rule under `.sloprail/` that refuses something an agent does. The work is
not writing a plausible declaration; it is writing one and then proving it refused
something. A rule that loads cleanly and admits everything is worse than no rule: it looks
like protection and is not.

## Is the rule worth writing?

Write it only when all of these hold. If one does not, say so instead of writing a weaker
rule.

- **The violation is real and recurring.** You have seen it, or the user named it. A rule
  against something nobody does costs every session and catches nothing.
- **A machine can tell.** A script decides what is decidable ("a write under
  `memories/decisions/` before the `document-strategy` skill was loaded"). A judge, a model
  with a rubric, decides what needs judgement ("the change is clean and targeted"). Hand a
  judge only what a script cannot decide.
- **Refusing is the right response.** If the honest response is "note it and move on", a
  guardrail is the wrong tool.
- **A check can reach the answer.** Besides the event itself, a check can read the
  repository, what earlier cycles recorded in `sr-session state`
  ([state-management.md](state-management.md)), and the session transcript
  ([script-checks.md](script-checks.md#asking-what-the-agent-did)).

## Which nature is it?

Every rule is one of three natures. The nature fixes its folder, its YAML keys and when it
runs.

| The question | Nature | Example |
|---|---|---|
| Is what was committed right? | [file-guard](file-guard.md) | "Every file under `memories/` has frontmatter." |
| May this action happen, or may the turn end? | [gate](gate.md) | "Refuse a write under `spec/` until the spec skill was loaded." |
| Is the session in a mode other rules depend on? | [context](context.md) | "A refactor was declared; it stays on until it is finished." |

A file-guard judges commits after the fact; only a gate can refuse an action before it
happens. A rule that must do both, refuse a bad write and judge what was committed, is two
rules with one name: a gate and a file-guard.

Alongside the three natures there is the [structure gate](structure-gate.md): one allowlist of
the paths that may be written at all.

## Where a rule lives

```
.sloprail/file-guard/<name>/file-guard.yaml
.sloprail/gate/<name>/gate.yaml
.sloprail/context/<name>/context.yaml
.sloprail/file-guard/structure.yaml        # the structure gate: one file
.sloprail/config.yaml                      # project settings, not a rule
.sloprail/<nature>/<name>/tests/<case>/test.sh
```

The folder name is the rule's name, and a refusal ends with it, so pick one that reads well
there; kebab-case is the convention. The rule's scripts and judge templates sit beside its
YAML. Create the folders yourself; nothing scaffolds them.

A rule's full name is `<plugin>/<nature>/<name>` (`sloprail/gate/cite-before-commit`), or
`<nature>/<name>` for the project's own. The nature is part of it because a gate and a
context may share a name.

## How a rule decides

A rule narrows itself to the events or files it is about with a `match`
([matchers.md](matchers.md)), may `require` preconditions, and runs its `checks:` in order
until one refuses:

```yaml
checks:
  - script: ./check.sh                 # deterministic: exit 0 permits
  - prepare: ./gather.sh               # optional, assembles what the judge needs
    judge: ./is-it-good.md.j2          # a model answers with a verdict
```

A [script check](script-checks.md) reads one JSON `CheckPayload` on stdin, and its exit code
is the verdict. Start from [check-template.sh](check-template.sh) for a file-guard or
[gate-check-template.sh](gate-check-template.sh) for a gate that prevents a write, and change
only `fine()`. A [judge check](judge-checks.md) is a prompt template a model answers.

The event's fields sit directly under `.event`: `.event.path`, `.event.newContent`,
`.event.kind`. There is no `.event.fields` nesting. Beside the event, the payload carries
`.transcriptPath` (the session record) and, on a gate, `.context` (every declared context).
A file-guard's checks receive a changeset of commits instead of an event. Every event kind
and its fields: [events.md](events.md).

## Prove it fires

A rule that does not load is reported to you at the next hook and at Stop; that report is the
load check, and it names every event kind and field the build knows. You do not need to run
anything for it.

Loading is not firing. A rule can load and still never refuse anything: a `match` true of
nothing real, a misspelled key the loader cannot see, a check that permits where it meant to
refuse. So cause the action the rule guards, see it refused, and see a good neighbour
permitted. Keep that proof as a case in the rule's own `tests/<case>/test.sh`, one rule per
case, and run it with `sr-test run --rule <nature>/<name>`. `sr-test doctor` lists the rules
that have no case.

A file-guard is judged over a range of commits with `sr-checks`
([file-guard.md](file-guard.md#running-it)).

## Changing a rule that already stands

A change to a rule that already stands must trace to the user's words or to a tool output
that shows the rule misfiring. Cite it in the commit:

```bash
git commit -m 'relax demo: allow untitled notes' \
  -m 'Sloprail-Cites-User: let the demo rule accept untitled notes'
```

How citations work: [grounding.md](grounding.md).

## Turning a rule off

Keep the folder: its YAML and scripts hold the reasoning someone needs to switch it back on.
Switch it off by its full name in `.sloprail/config.yaml`; turning a rule off is a rule change,
cited like any other.

```yaml
disabled:
  - sloprail/file-guard/authoring-slop
```

This is also the way to switch off a plugin's rule, whose files a reinstall would overwrite,
and a plugin's rule that does not load, which you cannot fix. A gate that ships off
(`enabled: false` in its YAML) is switched on the same way, under `enabled:`. Disabling a
context leaves every gate that `require`s it refusing, so disable those too.

Files in this skill

  • SKILL.md6.3 KB
  • check-template.sh2.5 KB
  • context.md4.8 KB
  • events.md6.8 KB
  • file-guard.md6.5 KB
  • gate-check-template.sh1.5 KB
  • gate.md6.1 KB
  • grounding.md6.2 KB
  • judge-checks.md5.4 KB
  • matchers.md4.1 KB
  • script-checks.md3.9 KB
  • state-management.md4.4 KB
  • structure-gate.md4.2 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.