If you use more than one AI coding agent, you've probably noticed that each one wants its own context file.
Claude Code reads CLAUDE.md. Cursor reads .cursorrules. GitHub Copilot reads .github/copilot-instructions.md. Kiro reads .kiro/steering/*.md. Windsurf reads .windsurf/rules/*.md. Gemini CLI and Antigravity read GEMINI.md. And then there's AGENTS.md and llms.txt.
That's nine different files describing the same thing: your project's stack, architecture, and coding conventions.
Most of them contain nearly identical content. But they go out of sync the moment someone updates one and forgets the rest. The result is that your AI agent gives inconsistent suggestions depending on which tool you're using.
One config, every agent
contextai is a CLI that generates all of these from a single TypeScript config:
import { defineContext } from 'contextai';
export default defineContext({
project: {
name: 'my-app',
stack: ['TypeScript', 'React', 'Node.js'],
architecture: 'Monorepo with shared packages',
},
conventions: {
code: [
{
title: 'Naming',
items: ['camelCase for variables', 'PascalCase for components'],
},
],
testing: [
{
title: 'Unit tests',
items: ['Use Vitest', 'Colocate test files with source'],
scope: 'agent-only',
},
],
},
outputs: {
'AGENTS.md': true,
'CLAUDE.md': true,
'.cursorrules': true,
'.github/copilot-instructions.md': true,
'llms.txt': true,
'.kiro/steering': true,
'.windsurf/rules': true,
'GEMINI.md': true,
},
});
Then:
npx contextai generate
All nine files created from one source. Change a convention, run generate again, everything stays in sync.
Supported output targets
| Target | File |
|---|---|
| Claude Code | CLAUDE.md |
| Cursor | .cursorrules |
| Codex / generic agents | AGENTS.md |
| GitHub Copilot | .github/copilot-instructions.md |
| Kiro (AWS) | .kiro/steering/*.md |
| Windsurf | .windsurf/rules/*.md |
| Gemini CLI / Antigravity | GEMINI.md |
| AI search engines | llms.txt |
| Custom | any path via config |
Each generator respects the target's native format. Kiro gets YAML frontmatter with inclusion: always. Windsurf gets trigger: always_on. Gemini gets clean markdown. You don't have to think about format differences.
Project scanner
contextai init inspects your project root — reads package.json, tsconfig.json, framework configs — and bootstraps a context.config.ts with detected stack and sensible defaults.
Built-in convention templates are available for Next.js, NestJS, Express, Remix, and SvelteKit:
export default defineContext({
templates: ['nextjs'],
// ...
});
Convention scoping
Sometimes you want technical depth for AI agents that doesn't belong in human-facing docs:
conventions: {
security: [
{
title: 'Auth patterns',
items: ['Use JWT tokens', 'Rotate secrets quarterly'],
scope: 'agent-only',
},
],
}
agent-only sections appear in all generated output files. human-only sections are excluded from AI context entirely.
Custom generators
New AI tools appear regularly. Custom generators let you target anything without waiting for a contextai update:
outputs: {
'CLAUDE.md': true,
custom: [
{
path: 'docs/ai-context.md',
generator: (config) => `# ${config.project.name}\n${config.project.architecture}`,
},
],
}
Keeping things in sync
-
contextai validate— checks that output files exist and aren't stale -
contextai diff— shows what would change without writing anything -
contextai generate --dry-run— preview mode -
contextai watch— regenerates automatically when config changes - Git hook —
contextai initcan install a pre-commit hook that runs generate before every commit
JSON output for CI
contextai generate --format json
Outputs the full intermediate representation to stdout instead of writing files. Useful for CI pipelines, piping into other tools, or debugging.
Links
- Site: contextai.run
- GitHub: github.com/madeburo/contextai
- npm: npmjs.com/package/contextai
- License: MIT

Top comments (0)