Crafting Rules
Rules are markdown files injected into the system prompt to guide agent behavior.
Rule Format
---
globs:
- '**/*.ts'
keywords:
- 'vitest'
---
# Rule Title
- Write rules as concrete, actionable instructions.
Field Reference
| Field |
Type |
Purpose |
globs |
string[] |
Apply when any file in context matches a pattern |
keywords |
string[] |
Apply when the user's latest prompt matches a keyword |
- Both fields are optional; no frontmatter means the rule always applies.
- If both
globs and keywords are present, matching is OR (either triggers).
Matching Strategy
- Use
globs when the rule is about code in specific files/directories.
- Use
keywords when the rule is about a topic that may not include files.
- Use both when either condition should trigger.
- Use neither for global standards (tone, structure, safety, commit conventions).
Important constraints:
- Keyword matching is case-insensitive word-boundary prefix matching (e.g.,
test matches tests and testing).
- You cannot express
globs AND keywords; if you need that behavior, split into multiple rules.
Storage Location
~/.config/opencode/rules/: personal preferences you want across projects.
.opencode/rules/: project/team conventions and repo-specific behavior.
Extracting Rules from Patterns
Signals a pattern should become a rule:
- Explicit: "always do X", "never do Y", "remember to...", "from now on..."
- Corrections: the user fixes the same agent behavior more than once
- Preferences: consistent style/process guidance (tests, commits, PRs, error handling)
- Frustration indicators: "I told you before", "again"
Analysis questions:
- Is this recurring, or a one-off for the current task?
- Does this apply to specific files, or all work?
- Is there an existing rule/config that already encodes this (AGENTS.md, lint config, Prettier, etc.)?
- Would this conflict with project conventions?
Workflow:
- Identify the behavioral delta (what should change?).
- Determine scope (globs, keywords, or always-on).
- Check existing rules/configs for overlap/conflict.
- Draft the minimal rule (one concept per rule when practical).
- Choose location (global vs project).
Conversation extraction examples:
- User: "Use early returns instead of nested if/else" -> always-on code style rule.
- User: "In unit tests, always use describe/it blocks" -> prefer glob-scoped rule (e.g.,
**/*.{test,spec}.*, **/__tests__/**); if prompt-scoped, use allowlisted keywords like unit test, vitest, jest (avoid test/testing).
- User repeatedly fixes import ordering -> glob-scoped rule for the relevant languages/files.
Keyword Selection Guidelines
How matching works (important):
- Keywords are matched with case-insensitive word-boundary prefix matching, so short/generic keywords tend to over-match.
Denylist (avoid by default):
- Generic nouns:
code, file, project, repo, bug, issue, change
- Common verbs:
add, update, remove, fix, make, create, implement
- Over-broad topic nouns:
testing, performance, security, deployment, database, api
- Single-token abbreviations:
ci, cd, db, ui, ux
Allowlist (prefer by default):
- Tool/framework names:
vitest, jest, pytest, playwright, cypress, eslint, prettier, typescript, terraform, kubernetes
- Compound phrases:
unit test, integration test, snapshot test, lint rule, error boundary, api endpoint, rest api
- High-intent engineering verbs:
refactor, rollback, migrate, deprecate
If you feel tempted to use a denylisted keyword:
- Prefer globs (file-scoped) instead.
- Or replace it with a compound phrase / tool name that captures intent.
Keyword audit checklist:
- Would this keyword appear in prompts where the rule should NOT apply?
- Is it likely to appear as part of another word due to prefix matching?
- Can you scope via globs instead?
Writing Guidelines
- Use imperative voice: "Do X", "Prefer Y", "Avoid Z".
- Make rules executable: instructions the agent can follow.
- Stay minimal: avoid restating generic best practices.
- Prefer examples over prose when a pattern is subtle.
Examples
Glob-based: TypeScript conventions
---
globs:
- '**/*.ts'
- '**/*.tsx'
---
# TypeScript
- Prefer `type` over `interface` unless you need declaration merging.
- Avoid `any`; use `unknown` and narrow.
Keyword-based: unit test guidance (allowlisted terms)
---
keywords:
- 'unit test'
- 'integration test'
- 'vitest'
- 'jest'
---
# Unit Tests
- Follow Arrange-Act-Assert.
- Name tests: `it('should <expected> when <condition>')`.
Unconditional: always-on standards
# Code Style
- Prefer early returns over deep nesting.
- Extract magic numbers to named constants.
Combined: deployment safety (OR logic)
---
globs:
- '**/deploy/**'
- '**/*.tf'
keywords:
- 'terraform'
- 'kubernetes'
- 'production'
- 'rollback'
---
# Deployment
- Never hardcode secrets; use environment variables or a secrets manager.
- Include rollback steps in any production change plan.
1---2name: crafting-rules3description: Use when creating or modifying OpenCode rules (.md/.mdc files) that customize agent behavior. Helps extract patterns from conversation history, analyze project conventions (AGENTS.md, linters, package.json), and draft well-formatted rules with appropriate globs/keywords. Trigger when user wants to create a rule, codify repeated instructions, persist guidance across sessions, or customize agent behavior for specific files or topics.4---56# Crafting Rules78Rules are markdown files injected into the system prompt to guide agent behavior.910## Rule Format1112```md13---14globs:15 - '**/*.ts'16keywords:17 - 'vitest'18---1920# Rule Title2122- Write rules as concrete, actionable instructions.23```2425## Field Reference2627| Field | Type | Purpose |28| ---------- | ---------- | ----------------------------------------------------- |29| `globs` | `string[]` | Apply when any file in context matches a pattern |30| `keywords` | `string[]` | Apply when the user's latest prompt matches a keyword |3132- Both fields are optional; no frontmatter means the rule always applies.33- If both `globs` and `keywords` are present, matching is OR (either triggers).3435## Matching Strategy3637- Use `globs` when the rule is about code in specific files/directories.38- Use `keywords` when the rule is about a topic that may not include files.39- Use both when either condition should trigger.40- Use neither for global standards (tone, structure, safety, commit conventions).4142Important constraints:4344- Keyword matching is case-insensitive word-boundary _prefix_ matching (e.g., `test` matches `tests` and `testing`).45- You cannot express `globs AND keywords`; if you need that behavior, split into multiple rules.4647## Storage Location4849- `~/.config/opencode/rules/`: personal preferences you want across projects.50- `.opencode/rules/`: project/team conventions and repo-specific behavior.5152## Extracting Rules from Patterns5354Signals a pattern should become a rule:5556- Explicit: "always do X", "never do Y", "remember to...", "from now on..."57- Corrections: the user fixes the same agent behavior more than once58- Preferences: consistent style/process guidance (tests, commits, PRs, error handling)59- Frustration indicators: "I told you before", "again"6061Analysis questions:6263- Is this recurring, or a one-off for the current task?64- Does this apply to specific files, or all work?65- Is there an existing rule/config that already encodes this (AGENTS.md, lint config, Prettier, etc.)?66- Would this conflict with project conventions?6768Workflow:69701. Identify the behavioral delta (what should change?).712. Determine scope (globs, keywords, or always-on).723. Check existing rules/configs for overlap/conflict.734. Draft the minimal rule (one concept per rule when practical).745. Choose location (global vs project).7576Conversation extraction examples:7778- User: "Use early returns instead of nested if/else" -> always-on code style rule.79- User: "In unit tests, always use describe/it blocks" -> prefer glob-scoped rule (e.g., `**/*.{test,spec}.*`, `**/__tests__/**`); if prompt-scoped, use allowlisted keywords like `unit test`, `vitest`, `jest` (avoid `test`/`testing`).80- User repeatedly fixes import ordering -> glob-scoped rule for the relevant languages/files.8182## Keyword Selection Guidelines8384How matching works (important):8586- Keywords are matched with case-insensitive word-boundary prefix matching, so short/generic keywords tend to over-match.8788Denylist (avoid by default):8990- Generic nouns: `code`, `file`, `project`, `repo`, `bug`, `issue`, `change`91- Common verbs: `add`, `update`, `remove`, `fix`, `make`, `create`, `implement`92- Over-broad topic nouns: `testing`, `performance`, `security`, `deployment`, `database`, `api`93- Single-token abbreviations: `ci`, `cd`, `db`, `ui`, `ux`9495Allowlist (prefer by default):9697- Tool/framework names: `vitest`, `jest`, `pytest`, `playwright`, `cypress`, `eslint`, `prettier`, `typescript`, `terraform`, `kubernetes`98- Compound phrases: `unit test`, `integration test`, `snapshot test`, `lint rule`, `error boundary`, `api endpoint`, `rest api`99- High-intent engineering verbs: `refactor`, `rollback`, `migrate`, `deprecate`100101If you feel tempted to use a denylisted keyword:102103- Prefer globs (file-scoped) instead.104- Or replace it with a compound phrase / tool name that captures intent.105106Keyword audit checklist:107108- Would this keyword appear in prompts where the rule should NOT apply?109- Is it likely to appear as part of another word due to prefix matching?110- Can you scope via globs instead?111112## Writing Guidelines113114- Use imperative voice: "Do X", "Prefer Y", "Avoid Z".115- Make rules executable: instructions the agent can follow.116- Stay minimal: avoid restating generic best practices.117- Prefer examples over prose when a pattern is subtle.118119## Examples120121Glob-based: TypeScript conventions122123```md124---125globs:126 - '**/*.ts'127 - '**/*.tsx'128---129130# TypeScript131132- Prefer `type` over `interface` unless you need declaration merging.133- Avoid `any`; use `unknown` and narrow.134```135136Keyword-based: unit test guidance (allowlisted terms)137138```md139---140keywords:141 - 'unit test'142 - 'integration test'143 - 'vitest'144 - 'jest'145---146147# Unit Tests148149- Follow Arrange-Act-Assert.150- Name tests: `it('should <expected> when <condition>')`.151```152153Unconditional: always-on standards154155```md156# Code Style157158- Prefer early returns over deep nesting.159- Extract magic numbers to named constants.160```161162Combined: deployment safety (OR logic)163164```md165---166globs:167 - '**/deploy/**'168 - '**/*.tf'169keywords:170 - 'terraform'171 - 'kubernetes'172 - 'production'173 - 'rollback'174---175176# Deployment177178- Never hardcode secrets; use environment variables or a secrets manager.179- Include rollback steps in any production change plan.180```