A lightweight OpenCode plugin that discovers and injects markdown rule files into AI agent system prompts, enabling flexible behavior customization without per-project configuration.
opencode-rules automatically loads rule files from standard directories and integrates them into AI agent prompts, allowing you to:
- Define global coding standards that apply across all projects
- Create project-specific rules for team collaboration
- Apply conditional rules based on file patterns or prompt keywords
- Maintain zero-configuration workflow with sensible defaults
This approach allows you to dynamically include rules automatically like style guides for specific languages, guidance on specific actions, etc. Unlike skills, which are called on by the agent, rules use a simple matching approach.
- Dual-format support: Load rules from both
.mdand.mdcfiles - Conditional rules: Apply rules based on file paths using glob patterns or prompt keywords
- Keyword matching: Apply rules when the user's prompt contains specific keywords
- Global and project-level rules: Define rules at both system and project scopes
- Context-aware injection: Rules filtered by extracted file paths and user prompts
- Zero-configuration: Works out of the box with XDG Base Directory specification
- TypeScript-first: Built with TypeScript for type safety and developer experience
- Performance optimized: Efficient file discovery and minimal startup overhead
Add the plugin to your opoencode config:
{
"$schema": "https://opencode.ai/config.json",
"plugin": ["opencode-rules@latest"]
}-
Create the global rules directory:
mkdir -p ~/.config/opencode/rules -
Add a simple rule file:
cat > ~/.config/opencode/rules/coding-standards.md << 'EOF' # Coding Standards - Use meaningful variable names - Follow the project's code style guide - Write self-documenting code EOF
That's it! The rule will now be automatically injected into all AI agent prompts.
Rules are automatically discovered from these directories (including all subdirectories):
- Global rules:
$XDG_CONFIG_HOME/opencode/rules/(typically~/.config/opencode/rules/) - Project rules:
.opencode/rules/(in your project root)
Both directories are scanned recursively, allowing you to organize rules into subdirectories.
.md- Standard markdown files with optional metadata.mdc- Markdown files with optional metadata
Create ~/.config/opencode/rules/naming-convention.md:
# Naming Convention Rules
- Use camelCase for variables and functions
- Use PascalCase for classes and interfaces
- Use UPPER_SNAKE_CASE for constants
- Prefix private properties with underscoreCreate ~/.config/opencode/rules/typescript.mdc:
---
globs:
- '**/*.ts'
- '**/*.tsx'
---
# TypeScript Best Practices
- Always use `const` and `let`, avoid `var`
- Use interfaces for object types
- Add type annotations for function parameters
- Avoid `any` type without justification
- Enable strict mode in tsconfig.jsonThis rule only applies when processing TypeScript files.
Create ~/.config/opencode/rules/testing.mdc:
---
keywords:
- 'testing'
- 'unit test'
- 'jest'
- 'vitest'
---
# Testing Best Practices
- Write tests before implementing features (TDD)
- Use descriptive test names that explain the expected behavior
- Mock external dependencies
- Aim for high test coverage on critical pathsThis rule applies when the user's prompt mentions testing-related terms.
Create ~/.config/opencode/rules/test-files.mdc:
---
globs:
- '**/*.test.ts'
- '**/*.spec.ts'
keywords:
- 'testing'
---
# Test File Standards
- Use `describe` blocks to group related tests
- Use `it` or `test` with clear descriptions
- Follow AAA pattern: Arrange, Act, AssertThis rule applies when EITHER a test file is in context OR the user mentions testing (OR logic).
You can organize rules into subdirectories for better management. Rules are discovered recursively from all subdirectories:
~/.config/opencode/rules/
├── coding-standards.md # Always applied
├── typescript/
│ ├── general.md # TypeScript general rules
│ └── react.mdc # React-specific rules (conditional)
├── testing/
│ └── vitest.md # Testing guidelines
└── security/
└── api-keys.md # Security rules
Hidden directories (starting with .) are automatically excluded from discovery.
Create .opencode/rules/react-components.mdc in your project:
---
globs:
- 'src/components/**/*.tsx'
---
# React Component Guidelines
- Use functional components with hooks
- Export components as named exports
- Include PropTypes or TypeScript interfaces
- Use React.memo for expensive components
- Co-locate styles with componentsBoth .md and .mdc files support optional YAML metadata for conditional rule application:
---
globs:
- 'src/**/*.ts'
- 'lib/**/*.js'
keywords:
- 'refactoring'
- 'cleanup'
---globs(optional): Array of glob patterns for file-based matching- Rule applies when any file in context matches a pattern
keywords(optional): Array of keywords for prompt-based matching- Rule applies when the user's prompt contains any keyword
- Case-insensitive, word-boundary matching (e.g., "test" matches "testing")
- Does NOT match mid-word (e.g., "test" does NOT match "contest")
- No metadata: Rule applies unconditionally (always included)
- Only globs: Rule applies when any context file matches
- Only keywords: Rule applies when the user's prompt contains any keyword
- Both globs and keywords: Rule applies when EITHER condition matches (OR logic)
The plugin uses minimatch for pattern matching:
| Pattern | Matches |
|---|---|
src/**/*.ts |
All TypeScript files in src and subdirectories |
**/*.test.ts |
All test files at any depth |
src/components/**/*.tsx |
React components in components directory |
*.json |
JSON files in root directory only |
lib/{utils,helpers}/**/*.js |
JavaScript files in specific lib subdirectories |
This repository includes a crafting-rules/ skill that teaches AI agents how to create well-formatted rules. The skill provides:
- Rule format reference - Frontmatter fields (
globs,keywords) and markdown body structure - Matching strategy guidance - When to use globs vs keywords vs both vs neither
- Pattern extraction workflow - How to identify repeated conversation patterns that should become rules
- Keyword safety guidelines - Denylist of overly broad keywords to avoid, allowlist of safe alternatives, and an audit checklist
To use the skill, copy skills/crafting-rules/ to ~/.config/opencode/skills/ or reference it directly. The skill triggers when users ask to create rules, codify preferences, or persist guidance across sessions.
opencode-rules/
├── src/
│ ├── index.ts # Main plugin entry point
│ ├── utils.ts # File discovery and processing utilities
│ └── index.test.ts # Test suite
├── docs/
│ └── rules.md # Detailed usage documentation
├── openspec/ # Project specifications and proposals
└── dist/ # Compiled JavaScript output
# Install dependencies
bun install
# Run tests in watch mode
bun run test
# Run tests once
bun run test:run
# Build the project
bun run build
# Watch for changes and rebuild
bun run dev
# Format code
bun run format
# Lint code
bun run lint- TypeScript - Type-safe development
- @opencode-ai/plugin - OpenCode plugin framework
- Vitest - Fast unit testing
- Prettier - Code formatting
- ESLint - Linting and code quality
This plugin uses OpenCode's experimental transform hooks to inject rules into the LLM context:
-
experimental.chat.messages.transform- Fires before each LLM call- Extracts file paths from conversation messages (tool calls, text content)
- Stores paths for conditional rule filtering
- Does NOT modify messages
-
experimental.chat.system.transform- Fires after messages.transform- Reads discovered rule files
- Filters conditional rules (
.mdcwithglobs) against extracted file paths - Appends formatted rules to the system prompt
- No session tracking - Rules are injected fresh on every LLM call
- No compaction handling - System prompt is rebuilt automatically
- Cleaner injection - Rules in system prompt instead of conversation messages
- Context-aware filtering - Conditional rules only apply when relevant files are referenced
This plugin depends on experimental OpenCode APIs:
experimental.chat.messages.transformexperimental.chat.system.transform
These APIs may change in future OpenCode versions. Check OpenCode release notes when upgrading.
- Discovery: Scan global and project directories for
.mdand.mdcfiles - Parsing: Extract metadata from files with YAML front matter
- Messages Transform: Extract file paths from message content for context awareness
- Filtering: Apply conditional rules based on extracted file paths
- System Transform: Append filtered rules to the system prompt
- Fresh Injection: Rules are re-evaluated on every LLM call, ensuring always-current context
- Rule discovery performed once at plugin initialization
- Rule content cached with mtime-based invalidation for fast re-reads
- Efficient synchronous file operations during initialization
- Optimized glob matching with
minimatch - Session context deleted after use to prevent memory leaks
- Minimal memory footprint with efficient caching
To enable debug logging, set the OPENCODE_RULES_DEBUG environment variable:
OPENCODE_RULES_DEBUG=1 opencodeThis will log information about:
- Rule discovery (files found)
- Cache hits/misses
- Rule filtering (which rules are included/skipped)
- Verify directories exist:
~/.config/opencode/rules/and/or.opencode/rules/ - Check file extensions are
.mdor.mdc - Ensure files with metadata have properly formatted YAML
- Test glob patterns using the
fileMatchesGlobs()function
- Missing directories: Plugin gracefully handles missing directories
- Invalid YAML: Metadata parsing errors are logged but don't crash the plugin
- Pattern mismatches: Use relative paths from project root for glob patterns
We welcome contributions! Please:
- Fork the repository
- Create a feature branch
- Add tests for new functionality
- Ensure all tests pass:
bun run test:run - Format code:
bun run format - Submit a pull request
- Follow existing code style (Prettier configuration)
- Add comprehensive tests for new features
- Update documentation for API changes
- Use TypeScript for all new code