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
globsandkeywordsare present, matching is OR (either triggers).
Matching Strategy
- Use
globswhen the rule is about code in specific files/directories. - Use
keywordswhen 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.,
testmatchestestsandtesting). - 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 likeunit test,vitest,jest(avoidtest/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.