Plugs guide
Experimental feature. Plugs are functional but under active development. APIs may change. Most solo developers can skip this feature entirely.
Solo developer? You can skip this page unless you’re using rule Aligns that require project-specific values. Most solo workflows don’t need plugs.
Fills are set only in .aligntrue/config.yaml (IR fills are ignored).
Supported formats: command, text. file and url are deprecated and
treated as text. Sync fails if required plugs are missing.
Plugs provide template-based customization for rules that need different values across projects, stacks, or teams. Instead of forking rules to change test commands or file paths, you declare slots and fill them with project-specific values.
You need plugs when:
- You use Aligns that contain
[[plug:...]]template slots - You want to customize test commands or file paths across projects
- You need organization-wide metadata (company name, URLs) in rules
Real-world scenarios: See 3 complete examples below for test command customization, organization metadata, and stack-specific paths.
On this page: Quick Example · Declaring Slots · Providing Fills · Scenarios · Performance
Quick example
Rule with plug:
rules:
- id: testing.run-tests
summary: Run tests before committing
guidance: |
Run tests with: [[plug:test.cmd]]
applies_to: ["**/*"]
plugs:
slots:
test.cmd:
description: "Command to run the project's tests"
format: command
required: true
example: "pytest -q"Fill the slot:
aligntrue plugs set test.cmd "pnpm test"Result after sync:
Run tests with: pnpm testWhen to use plugs
Good use cases
- Test commands -
pytest,pnpm test,cargo test, etc. - File paths - Config files, documentation URLs, build outputs
- Project metadata - Author names, organization names, repository URLs
- Stack-specific values - Package managers, build tools, deployment targets
Not suitable for
- Check logic - Use overlays to adjust severity/inputs, or fork for logic changes
- Multi-line content - Plugs are single-line only
- Secret values - Don’t put secrets in fills (use environment variables at runtime)
- Computed values - Plugs are static strings, not expressions
Declaring slots
Slots define the template variables in your rules.
Slot structure
plugs:
slots:
<key>:
description: "One-line description"
format: command | text | file | url
required: true | false
example: "example value" # Recommended for required slotsFormat types
command
- Single-line shell command
- No environment variable interpolation (except
CI=true) - Examples:
pnpm test,cargo build --release
text
- Any single-line UTF-8 string
- Examples:
John Doe,Acme Corp,v1.0.0
file
- Repo-relative POSIX path
- No
..segments (parent directory traversal blocked) - No absolute paths
- Examples:
config/settings.json,docs/README.md
url
- Must start with
http://orhttps:// - Examples:
https://docs.example.com,https://github.com/org/repo
For concrete examples of these formats in action, see Scenarios.
Key naming rules
- Lowercase letters, numbers, dots, hyphens, underscores:
^[a-z0-9._-]+$ - Cannot start with
stack.orsys.(reserved) - Use dots for namespacing:
test.cmd,docs.url,author.name
Example declarations
plugs:
slots:
# Required command
test.cmd:
description: "Command to run tests"
format: command
required: true
example: "pytest -q"
# Optional URL
docs.url:
description: "Documentation website URL"
format: url
required: false
example: "https://example.com/docs"
# Required file path
config.file:
description: "Path to configuration file"
format: file
required: true
example: "config/settings.json"
# Optional text
author.name:
description: "Primary author name"
format: text
required: falseProviding fills
Fills provide the actual values for slots.
Fill sources (merge order)
Fills merge in this order (first source wins):
- Base align - Default fills from upstream
- Stack align(s) - Stack-specific defaults (e.g.,
nextjs-alignprovidestest.cmd: "pnpm test") - Repo-local - Your project’s fills (highest priority)
Setting fills
There are two ways to provide fills: via CLI commands or via configuration file.
Via CLI (recommended)
aligntrue plugs set <key> <value>Examples:
# Set test command
aligntrue plugs set test.cmd "pnpm test"
# Set author name
aligntrue plugs set author.name "Jane Smith"
# Set documentation URL
aligntrue plugs set docs.url "https://docs.example.com"
# Set config file path
aligntrue plugs set config.file "config/production.json"The CLI command validates the fill format and updates your .aligntrue/config.yaml file.
Via config file
You can also set fills directly in .aligntrue/config.yaml:
version: "1"
mode: solo
plugs:
fills:
test.cmd: "pnpm test"
author.name: "Jane Smith"
docs.url: "https://docs.example.com"
config.file: "config/production.json"
exporters:
- agents-md
- cursorConfig fills take precedence over IR fills, allowing you to override align defaults without modifying the align itself.
Removing fills
# Remove a fill
aligntrue plugs unset test.cmd
# Or edit config.yaml and remove the fill entryFill validation
AlignTrue validates fills against slot formats:
# Valid
aligntrue plugs set test.cmd "pnpm test" # ✓ Single-line command
# Invalid
aligntrue plugs set test.cmd "pnpm test && echo done" # ✗ Complex command with &&
aligntrue plugs set config.file "../secrets.json" # ✗ Parent directory traversal
aligntrue plugs set docs.url "example.com" # ✗ Missing http:// or https://Resolution algorithm
Plugs resolve during aligntrue sync before exporting to agents.
Resolution steps
- Normalize line endings - Convert CRLF/CR to LF
- Protect escapes - Temporarily replace
[[\plug:with sentinel - Resolve each plug:
- If fill exists → replace
[[plug:key]]with fill value - If required and no fill → insert TODO block
- If optional and no fill → replace with empty string
- If fill exists → replace
- Unescape literals - Restore
[[\plug:to[[plug: - Normalize output - Ensure single trailing LF
Resolution examples
Filled plug:
Input: Run tests with: [[plug:test.cmd]]
Fill: test.cmd: "pnpm test"
Output: Run tests with: pnpm testUnresolved required plug (with example):
Input: Run tests with: [[plug:test.cmd]]
Slot: required: true, example: "pytest -q"
Fill: (none)
Output: Run tests with: TODO(plug:test.cmd): Provide a value for this plug.
Examples: pytest -qUnresolved optional plug:
Input: Documentation: [[plug:docs.url]]
Slot: required: false
Fill: (none)
Output: Documentation:Escaped literal:
Input: Use [[\plug:key]] syntax for plugs
Output: Use [[plug:key]] syntax for plugsCLI commands
list - List slots and fills
aligntrue plugs listShows:
- All declared slots with descriptions and formats
- Current fill values
- Resolution status (filled, required, optional)
- Orphan fills (fills without slots)
- Summary statistics
Example output:
📌 Plugs List
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Slots declared:
test.cmd
Description: Command to run the project's tests
Format: command
Required: true
Example: pytest -q
Status: ✓ filled
Fill: pnpm test
docs.url
Description: Documentation website URL
Format: url
Required: false
Status: ○ optional
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Summary:
Total slots: 2
Required slots: 1
Filled required: 1resolve - Preview resolution
aligntrue plugs resolve [--dry-run]Previews plug resolution without writing changes. Shows resolved text and lists unresolved required plugs.
Example output:
✓ Resolved 2 plugs
Resolved text preview:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Run tests with: pnpm test
Documentation: https://docs.example.com
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Unresolved required plugs: 0validate - Check for errors
aligntrue plugs validateValidates plugs without writing changes. Fails fast on undeclared slots, missing required fills, or format errors; use it before aligntrue sync or in CI.
Example output:
✓ All plugs validExample failure:
✗ Plugs validation failed
- Missing required plug: test.cmd
- Undeclared plug reference: missing.keyset - Set fill value
aligntrue plugs set <key> <value>Sets a config-based fill with format validation.
Example:
aligntrue plugs set test.cmd "pnpm test"Output:
✓ Set plug fill: test.cmd = "pnpm test"
Run 'aligntrue sync' to apply the fillThe command validates the fill against the slot’s format (command, file, url, text) and updates .aligntrue/config.yaml.
Note:
plugs setis interactive-only and does not support--yes. Run it in a TTY instead of non-interactive scripts.
unset - Remove fill value
aligntrue plugs unset <key>Removes a config-based fill.
Example:
aligntrue plugs unset test.cmdOutput:
✓ Removed plug fill: test.cmd
Run 'aligntrue sync' to apply changesNote:
plugs unsetis also interactive-only (no--yes).
See CLI Reference for complete command documentation.
Scenario-based examples
Scenario 1: Solo developer with custom test command
Goal: Use shared TypeScript rules but customize test command for your project.
Setup:
# Pull upstream TypeScript align
sources:
- git: https://github.com/org/typescript-standards
ref: v1.0.0Upstream align includes:
rules:
- id: testing.run-before-commit
guidance: |
Run tests before committing: [[plug:test.cmd]]
plugs:
slots:
test.cmd:
description: "Command to run tests"
format: command
required: true
example: "pytest -q"Your customization:
# Set your project's test command
aligntrue plugs set test.cmd "pnpm test"
# Sync to agents
aligntrue syncResult: Rules use pnpm test instead of upstream’s pytest -q example.
Scenario 2: Team sharing stack-specific configs
Goal: Team uses shared base rules with stack-specific test commands.
Base align (shared):
# base-rules.yaml
rules:
- id: testing.run-tests
guidance: |
Run tests: [[plug:test.cmd]]
plugs:
slots:
test.cmd:
description: "Command to run tests"
format: command
required: trueStack align (Next.js team):
# nextjs-align.yaml
plugs:
fills:
test.cmd: "pnpm test" # Default for Next.js projectsStack align (Python team):
# python-align.yaml
plugs:
fills:
test.cmd: "pytest -q" # Default for Python projectsProject overrides (if needed):
# Override stack default for specific project
aligntrue plugs set test.cmd "pnpm test:ci"Merge order:
- Base align: declares slot
- Stack align: provides stack default
- Repo-local: overrides if needed
Scenario 3: Multi-stack monorepo
Goal: Different test commands per scope in monorepo.
Config:
scopes:
- path: "apps/web"
rulesets: ["base-rules", "nextjs-rules"]
- path: "services/api"
rulesets: ["base-rules", "python-rules"]
plugs:
fills:
# Global fills (used if scope doesn't override)
test.cmd: "pnpm test"Scope-specific fills:
# apps/web/.aligntrue/rules
plugs:
fills:
test.cmd: "pnpm test:web"
# services/api/.aligntrue/rules
plugs:
fills:
test.cmd: "pytest -q"Result: Each scope uses its own test command.
Scenario 4: Documentation URLs per project
Goal: Shared rules reference project-specific documentation.
Shared rule:
rules:
- id: docs.link-in-readme
summary: Link to documentation in README
guidance: |
Add documentation link to README: [[plug:docs.url]]
applies_to: ["README.md"]
plugs:
slots:
docs.url:
description: "Project documentation URL"
format: url
required: false # Optional - not all projects have docs
example: "https://docs.example.com"Project A:
aligntrue plugs set docs.url "https://docs.projecta.com"Project B (no docs yet):
# Don't set fill - optional plug resolves to empty stringResult:
- Project A: Guidance includes docs URL
- Project B: Guidance omits docs URL (empty string)
Troubleshooting
Unresolved required plugs
Problem: Sync fails with “Unresolved required plugs”
Solution:
# 1. Validate to see missing or undeclared plugs
aligntrue plugs validate
# 2. Set missing fills
aligntrue plugs set <key> <value>
# 3. Sync again
aligntrue syncFormat validation errors
Problem: Format validation failed: file
Solution: Check format requirements:
# Bad: Parent directory traversal
aligntrue plugs set config.file "../secrets.json" # ✗
# Good: Repo-relative path
aligntrue plugs set config.file "config/settings.json" # ✓
# Bad: Absolute path
aligntrue plugs set config.file "/etc/config.json" # ✗
# Good: Relative to repo root
aligntrue plugs set config.file "config/production.json" # ✓Orphan fills
Problem: plugs list or plugs validate shows “Fills without declared slots”
Cause: Fill exists but no slot declared (typo or removed slot)
Solution:
# Option 1: Fix typo in fill key
aligntrue plugs set correct.key "value"
# Option 2: Remove orphan fill
# Edit .aligntrue/rules and remove the fillMulti-line values
Problem: Need multi-line guidance with plug
Solution: Plugs are single-line only. Use multiple plugs or overlays:
# Bad: Multi-line plug (not supported)
guidance: |
[[plug:multi.line]]
# Good: Multiple single-line plugs
guidance: |
Step 1: [[plug:step.one]]
Step 2: [[plug:step.two]]
# Alternative: Use overlay to replace entire guidance
overlays:
overrides:
- selector: "rule[id=my-rule]"
set:
guidance: |
Custom multi-line
guidance hereEscaping plug syntax
Problem: Need to show [[plug:key]] literally in guidance
Solution: Use double backslash escape:
guidance: |
Use [[\plug:key]] syntax for plugsResult after resolution:
Use [[plug:key]] syntax for plugsDeterminism and hashing
Lock hash (pre-resolution)
Computed over canonicalized YAML before plug resolution:
# This YAML is hashed (with plugs unresolved)
rules:
- id: test
guidance: "Run: [[plug:test.cmd]]"
plugs:
slots:
test.cmd: { ... }
fills:
test.cmd: "pnpm test"Purpose: Detect changes to rule structure and plug declarations.
Export hash (post-resolution)
Computed over resolved text after plug resolution:
# This text is hashed (with plugs resolved)
Run: pnpm testPurpose: Detect changes to exported agent files.
Volatile fields
Fills are not volatile - they affect export hash. If you change a fill, the export hash changes.
Best practices
For rule authors
- Use recommended conventions - See Conventions Reference for standard plug keys
- Provide examples - Always include examples for required plugs
- Clear descriptions - One-line descriptions that explain the purpose
- Appropriate formats - Use the most restrictive format (command > file > text)
- Optional by default - Only mark as required if truly necessary
- Namespace keys - Use dots for organization:
test.cmd,docs.url,build.output
For solo developers
- Set fills early - Run
aligntrue plugs listafter init - Use stack Aligns - Let stack Aligns provide sensible defaults
- Override selectively - Only set fills when defaults don’t work
- Document decisions - Add comments in .aligntrue/rules explaining custom fills
For teams
- Share stack Aligns - Create org-specific stack Aligns with common fills
- Document required plugs - List required plugs in team onboarding docs
- Validate in CI - Run
aligntrue plugs listin CI to catch missing fills - Review fill changes - Treat fill changes like code changes (PR review)
- Avoid secrets - Never put secrets in fills (use env vars at runtime)
Scenarios
Real-world examples showing how to use plugs for project-specific customization:
- Test command customization - Different test runners per project
- Organization metadata - Company-specific values
- Stack-Specific Paths - Config file locations per stack
Test command customization
Problem: You’re using a shared rule align that references [[plug:test.cmd]] but your project uses a specific test runner. Some projects use pytest -q, others use pnpm test, and some use cargo test. You need to customize the test command without forking the align.
Solution: Use plugs to fill the test command slot with your project-specific value.
Configuration:
version: "1"
mode: solo
sources:
- type: local
path: "shared-align.yaml"
plugs:
fills:
test.cmd: "pnpm test"
build.cmd: "pnpm build"
lint.cmd: "pnpm lint"
exporters:
- agents-md
- cursorExpected outcome: The align references [[plug:test.cmd]] in rules, your project fills it with pnpm test, and exported rules contain the resolved command. No align forking required.
Keywords: test command, different test runners, pytest vs jest, custom test command, project-specific testing, test automation
Organization metadata
Problem: Your team uses shared rule Aligns that reference organization-specific metadata like company name ([[plug:org.name]]), documentation URL ([[plug:docs.url]]), support email ([[plug:support.email]]), and default author ([[plug:author.name]]). Each project needs to fill these with your organization’s values.
Solution: Use plugs to provide organization metadata that gets resolved across all rules.
Configuration:
version: "1"
mode: team
sources:
- type: local
path: "team-align.yaml"
plugs:
fills:
org.name: "Acme Corp"
docs.url: "https://docs.acme.com"
support.email: "support@acme.com"
author.name: "Acme Engineering Team"
repo.url: "https://github.com/acme/project"
exporters:
- agents-md
- cursorExpected outcome: Rules reference organization metadata via plugs, all projects use consistent values, easy to update across all projects, and no hardcoded company-specific values in Aligns.
Keywords: company name, organization URLs, author names, team metadata, company-specific values, organization branding
Stack-Specific Paths
Problem: Your shared rule align references configuration file paths like config file ([[plug:config.file]]), environment file ([[plug:env.file]]), and build output ([[plug:build.output]]). Different stacks use different locations: Next.js uses next.config.js, .env.local, .next/; Node.js uses config/default.json, .env, dist/; Python uses config.yaml, .env, build/.
Solution: Use plugs to specify stack-specific paths that match your project structure.
Configuration:
version: "1"
mode: solo
sources:
- type: local
path: "base-align.yaml"
- type: local
path: "nextjs-align.yaml"
plugs:
fills:
config.file: "next.config.js"
env.file: ".env.local"
build.output: ".next"
tsconfig.file: "tsconfig.json"
package.manager: "pnpm"
exporters:
- agents-md
- cursorExpected outcome: Rules reference file paths via plugs, each stack uses appropriate locations, no path assumptions in shared Aligns, and easy to adapt to different project structures.
Keywords: config file paths, stack-specific locations, different file locations, path customization, project structure, framework conventions
Performance characteristics
Plug resolution:
- O(n) where n = number of plugs (typically < 20)
- Resolved once during bundle merge, cached for exports
- No runtime overhead after resolution
- Validation happens at config load time
Memory usage:
- Minimal overhead: ~100 bytes per plug slot/fill
- Resolved values cached in memory during sync
- No impact on bundle or lockfile size
Best practices:
- Keep plug count under 50 for optimal performance
- Use descriptive keys for maintainability
- Validate format constraints early (command, file, url, text)
Common issues
”Plug references without slot definitions” error
What it means: The CLI found [[plug:...]] syntax in your rules, but the corresponding slot is not declared.
Why this happens:
- Slots must be declared in rule frontmatter YAML, not inline
- Typo in slot key (slot declared as
test.cmd, referenced astest_cmd) - Slot was removed but references remain
- Rule hasn’t been properly loaded into the IR
Fix:
- Check slot declaration - Verify your rule frontmatter includes the plugs section:
---
title: Your Rule
plugs:
slots:
test.cmd:
description: "Command to run tests"
format: command
required: true
example: "pytest -q"
---- Verify key spelling - Ensure referenced keys match declared keys exactly:
# Declared as:
plugs:
slots:
test.cmd: ...
# Reference must be:
Run tests: [[plug:test.cmd]] # ✓ Correct
# NOT:
Run tests: [[plug:test_cmd]] # ✗ Wrong - underscore instead of dot- Run sync - After fixing, sync to resolve the plugs:
aligntrue syncPlugs don’t resolve during aligntrue plugs list
What to expect: The aligntrue plugs list command shows status but does NOT resolve plugs yet. That happens during aligntrue sync.
Why: There are three separate operations:
aligntrue plugs list- Shows declared slots, fills, and statusaligntrue plugs resolve- Previews what resolution will look likealigntrue sync- Actually applies fills to rules and exports them
Workflow:
# 1. List to see what needs filling
aligntrue plugs list
# 2. Set missing fills
aligntrue plugs set test.cmd "pnpm test"
# 3. Preview resolution
aligntrue plugs resolve
# 4. Apply to agents
aligntrue syncFills aren’t persisting after aligntrue plugs set
Expected behavior: Fills persist to .aligntrue/config.yaml automatically.
If fills are missing:
- Check that set command succeeded:
aligntrue plugs set test.cmd "pnpm test"
# Should output: ✓ Set plug fill: test.cmd = "pnpm test"- Verify config file exists and is writable:
ls -la .aligntrue/config.yaml- Inspect config to see stored fills:
grep -A 5 "plugs:" .aligntrue/config.yaml- Run sync to apply:
aligntrue syncSlots defined in frontmatter but not recognized
Why this happens: Slots are defined in rule YAML frontmatter, but the rule file needs to be loaded into the IR for them to be available.
Workflow:
- Define slots in rule file:
# .aligntrue/rules/testing.md
---
title: Testing Standards
plugs:
slots:
test.cmd:
description: "Command to run tests"
format: command
required: true
---
## Run tests
Run tests with: [[plug:test.cmd]]- Run sync to load rules into IR:
aligntrue sync- Now slots are available:
aligntrue plugs list # Should show test.cmd slotRelated documentation
- Customization Overview - When to use plugs vs overlays vs scopes
- Overlays Guide - Modify rule properties without forking
- Scopes Guide - Apply different rules per directory
- CLI Reference - Complete command docs
- Solo Developer Guide - Solo workflow with plugs
- Team Guide - Team collaboration with plugs