Imported from renan-garcia/agent-rules-skill (
SKILL.md). Install upstream withnpx skills add renan-garcia/agent-rules-skill. Copyright stays with the author.
agent-rules-skill
Bootstrap and migration of vendor-neutral AI agent configuration for any project.
When to use
- Project has no agent configuration at all
- Project has only
.cursor/rules/*.mdc(Cursor-only) - Project has only a monolithic
.cursorrulesfile - Project has only
.claude/(Claude Code-only) - Project has only
.codex/(Codex-only) - Project has only
.opencode//opencode.json(opencode-only) - Migrating to multi-platform support from any single-platform setup
Scope constraint — migrate only, never invent
This skill migrates and restructures configuration that already exists. It must NOT generate, infer, or fetch new rule content. In particular:
- Do not author rules the source config did not already contain.
- Do not fetch or embed third-party library/framework documentation (e.g.
pulling TanStack Router, React, or any library docs from the web,
context7,node_modules, or training memory) as project rules. - Do not expand a short source file into extra rules beyond the themes that are literally present in it.
- When the source is empty or missing (Case A), ask the user for the content instead of inventing conventions.
The only transformation allowed is reorganizing existing content across the canonical format and adapters. If you think a rule is missing, surface it as a suggestion to the user — do not write it yourself.
The output rule set must be traceable 1:1 to the source: every .agents/rules/*.md
must correspond to content that existed in the input. If it cannot be traced to
the source, it does not belong.
Step 1 — Inventory the project
Before creating any file, read what already exists:
AGENTS.md → existing portable entrypoint?
CLAUDE.md → proxy pointing to AGENTS.md or own content?
.cursorrules → legacy monolithic Cursor rules?
.cursor/rules/*.mdc → organized Cursor rules?
.cursor/agents/*.md → Cursor subagents?
.cursor/hooks.json → Cursor hooks?
.claude/rules/*.md → Claude Code rules?
.claude/agents/*.md → Claude Code subagents?
.claude/settings.json → Claude Code hooks?
.codex/agents/*.toml → Codex subagents?
.codex/hooks.json → Codex hooks?
.opencode/agents/*.md → opencode subagents?
opencode.json → opencode config (instructions, plugins)?
.agents/ → canonical source already exists?
If .agents/ already exists with rules and agents, the project is already using
this architecture. Just run bin/sync-agent-config to regenerate adapters.
Step 2 — Detect origin and migrate
Case A: No configuration
Ask the user:
- Project stack (language, framework, test suite, linter)
- Key commands (run tests, run linter, build, CI)
- Mandatory workflow (are there strong code structure rules?)
With the answers, create .agents/ from scratch as described in Step 3.
Case B: Monolithic .cursorrules
Read the entire file and split by theme/area into separate rules:
- Identify rule groups by folder/scope (
app/models,spec/, etc.) - Each group becomes a
.agents/rules/<theme>.mdwith aglobs:frontmatter - Global rules without a scope →
.agents/rules/core.mdwithalwaysApply: true - Keep the original file until the sync is confirmed to be working
Split only — do not add. Every resulting rule must be a slice of the original
.cursorrules text. Do not enrich the split with library documentation, examples,
or best-practices the file did not contain (see "Scope constraint" above).
Case C: Existing .cursor/rules/*.mdc
For each .mdc file:
- Read frontmatter (
description,globs,alwaysApply) - Create
.agents/rules/<basename>.mdwith canonical frontmatter - Body content is identical
Canonical frontmatter (.agents/rules/):
---
description: Brief description of the rule scope
alwaysApply: true # or false
globs: app/models/**/*.rb # omit if alwaysApply: true
---
Case D: Existing .claude/rules/*.md
Same logic as Case C — Claude frontmatter uses paths: instead of globs:.
Convert:
# Claude (source) → Canonical (.agents/rules/)
paths: [app/models/**] → globs: app/models/**
Case E: Existing .codex/agents/*.toml
For each .toml:
- Extract
name,description,sandbox_mode,developer_instructions - Create
.agents/agents/<name>.md:--- name: <name> description: <description> model: <suggested-model> readonly: true # if sandbox_mode == "read-only" --- <developer_instructions> - If the
.tomlhad Codex-specific runtime notes (asdf, docker, etc.):- Extract that section
- Create
.agents/adapters/codex/agents/<name>.mdwith the Codex-specific content - Remove it from the main body
Case F: Existing .claude/agents/*.md
Read Claude frontmatter (tools, disallowedTools) and convert:
disallowedTools: Write, Edit, MultiEdit→readonly: truein canonical- Everything else follows the canonical format
Case G: Existing .opencode/agents/*.md or opencode.json
For each .opencode/agents/*.md:
- Read frontmatter (
description,model,mode,tools) - Create
.agents/agents/<name>.md; iftoolsdisableswrite/edit, setreadonly: true - Body content is identical
If opencode.json has an instructions array pointing to rule files, migrate those
files into .agents/rules/ (global ones as alwaysApply: true).
Step 3 — Create the .agents/ structure
Required directories
mkdir -p .agents/rules
mkdir -p .agents/agents
mkdir -p .agents/adapters/cursor/rules
mkdir -p .agents/adapters/cursor/agents
mkdir -p .agents/adapters/claude/rules
mkdir -p .agents/adapters/claude/agents
mkdir -p .agents/adapters/codex/rules
mkdir -p .agents/adapters/codex/agents
mkdir -p .agents/adapters/opencode/rules
mkdir -p .agents/adapters/opencode/agents
mkdir -p .agents/hooks
README files
Copy templates/agents-README.md from the package to .agents/README.md.
Copy templates/adapters-README.md to .agents/adapters/README.md.
Canonical rules
Each file at .agents/rules/<name>.md:
---
description: <objective description of the scope>
alwaysApply: false
globs: <glob pattern, e.g. app/models/**/*.rb>
---
# <Area Title>
<Rule content>
For global rules:
---
description: Core project conventions and global standards
alwaysApply: true
---
See examples/rule-core.md and examples/rule-scoped.md in the package for reference.
Canonical agents
Each file at .agents/agents/<name>.md:
---
name: <kebab-case-name>
description: <when to invoke, 1-2 sentences>
model: <claude-sonnet-4-5 | composer-2.5-fast | etc>
readonly: true # omit if the agent can edit files
---
<Agent instructions>
See examples/agent-code-reviewer.md in the package for reference.
Linter hook (if the project has a linter)
Copy templates/hook-linter.sh.template to .agents/hooks/linter-autocorrect.sh.
Edit LINT_CMD and FILE_EXTENSIONS for the project's linter:
| Language | LINT_CMD | FILE_EXTENSIONS |
|---|---|---|
| Ruby | bundle exec rubocop --autocorrect --force-exclusion |
rb |
| TypeScript/JS | npx eslint --fix |
ts|tsx|js|jsx |
| Python | black |
py |
| Go | gofmt -w |
go |
Worktrees (optional, Cursor only)
If the project requires worktree setup, create .agents/worktrees.json:
{
"setup-worktree-unix": ["<command 1>", "<command 2>"],
"setup-worktree": ["<command 1 for Windows/cross-platform>"]
}
Step 4 — Create AGENTS.md
Copy templates/AGENTS.md.template to AGENTS.md at the project root.
Fill in the TODO sections with real project information:
- Project Stack — language, framework, test suite, database, etc.
- Commands — real test, lint, CI commands
- Mandatory Workflow — project-specific process rules
- Rule Index — list the rules created in
.agents/rules/ - Specialized Agents — list the agents created in
.agents/agents/
Step 5 — Install the sync script and automations
bin/sync-agent-config ships in three behaviourally identical ports: the Ruby
reference (sync-agent-config), a Node port (sync-agent-config.js), and a
Python 3 port (sync-agent-config.py). The bun runtime reuses the Node port,
with the shebang pointed at bun. Copy the one matching the runtime saved by
the installer in ~/.config/agent-rules-skill/config.json (falls back to the
Ruby reference when unset):
# runtime → template: ruby=sync-agent-config, node|bun=sync-agent-config.js, python=sync-agent-config.py
runtime="$(python3 -c 'import json,os,sys;print(json.load(open(os.path.expanduser("~/.config/agent-rules-skill/config.json"))).get("runtime","ruby"))' 2>/dev/null || echo ruby)"
case "$runtime" in
node|bun) src=sync-agent-config.js; upd=sync-agent-update.js ;;
python) src=sync-agent-config.py; upd=sync-agent-update.py ;;
*) src=sync-agent-config; upd=sync-agent-update ;;
esac
cp "<package>/templates/$src" bin/sync-agent-config
cp "<package>/templates/$upd" bin/sync-agent-update
if [ "$runtime" = "bun" ]; then
# Hooks execute the scripts directly, so the shebang must call bun.
sed -i.bak '1s|env node|env bun|' bin/sync-agent-config && rm -f bin/sync-agent-config.bak
sed -i.bak '1s|env node|env bun|' bin/sync-agent-update && rm -f bin/sync-agent-update.bak
fi
chmod +x bin/sync-agent-config bin/sync-agent-update
The destination is always bin/sync-agent-config; the copied file's shebang
selects the interpreter. All ports accept --platforms / --check and read the
same installer preferences automatically.
To refresh the executables of an already-bootstrapped project after the skill
is upgraded, run <package>/update.sh <project-path> — it re-copies
bin/sync-agent-config, bin/sync-agent-update (honoring the configured
runtime; installed when missing) and .agents/hooks/sync-on-edit.sh without
touching any project source.
bin/sync-agent-update does the same directly from GitHub — no local skill
needed: it pins the repo's latest release (or --ref <tag|branch>), verifies
downloads against the release's SHA256SUMS when published, lists the changes
and asks a y/n confirmation before writing (EOF answers n, so nothing is ever
applied silently). State is recorded under the update namespace of
bin/sync-agent-config-options.json.
When an adapter's canonical source is deleted, the next sync offers to remove
each stale generated file with a y/n/a/i/q prompt (y remove, n keep,
a remove all remaining, i ignore this file forever, q keep all
remaining). On a TTY a single keypress answers — no Enter needed,
case-insensitive; invalid keys re-prompt. Ignored files are persisted in
bin/sync-agent-config-options.json under the prune.ignored namespace (the
file is namespaced by feature so future options can live alongside) and are
skipped by both the prompt and --check. Non-interactive runs (hooks, CI) read
EOF as q, so nothing is ever deleted silently; --check lists stale files as
drift instead.
Auto-sync hook (all platforms)
Copy the hook that detects edits to .agents/** and triggers sync automatically:
cp <package>/templates/sync-on-edit.sh .agents/hooks/sync-on-edit.sh
chmod +x .agents/hooks/sync-on-edit.sh
The sync-agent-config script automatically includes it in all platform configs:
| Platform | Config file | Trigger |
|---|---|---|
| Cursor | .cursor/hooks.json |
afterFileEdit |
| Claude Code | .claude/settings.json |
PostToolUse (Write/Edit/MultiEdit) |
| Codex | .codex/hooks.json |
PostToolUse (Edit/Write/apply_patch) |
The hook reads the edited file path from the JSON payload, checks if it is under
.agents/, and silently exits for any other file — so it never blocks unrelated edits.
Git pre-commit hook (drift guard)
Install to block commits when adapters are out of sync:
cp <package>/templates/pre-commit .git/hooks/pre-commit
chmod +x .git/hooks/pre-commit
The hook only runs the check when a .agents/** file is staged — it has no impact
on commits that do not touch agent config.
Step 6 — Run the sync
bin/sync-agent-config
This generates:
.cursor/rules/*.mdc+.cursor/agents/*.md+.cursor/hooks.json(if cursor).claude/rules/*.md+.claude/agents/*.md+.claude/settings.json+CLAUDE.md(if claude).codex/agents/*.toml+.codex/hooks.json(if codex).opencode/rules/*.md+.opencode/agents/*.md+opencode.json(if opencode)
To generate only specific platforms:
bin/sync-agent-config --platforms cursor,claude
To verify that generated adapters are in sync with .agents/:
bin/sync-agent-config --check
Step 7 — Clean up old configs
After confirming the sync works and adapters are generated correctly:
- Remove
.cursorrulesif its content has been migrated to.agents/rules/ - Files under
.cursor/,.claude/,.codex/are generated — do not edit manually
Day-to-day maintenance
| Action | Where to edit | Command |
|---|---|---|
| New rule | .agents/rules/<name>.md |
bin/sync-agent-config |
| New subagent | .agents/agents/<name>.md |
bin/sync-agent-config |
| Cursor-only overlay | .agents/adapters/cursor/... |
bin/sync-agent-config |
| Claude-only overlay | .agents/adapters/claude/... |
bin/sync-agent-config |
| Codex-only overlay | .agents/adapters/codex/... |
bin/sync-agent-config |
| opencode-only overlay | .agents/adapters/opencode/... |
bin/sync-agent-config |
| Check for drift | — | bin/sync-agent-config --check |
Golden rule: always edit .agents/** — never touch the generated adapters.
Reference: frontmatter mapping by platform
Rules
| Canonical field | Cursor (.mdc) |
Claude (.md) |
opencode |
|---|---|---|---|
description |
description |
description |
— (body only) |
alwaysApply: true |
alwaysApply: true |
(no paths:) |
body → .opencode/rules/, referenced by opencode.json instructions |
alwaysApply: false + globs: |
globs: <value> + alwaysApply: false |
paths: [<value>] |
same as above (no per-glob activation; always included) |
Codex has no rule files — global conventions live in AGENTS.md, which Codex reads natively.
Agents
| Canonical field | Cursor (.md) |
Claude (.md) |
Codex (.toml) |
opencode (.md) |
|---|---|---|---|---|
name |
frontmatter directly | name |
name = "..." |
(filename) |
description |
description |
description |
description = "..." |
description |
model |
model |
model: sonnet (readonly) or inherit |
— | model |
readonly: true |
readonly: true |
tools: Read,Grep,Glob,Bash + disallowedTools |
sandbox_mode = "read-only" |
tools: { write: false, edit: false } |
| (mode) | — | — | — | mode: subagent |
| body | directly | directly | developer_instructions = '''...''' |
directly |
Expected final structure
<project>/
├── AGENTS.md ← portable entrypoint
├── CLAUDE.md ← generated (points to AGENTS.md)
├── bin/
│ └── sync-agent-config ← sync script
├── .agents/
│ ├── README.md
│ ├── rules/
│ │ ├── core.md ← alwaysApply: true
│ │ └── <area>.md ← specific globs
│ ├── agents/
│ │ └── <name>.md
│ ├── adapters/
│ │ ├── cursor/
│ │ ├── claude/
│ │ ├── codex/
│ │ └── opencode/
│ └── hooks/
│ ├── sync-on-edit.sh ← auto-sync on .agents/** edit
│ └── linter-autocorrect.sh
├── .cursor/ ← generated
├── .claude/ ← generated
├── .codex/ ← generated
├── .opencode/ ← generated (rules/, agents/)
└── opencode.json ← generated/merged (instructions)