Best for
- Creating a new rule in src/rules/{name}.md
- Rewriting an existing rule (not a typo fix)
- Deciding whether something should be a rule at all
event4u-app/agent-config/src/skills/rule-writing/SKILL.md
Use when creating or editing a rule in src/rules/ — trigger wording, always vs auto classification, size budget — even when the user just says 'add a rule for X'.
Decision brief
Use when creating or editing a rule in src/rules/ — trigger wording, always vs auto classification, size budget — even when the user just says 'add a rule for X'.
Compatibility matrix
| Platform | Status | Evidence | What to check |
|---|---|---|---|
| Codex | Not declared | No explicit evidence | Portability before use |
| Claude Code | Not declared | No explicit evidence | Portability before use |
| Cursor | Not declared | No explicit evidence | Portability before use |
| Gemini CLI | Not declared | No explicit evidence | Portability before use |
Installation
The source command is displayed only when detected. A safe inspection prompt is always available so your agent can explain every action before execution.
npx skills add https://github.com/event4u-app/agent-config --skill "src/skills/rule-writing"Inspect the Agent Skill "rule-writing" from https://github.com/event4u-app/agent-config/blob/6a5670b7881a676c0da90d2afb950298087c4ccb/src/skills/rule-writing/SKILL.md at commit 6a5670b7881a676c0da90d2afb950298087c4ccb. List every install step, command, network request, credential, file read/write, external action, and rollback step. Explain whether it fits my task. Do not install or execute anything until I approve.
Workflow
Creating or materially rewriting a rule must go through Understand → Research → Draft from the artifact-drafting-protocol rule.
Creating a new rule in src/rules/{name}.md Rewriting an existing rule (not a typo fix) Deciding whether something should be a rule at all Converting a learning from learning-to-rule-or-skill into a concrete rule
A rule is a constraint — it states a boundary, not a workflow. If the content needs numbered steps, it is a skill.
Creating or materially rewriting a rule must go through Understand → Research → Draft from the artifact-drafting-protocol rule.
Normative source: rule-type-governance.
Permission review
No configured static risk pattern was detected
This is not proof of safety. Runtime behavior, indirect dependencies, and hidden external systems are outside the static scan.
Evidence record
| Signal | Value | Evidence type | Meaning |
|---|---|---|---|
| Quality score | 98/100 | Computed | Documentation, specificity, maintenance, and trust rules |
| Repository stars | 9 | Source | Repository attention, not individual Skill quality |
| Compatibility | 0 platforms | Source | Declared in the catalog source record |
| Usage guide | automated source guide | Editorial | Generated or reviewed according to the visible evidence level |
Pinned source
src/rules/{name}.mdlearning-to-rule-or-skill into a concrete ruleDo NOT use this skill when:
skill-writingguideline-writingcommand-writing| Intent | Artifact |
|---|---|
| "Agent must always/never do X" | Rule |
| "When Y happens, run these steps" | Skill |
| "Here is knowledge the agent may cite" | Guideline |
A rule is a constraint — it states a boundary, not a workflow. If the content needs numbered steps, it is a skill.
Creating or materially rewriting a rule must go through Understand →
Research → Draft from the
artifact-drafting-protocol rule.
src/rules/ for overlap
and analyze rule-type-governance, size-enforcement,
skill-quality before drafting.type, description) first, wait for
confirmation, then fill the body.always vs autoNormative source: rule-type-governance.
always — universal behavior (language, scope, safety, verification)auto — triggered by description match on domain/symptomDefault to auto. always must be justified — if >50% of conversations
don't need it, it is auto.
The description field is the trigger. Describe when the rule
applies, not what it contains. Hard cap: 200 characters (the
linter errors description_too_long above it); the rule schema
(rule.schema.json) additionally sets maxLength: 190.
# Bad — describes content, won't match reliably:
description: "PHP coding standards"
# Good — trigger-shaped, names domain + symptoms:
description: "Writing or reviewing PHP code — strict types, naming, comparisons, early returns, Eloquent conventions"
When iterating on phrasing, delegate to the
description-assist skill — approval-gated,
no silent edits, max two rounds.
Three different surfaces, three different rules. Mixing them up will
either fail the schema (./scripts-run src/scripts/validate_frontmatter) or
fail ./scripts-run src/scripts/lint_load_context. Canonical reference:
templates/rule.md § Path conventions and
docs/contracts/load-context-schema.md.
| Field | Form | Example |
|---|---|---|
load_context: / load_context_eager: | Logical name rooted at the source — never src/ | contexts/execution/verification-mechanics.md |
triggers[].path_prefix: | Literal match pattern the host evaluates against the file the agent is editing — not rewritten | src/skills/ (source-of-truth rules) or agents/, app/, .augment/ |
| Body links to guidelines / contracts | Verbatim relative form — ../../docs/... works in any markdown viewer; rewriter handles depth | [guideline](../../docs/guidelines/<group>/<name>.md) |
The condense-time rewriter (scripts/condense.ts::_rewrite_paths) is
idempotent and depth-aware — it resolves logical names and body links
to the deployment-correct relative path at condense time, leaving
path_prefix: literally as written. The schema regex
(scripts/schemas/rule.schema.json) and scripts/lint_load_context.ts
both reject the src/ prefix in load_context: /
load_context_eager: with an error pointing at the canonical logical
name.
Normative source: size-enforcement +
docs/guidelines/agent-infra/size-and-scope.md.
| Category | Target |
|---|---|
| Ideal | < 60 non-empty lines |
| Acceptable | < 100–120 lines |
| Hard limit | < 200 lines |
Linter emits long_rule above ~80 non-empty lines. Above that, justify in
the PR or split by responsibility.
./scripts-run src/scripts/skill_linter src/rules/{name}.md
→ must report 0 FAIL.bash scripts/condense.sh --sync to regenerate dist/agent-src/rules/{name}.md../scripts-run src/scripts/condense --generate-tools to project into .claude/, .cursor/, .clinerules/, .windsurfrules.Taskfile.yml in this repo for
the script list) — must exit 0 except for tolerated warnings.After validation, before declaring the rule done, run:
./scripts-run src/scripts/measure_augment_budget --check
If utilisation is ≥ 0.95 (or the check exits non-zero), STOP and
invoke rule-refactor. Do NOT:
FAIL_THRESHOLD in scripts/measure_augment_budget.ts —
threshold-lift is explicitly forbidden (see the
validation-budget rule and
the rule-refactor Iron Law).The discipline: budget pressure is the signal that the rule set
needs a cleanup pass, not that the new rule needs to be smaller. The
rule-refactor skill runs the audit and proposes merge / delete /
move-to-context / promote-to-skill so the new rule earns its space.
Advisory, reviewer-checked — no CI gate. When the same PR adds a
new check to scripts/skill_linter.ts (or strengthens an existing
one) such that previously-clean rules now warn, the PR body MUST
record the pre-existing violations on main in a Markdown table:
### Pre-existing baseline (informational)
| Code | Count on main | Bucket |
|---|---:|---|
| {new_code} | N | (a) genuine fix · (b) accept · (c) check too aggressive |
Forward-only: the new check applies to the rule under review and
to future edits. The baseline table is informational so reviewers
can distinguish genuine debt from acceptable carry-overs without
diffing the full lint output. See
agents/evidence/analysis/lint-warning-triage.md for the 3-bucket reference.
---
type: "auto" # or "always"
description: "Trigger-shaped sentence — domain + symptoms — schema max 190 chars"
alwaysApply: false # true only if type: always
source: package # or project for consumer-local rules
load_context: # logical names only — `contexts/<area>/<file>.md`
- contexts/execution/verification-mechanics.md
triggers: # path_prefix is literal, not rewritten
- path_prefix: "src/rules/"
routes_to:
- "skill:related-skill"
---
See § 3b above for the load-bearing distinction between load_context:
(logical, rewritten), triggers[].path_prefix: (literal, verbatim),
and body links (relative ../../docs/..., rewriter handles depth).
EVERY RULE STATES, IN ONE SENTENCE, THE MODEL'S WRONG DEFAULT IT EXISTS TO
OVERRIDE. NOT THE HISTORY. NOT THE RATIONALE. THE TENDENCY.
A RULE THAT CANNOT NAME ONE IS A RULE WITH NO OBSERVED FAILURE BEHIND IT.
One sentence, near the top, in the shape "left alone, the model <does the wrong thing>":
Why this field and not a longer rationale. It is the discriminator the
mechanism-must-match-an-observed-failure-mode discipline wants at authoring
time: a rule whose bias sentence is a plausible generality is a rule aimed at
nothing in particular, and that is visible in one line where it is invisible in
three paragraphs. The field is also the input to the removal question later —
decision-review asks whether the agent still exhibits the named tendency, and
that question cannot be asked of a rule that never named one.
Retrofit is opportunistic, never a sweep. Add the sentence when you touch a rule for another reason. A batch edit across the rule set trips the kernel-prefix byte-stability gate, and that gate is right to fire — the kernel prefix is pinned deliberately.
A rule body mixes two shapes. Standing obligations hold for every turn the rule is loaded ("every reply mirrors the user's language"). Condition-action clauses fire on a situation ("when the diff deletes a directory, surface it"). The router matches on frontmatter; in-body conditionals are prose, so a rule's situational half is invisible to everything except a full read.
Where a rule carries more than two of them, group them under a
## Conditions heading, one bullet per clause, each in the shape
<condition> → <action>. Two effects, both cheap:
decision-review needs to ask whether the clause still earns its
place.Optional on purpose. A rule with one conditional does not need a section to hold it, and a heading over a single bullet is ceremony.
type: is a delivery class — how the rule reaches the model. It says
nothing about what is at stake when the rule fires, and kernel-membership and
always-loaded-budget arguments were being made with no stated impact class at
all. decision_impact: carries that, with three values:
| Value | Meaning | Consequence |
|---|---|---|
overrides-model-default | the model's base behaviour is wrong here | load-bearing; the strongest case for staying loaded |
encodes-house-choice | the model would make a defensible choice, not ours | stays until the house choice changes |
already-complied-with | the model does this unprompted | the one value that permits removal |
The third carries an evidence bar, enforced by lint_decision_impact: it
requires decision_impact_evidence, a pointer a reviewer can follow to the
observation. The bar exists because that classification is what permits deleting
a rule, and "the model probably does this anyway" is the cheapest possible way
to remove a floor that was working precisely because nothing had crossed it —
active-remediation names that failure as deleting a rule that is merely quiet.
Optional, and backfill is opportunistic. Classifying all 111 rules in one
batch is exactly the shape that trips check_kernel_prefix_stability. Add it to
new rules, and to a rule you are already touching for another reason.
src/rules/{name}.mdbash scripts/condense.sh --sync + ./scripts-run src/scripts/condense --generate-tools ran cleanalways "just in case" — token cost is real, auto is default../scripts-run src/scripts/condense --generate-tools — downstream tools stay stale.dist/agent-src/rules/ or .augment/rules/ directly — those are generated.Apply the Frugality Charter to every rule you author.
Examples in this artifact:
kernel-membership
list.Pre-save self-check:
dist/agent-src/, .augment/, .claude/, etc.)On cloud surfaces (Claude.ai Web, Skills API) the package's
scripts/skill_linter.ts, scripts/condense.ts, and task runner
are not reachable. The skill still applies — with prose-only
validation:
type is always
or auto, description is trigger-shaped, alwaysApply matches
type.src/rules/{name}.md
and run task sync && task lint-skills locally before committing.Good description (trigger-shaped, names domain + symptoms):
"Git commit message format, branch naming, conventional commits, committing, pushing, or creating pull requests"
Bad description (no trigger, too vague):
"Commit conventions"
The pair above governs descriptions. A rule whose obligation is easy to agree with and hard to apply — what counts as a cheap question, when an interrupt is an interrupt, which reply mirrors the user's language — needs the same treatment for the behaviour, not just the frontmatter.
Six live corpora already carry those pairs:
direct-answers-demos,
asking-and-brevity-examples,
language-and-tone-examples,
and autonomy-examples / interrupt-examples / cheap-question-mechanics under
src/agent-src/contexts/execution/. Follow one; do not invent a format.
The shape they share: the wrong version in the form it actually gets written, the right version, and one line of why — the why is what makes it a rule rather than a memorised case.
Where the pairs go is a size decision, not a taste one. A rule body is capped at
200 lines hard / 120 soft, so more than two or three pairs belong in a guideline
or context file the rule points at — same split
skill-writing § Contrastive-example slot uses.
Frequently asked questions
Use when creating or editing a rule in src/rules/ — trigger wording, always vs auto classification, size budget — even when the user just says 'add a rule for X'.
The source record exposes this install command: npx skills add https://github.com/event4u-app/agent-config --skill "src/skills/rule-writing". Inspect the command and pinned source before running it.
Alternatives
coreyhaines31/marketingskills
When the user wants to plan, design, or implement an A/B test or experiment, or build a growth experimentation program. Also use when the user mentions "A/B test," "split test," "experiment," "test this change," "variant copy," "multivariate test," "hypothesis," "should I test this," "which version is better," "test two versions," "statistical significance," "how long should I run this test," "growth experiments," "experiment velocity," "experiment backlog," "ICE score," "experimentation program
garrytan/gbrain
End-to-end discipline for turning any large data source (audio libraries, email takeouts, document corpora, chat exports, API dumps) into brain pages at scale. The lifecycle spine: SCHEMA → ACCESS → TRIAL → EVALUATE → IMPROVE → CODIFY → TEST → SKILLIFY → BULK → MONITOR. State is tracked in a durable JSON manifest (see MANIFEST-PATTERN.md) so any crash, session boundary, or subagent fan-out resumes from ground truth instead of memory.
alirezarezvani/claude-skills
App Store Optimization (ASO) toolkit for researching keywords, analyzing competitor rankings, generating metadata suggestions, and improving app visibility on Apple App Store and Google Play Store. Use when the user asks about ASO, app store rankings, app metadata, app titles and descriptions, app store listings, app visibility, or mobile app marketing on iOS or Android. Supports keyword research and scoring, competitor keyword analysis, metadata optimization, A/B test planning, launch checklist
dotnet/skills
Migrates .NET test projects from VSTest to Microsoft.Testing.Platform (MTP). Use when user asks to "migrate to MTP", "switch from VSTest", "enable Microsoft.Testing.Platform", "use MTP runner", set OutputType=Exe only for test projects in Directory.Build.props, or mentions EnableMSTestRunner, EnableNUnitRunner, or UseMicrosoftTestingPlatformRunner. USE FOR: MTP behavioral differences vs VSTest (exit code 8, zero tests discovered, --ignore-exit-code, TESTINGPLATFORM_EXITCODE_IGNORE); centralizing