agents
AGENTS.md102 starsChanged 2 months agoApache-2.0View on GitHub
Instructions for AI coding agents working on the @agents-dev/cli project. @agents-dev/cli is a CLI tool that provides a practical standard layer for multi-LLM development. It solves the configuration fragmentation problem by syncing MCP servers, skills and instructions across 18 AI coding tools from a single source of truth, and packages the result as an Agent Plugins bundle. Key Principle: One .agents/ folder syncs to all tools. Add an MCP server once, it appears everywhere. Projects have: - .agents/agents.json — MCP…
- Installs packages
- Commits and pushes
Where files are headingNew AGENTS.md files have more rules about keeping secrets out of the code, and fewer about code style.
Of the AGENTS.md files we read, the 31,542 first seen in the last six months, against the older ones: the kind of rule that gained most share, and the kind that lost most. About files like this in general, not this one, and an estimate, since a kind is a pattern in the words.
In this repository3 other files it gives its agents.
- docs-researchSkill
- mcp-troubleshootingSkill
- skill-guideSkill
The file
Show its rules and text
We split this AGENTS.md into the rules it gives an agent
46 rules. About 1 is common, 28 are distinctive, and 17 are very specific to this project.
≈1
Common · estimate
Many files like this have a rule of this kind.
≈28
Distinctive · estimate
This author's own choices. Worth a look.
17
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 77
Unit tests: Test individual functions in isolation
- Distinctive: line 78
Integration tests: Test full command flows with temp directories
- Very specific: line 79
Use mkdtemp for temporary test directories
- Very specific: line 80
Always clean up in afterEach hooks
- Distinctive: line 86
Follow existing patterns and conventions
- Distinctive: line 87
Use descriptive variable names
- Distinctive: line 88
Add JSDoc comments for exported functions
- Distinctive: line 89
Keep functions focused (single responsibility)
- Distinctive: line 90
Prefer pure functions where possible
- Very specific: line 105
Read .agents/agents.json and .agents/local.json
- Distinctive: line 108
Write atomically (temp file + rename)
- Distinctive: line 148
Read the section with a line scan, so a syntax error elsewhere does not hide it
- Distinctive: line 152
Never reserialize the whole config: it carries comments and settings we do not own
- Distinctive: line 157
Write to temp file
- Very specific: line 168
Add tests in tests/your-command.test.ts
- Distinctive: line 169
Update README.md command reference
- Very specific: line 180
Add renderer in src/core/renderers.ts
- Very specific: line 181
Add the paths it needs in src/core/paths.ts
- Very specific: line 187
Add a sync hook in src/integrations/syncHooks.ts
- Very specific: line 188
Add the skills bridge to SKILL_BRIDGES in src/core/skills.ts, or set nativeSkills when the tool reads .agents/skills itself
- Distinctive: line 191
Update README supported tools table
- Distinctive: line 195
Write a failing test that reproduces the bug
- Distinctive: line 198
Add edge case tests
- Distinctive: line 199
Update CHANGELOG.md (## Unreleased > ### Fixed)
- Distinctive: line 204
Write tests for new behavior
- Distinctive: line 207
Update CHANGELOG.md (## Unreleased > ### Added)
- Very specific: line 249
Use src/core/ui.ts for all user-facing output:
- Very specific: line 276
Never use raw console.log() for user-facing output
- Very specific: line 277
Use ui.spin() for any operation > 500ms
- Distinctive: line 334
If a test is flaky (timing-dependent):
- Distinctive: line 336
Add retry logic if appropriate
- Distinctive: line 347
Create GitHub release with tag
- Very specific: line 365
Always use afterEach to clean up, or tests will leave garbage in /tmp.
- Distinctive: line 390
Check if CLI is installed before calling:
- Common: line 402
Never log secrets to console
- Very specific: line 403
Use --secret-env and --secret-header flags for sensitive values
- Distinctive: line 405
Don't execute arbitrary code from config files
- Very specific: line 409
Use sync --check for drift detection (faster than full sync)
- Very specific: line 410
Use status --fast to skip slow external CLI probes
- Very specific: line 412
Use Promise.all() for parallel operations
- Distinctive: line 417
Keep README.md concise (high-level overview)
- Very specific: line 418
Put details in docs/ files
- Distinctive: line 419
Use code examples for clarity
- Distinctive: line 447
Check existing code for patterns
- Distinctive: line 448
Read tests for examples
- Distinctive: line 449
Ask in GitHub Discussions
≈ “Common” is an estimate: at least 1 in 5 of the 40,246 AGENTS.md files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
AGENTS.md
Instructions for AI coding agents working on the @agents-dev/cli project.
Project Overview
@agents-dev/cli is a CLI tool that provides a practical standard layer for multi-LLM development. It solves the configuration fragmentation problem by syncing MCP servers, skills and instructions across 18 AI coding tools from a single source of truth, and packages the result as an Agent Plugins bundle.
Key Principle: One .agents/ folder syncs to all tools. Add an MCP server once, it appears everywhere.
Tech Stack
- Language: TypeScript (strict mode)
- Runtime: Node.js 20.12+
- Build: tsc (TypeScript compiler)
- Tests: Vitest
- CLI Framework: Commander.js
- Prompts: @clack/prompts
- Package Manager: npm
Project Structure
agents/
├── src/
│ ├── cli.ts # CLI entry point
│ ├── commands/ # Command implementations
│ │ ├── start.ts # Setup wizard
│ │ ├── sync.ts # Config sync
│ │ ├── mcp-add.ts # Add MCP server
│ │ └── ...
│ ├── core/ # Core logic
│ │ ├── sync.ts # Sync orchestration
│ │ ├── mcp.ts # MCP management
│ │ ├── renderers.ts # Tool-specific config generators
│ │ ├── trust.ts # Codex trust management
│ │ ├── ui.ts # CLI output helpers (colors, spinners)
│ │ └── ...
│ ├── integrations/ # Tool integrations
│ │ ├── codex.ts
│ │ ├── claude.ts
│ │ ├── cursor.ts
│ │ └── ...
│ └── types.ts # TypeScript types
├── tests/ # Test files
│ ├── *.test.ts # Unit tests
│ └── *.integration.test.ts # Integration tests
├── templates/ # Scaffold templates
│ └── agents/ # .agents/ directory templates
├── docs/ # Public documentation
└── bin/agents # CLI wrapper scriptDevelopment Workflow
Setup
npm install
npm run build
npm linkDevelopment Commands
npm run dev -- <command> # Run CLI in dev mode
npm run build # Compile TypeScript
npm test # Run all tests
npm test tests/sync.test.ts # Run specific test
npm test -- --watch # Watch mode
npm run lint # Run ESLintTesting
- Unit tests: Test individual functions in isolation
- Integration tests: Test full command flows with temp directories
- Use
mkdtempfor temporary test directories - Always clean up in
afterEachhooks - Mock external CLI calls when appropriate
Code Style
- TypeScript strict mode is enabled
- Follow existing patterns and conventions
- Use descriptive variable names
- Add JSDoc comments for exported functions
- Keep functions focused (single responsibility)
- Prefer pure functions where possible
Key Concepts
1. Project Structure (core/project.ts)
Projects have:
.agents/agents.json— MCP servers, shared config.agents/local.json— Secrets (gitignored).agents/skills/— Reusable workflows.agents/generated/— Auto-generated files (gitignored)AGENTS.md— Instructions for all tools
2. Sync Process (core/sync.ts)
- Read
.agents/agents.jsonand.agents/local.json - Merge configs (local overrides shared)
- Generate tool-specific configs via renderers
- Write atomically (temp file + rename)
- Acquire sync lock to prevent race conditions
3. Renderers (core/renderers.ts)
Each tool has a renderer that converts .agents/agents.json to tool-specific format:
- Codex: TOML (
.codex/config.toml) - Claude Code: JSON (
.mcp.json, project scope, shared with Copilot CLI) - Gemini: JSON (
.gemini/settings.json) - Cursor: JSON (
.cursor/mcp.json) - Copilot VS Code: JSON (
.vscode/mcp.json) - Antigravity: JSON (
.agents/mcp_config.json) - Grok Build: TOML (
.grok/config.toml), same dialect as Codex with aheaderstable - Amp: JSON (
.amp/settings.json, keyamp.mcpServers) - Droid / Devin: JSON (
.factory/mcp.json,.devin/mcp_config.json) - Kilo: JSONC (
.kilo/kilo.jsonc, keymcp) - Zed: JSONC (
.zed/settings.json, keycontext_servers) - Goose: YAML (
~/.config/goose/config.yaml, keyextensions)
Two renderers are shared: Codex and Grok use renderMcpToml with different options,
OpenCode and Kilo use the same local/remote shape.
4. MCP Server Management (core/mcp.ts)
MCP servers have:
- Transport:
stdio(command-based) orhttp/sse(URL-based).sseis deprecated by the MCP 2026-07-28 specification and flagged byagents doctor. - Config: command, args, env, headers, cwd, plus the optional
timeout,connectTimeout,tools,disabledTools,oauth,headersHelper,bearerTokenEnvVarandenvFile, each rendered only where the tool supports it - Secrets: Stored in
.agents/local.json, never exported into a plugin - Validation: Keys must be shell-safe (env) or HTTP token format (headers)
- Profiles:
profilesandactiveProfileselect a subset of servers for a sync
5. Trust Management (core/trust.ts)
Codex ignores a project-local .codex/config.toml unless the project is trusted, and
there is no codex trust command to do it. Trust lives in the [projects."<path>"]
section of the global ~/.codex/config.toml, which we edit in place:
- Read the section with a line scan, so a syntax error elsewhere does not hide it
- Refuse to touch a file Codex itself cannot parse;
agents doctorreports the error - Refuse to append when the project is recorded in another valid TOML shape, which would create a duplicate key and break the file
- Never reserialize the whole config: it carries comments and settings we do not own
6. File Safety (core/fs.ts)
Critical operations use atomic writes:
- Write to temp file
- Rename to target (atomic on most filesystems)
- Prevents data corruption if process crashes
Common Tasks
Adding a New Command
- Create
src/commands/your-command.ts - Export async function matching command signature
- Register in
src/cli.tswith Commander - Add tests in
tests/your-command.test.ts - Update README.md command reference
- Update CHANGELOG.md
Adding a New Tool Integration
Before writing code: confirm the config path and schema in the vendor's own documentation, and run the tool's CLI against a generated file if it is installed. Integrations verified that way are marked in the README table; the rest say so.
- Create
src/integrations/your-tool.ts - Implement integration interface (id, name, paths)
- Add renderer in
src/core/renderers.ts - Add the paths it needs in
src/core/paths.ts - Register in
src/integrations/registry.ts, including theconfigdescriptor: the path key, the format and the label.status,doctor,resetandstartread the descriptor, so this is the only place that list lives. A tool whose file depends on an option or the platform has no descriptor and is handled where that choice is made — add it toWITHOUT_DESCRIPTORintests/integration-registry.test.tswith the reason. - Add a sync hook in
src/integrations/syncHooks.ts - Add the skills bridge to
SKILL_BRIDGESinsrc/core/skills.ts, or setnativeSkillswhen the tool reads.agents/skillsitself - Add tests
- Update README supported tools table
Fixing a Bug
- Write a failing test that reproduces the bug
- Fix the bug
- Verify test passes
- Add edge case tests
- Update CHANGELOG.md (## Unreleased > ### Fixed)
Adding a Feature
- Discuss in GitHub issue first (if major)
- Write tests for new behavior
- Implement feature
- Update documentation
- Update CHANGELOG.md (## Unreleased > ### Added)
Important Patterns
Error Handling
// Throw descriptive errors
throw new Error(`MCP server "${name}" not found in .agents/agents.json`)
// User-facing errors should be clear and actionable
console.error(`Error: Invalid env key "${key}". Use format: [A-Za-z_][A-Za-z0-9_]*`)
process.exitCode = 1File Operations
// Always use atomic writes for critical files
import { writeJsonAtomic } from './core/fs.js'
await writeJsonAtomic(path, data)External CLI Calls
// Use spawnSync for external commands
import { spawnSync } from 'node:child_process'
const result = spawnSync('codex', ['trust', 'list'], {
encoding: 'utf-8',
stdio: ['ignore', 'pipe', 'pipe']
})
if (result.status !== 0) {
// Handle error
}CLI Output (UI Module)
Use src/core/ui.ts for all user-facing output:
import { ui } from './core/ui.js'
// Status messages
ui.success('Config synced')
ui.error('Failed to connect')
ui.warning('Server not responding')
ui.info('Checking configuration...')
// Formatted output
ui.keyValue('Status', 'connected')
ui.list(['item1', 'item2'])
ui.section('MCP Servers')
ui.hint('Run `agents sync` to apply changes')
// Spinners for async operations
const result = await ui.spin('Syncing...', async () => {
return await doAsyncWork()
})
// Context-aware (respects --json, --quiet, NO_COLOR)
ui.json(data) // Only outputs if --json flag is setRules:
- Never use raw
console.log()for user-facing output - Use
ui.spin()for any operation > 500ms - Colors are minimal: green (success), red (error), yellow (warning), cyan (info)
- Unicode symbols have ASCII fallbacks for non-Unicode terminals
Temp Directories in Tests
import { mkdtemp, rm } from 'node:fs/promises'
import { join } from 'node:path'
import { tmpdir } from 'node:os'
describe('my test', () => {
const tempDirs: string[] = []
afterEach(async () => {
await Promise.all(tempDirs.map(dir => rm(dir, { recursive: true, force: true })))
tempDirs.length = 0
})
it('does something', async () => {
const dir = await mkdtemp(join(tmpdir(), 'agents-test-'))
tempDirs.push(dir)
// test logic
})
})Testing Guidelines
What to Test
- ✅ All public functions
- ✅ Error conditions
- ✅ Edge cases (empty arrays, null values, etc.)
- ✅ Integration flows (full command execution)
- ✅ File I/O (read/write operations)
- ❌ Don't test third-party libraries
Test Structure
describe('feature', () => {
it('should do X when Y', () => {
// Arrange
const input = { ... }
// Act
const result = myFunction(input)
// Assert
expect(result).toBe(expected)
})
})Flaky Tests
If a test is flaky (timing-dependent):
- Increase timeout:
it('test', { timeout: 10000 }, async () => { ... }) - Add retry logic if appropriate
- Mock external dependencies that cause flakiness
Release Process
(For maintainers only - see .docs-internal/PUBLISHING.md)
- Update CHANGELOG.md
- Bump version:
npm version patch|minor|major - Build and test:
npm run build && npm test - Publish:
npm publish --access public - Create GitHub release with tag
Common Pitfalls
1. Forgetting Atomic Writes
Wrong:
await writeFile(path, JSON.stringify(data))Right:
await writeJsonAtomic(path, data)2. Not Cleaning Up Temp Dirs in Tests
Always use afterEach to clean up, or tests will leave garbage in /tmp.
3. Hardcoding Paths
Wrong:
const codexConfig = '/Users/me/.codex/config.toml'Right:
import { getCodexConfigPath } from './core/paths.js'
const codexConfig = getCodexConfigPath()4. Not Validating User Input
Always validate:
- MCP server names (no spaces, special chars)
- Env keys (shell-safe format)
- Header keys (HTTP token format)
- File paths (absolute, not relative)
5. Assuming External CLIs Are Available
Check if CLI is installed before calling:
const result = spawnSync('codex', ['--version'], { encoding: 'utf-8' })
if (result.status !== 0) {
console.warn('Codex CLI not found. Skipping Codex integration.')
return
}Security Considerations
- Secrets are stored in
.agents/local.json(gitignored) - Never log secrets to console
- Use
--secret-envand--secret-headerflags for sensitive values - Validate all user input (especially paths and shell commands)
- Don't execute arbitrary code from config files
Performance Tips
- Use
sync --checkfor drift detection (faster than full sync) - Use
status --fastto skip slow external CLI probes - Cache external CLI results when appropriate
- Use
Promise.all()for parallel operations
Documentation Standards
When updating docs:
- Keep README.md concise (high-level overview)
- Put details in
docs/files - Use code examples for clarity
- Include expected output
- Add troubleshooting sections
Git Workflow
# Create feature branch
git checkout -b feature/my-feature
# Make changes, commit
git add .
git commit -m "feat: add new feature"
# Push and create PR
git push origin feature/my-featureCommit Message Format:
feat:— New featurefix:— Bug fixdocs:— Documentationtest:— Testsrefactor:— Code refactoringchore:— Maintenance
Questions?
- Check existing code for patterns
- Read tests for examples
- Ask in GitHub Discussions
- Open an issue if stuck
Key Files Reference
- Entry point:
src/cli.ts - Sync logic:
src/core/sync.ts - MCP management:
src/core/mcp.ts,src/core/mcpCrud.ts - Renderers:
src/core/renderers.ts - Project MCP (.mcp.json):
src/core/projectMcp.ts - Agent Plugins:
src/core/agentPlugin.ts - MCP client for budget:
src/core/mcpProbe.ts - Types:
src/types.ts - File I/O:
src/core/fs.ts - Paths:
src/core/paths.ts - UI helpers:
src/core/ui.ts
Remember: The goal is to make multi-LLM development simple. Every feature should reduce friction, not add complexity.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

