One config. Every coding agent.
Project-level configuration for AI coding agents, materialized into whatever each tool expects to find on disk.
agnos is a project-level configuration manager for AI coding agents. You declare your docs, rules, skills, MCP servers, and hooks once in a single agnos.json at the root of your repo. agnos materializes that declaration into whatever each agent expects to find on disk: CLAUDE.md + .mcp.json + .claude/settings.json for Claude Code, AGENTS.md + .codex/config.toml for OpenAI Codex, GEMINI.md + .gemini/settings.json for Gemini CLI, and so on.
agnos ships as a single package (@luxia/agnos) with a fixed, built-in set of agents (Claude Code, Codex, Gemini CLI) and domains (docs, rules, skills, mcp, hooks, agents). Point it at your project, run it once, or leave it in watch mode: every agent's files stay in sync with your one source of truth.
Every coding agent invents its own on-disk configuration format. Keeping them consistent by hand is tedious and error-prone:
- Drift:
CLAUDE.mdandAGENTS.mdsay different things because you updated one and forgot the other. - Duplication: the same MCP server, the same hook, the same rule copied into three tool-specific files with three different syntaxes.
- Onboarding cost: adding a new agent to a repo means learning yet another file layout and hand-translating everything you already wrote.
- No single source of truth: nothing in the repo tells you what the intended configuration is; it's scattered across whatever files each tool happens to read.
agnos collapses all of that into one declarative agnos.json. You edit intent; agnos renders the per-agent reality. Adding an agent becomes "render its files"; removing one becomes "delete its files."
- What is agnos?
- What does it solve?
- Table of contents
- Features
- The model: config writers + one config reader
- Installation
- Usage
- Configuration (
agnos.json) - Commands
- Active development
- Contributing
- License
- π― One source of truth: declare docs, rules, skills, MCP servers, and hooks once in
agnos.json. - π Multi-agent output: renders native files for Claude Code, OpenAI Codex, and Gemini CLI from the same config.
- π Watch mode: a per-domain watcher tree keeps agent files in sync as your sources change; edit a rule fragment and the canonical files re-render.
- π§© Composable rules: inject titled sections (by frontmatter
title) from fragment files into your canonical rules file, preserving your hand-written sections. - π Docs index: compile a metadata index from your docs directory and surface it to agents.
- π¦ Skills management: fetch, pin, verify, and update agent skills from GitHub/GitLab/Bitbucket or local paths, linked per-agent.
- π°οΈ MCP registry integration: search and add MCP servers from the registry, or configure them manually; agnos renders them per-agent.
- πͺ Portable hooks: declare command hooks once against a normalized event vocabulary; each agent gets them in its native format.
- β»οΈ Migrate what you already have: import existing MCP servers, hooks, and skills from your agents' current config into
agnos.json. - π§ͺ Dry runs:
--dryshows exactly what would change without writing anything.
agnos splits its work in two:
- Config-writer domains manage their own slice of the project.
skills/mcp/hookswrite entries intoagnos.json;docscompiles a documentation index;rulesinjects titled sections into your canonical rules file(s). - One config-reader domain,
agents: readsagnos.jsonand the canonical outputs and renders every per-agent native file via per-agent adapters. Installing an agent is just "render its files"; removing it is "delete its files."
βββββββββββββ config WRITERS βββββββββββββ βββ reader βββ
docs βββΆ .docs/index.md β β
rules ββΆ ./AGENTS.md (titled sections injected) ββββββββΆβ agents ββββΆ CLAUDE.md, .mcp.json,
skills βΆ agnos.json#skills + .agnos/skills/ β (adapters) β .claude/settings.json,
mcp ββββΆ agnos.json#mcp β β .claude/skills, .codex/*
hooks ββΆ agnos.json#hooks β β
βββββββββββββββββββββββββββββββββββββββββββ ββββββββββββββ
Domains run in priority order (skills β docs β rules β mcp β hooks β agents), so every writer has produced its canonical output before the reader renders.
Requires Node.js 24 or newer. agnos is ESM-only. This project uses pnpm exclusively.
# global (recommended for the CLI)
pnpm add -g @luxia/agnos
# or per-project
pnpm add -D @luxia/agnoscd my-project
agnos --init # bootstrap agnos.json + pick agents (add -y for defaults)
agnos --once # run the pipeline once: prepare skills β docs β rules β render agents
agnos # watch mode: keep agent files in sync as sources changeNOTE: agnos always tries a symlink first when the
agentsdomain links skills or mirrors rules. On Windows, creating a file symlink can require an elevated terminal or Developer Mode; when that's not available it falls back to a hardlink, then a plain copy. Directories use junctions on Windows instead, which don't need elevation. macOS/Linux create symlinks without any special privileges.
Typical workflow:
agnos --initcreatesagnos.jsonand walks you through picking agents, a docs root, a rules file, and a skills directory. Add-yto accept every default non-interactively.- Edit
agnos.json(or use the domain subcommands likeagnos mcp add githubandagnos skills add owner/repo) to declare what you want. agnosin one terminal watches all domains and re-renders on change. Runagnos --oncein CI or a pre-commit hook for a single deterministic pass, oragnos --dryto preview.
You can also run a single domain: agnos rules --once, agnos docs, etc.
agnos --init walks you through building agnos.json interactively; running it seeds agents, docs.root, rules.files, and skills.route. mcp and hooks entries are added afterward via their subcommands (or by hand). Here's an example showing every domain populated at once:
{
"$schema": "https://unpkg.com/@luxia/agnos/schema.json",
"schemaVersion": 1,
"agents": ["claude-code", "codex", "gemini-cli"],
"docs": { "root": ".docs" },
"rules": {
"files": {
"./AGENTS.md": ["./.docs/index.md", "./.rules/security.md", "./.rules/style.md"]
}
},
"skills": {
"sources": {
"pdf": "github:vercel-labs/agent-skills/skills/pdf"
}
},
"mcp": [
{
"name": "github",
"transport": "stdio",
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-github"],
"env": { "GITHUB_TOKEN": "${GITHUB_TOKEN}" }
}
],
"hooks": [
{
"event": "PreToolUse",
"matcher": "git",
"type": "command",
"command": "echo 'about to run git'",
"message": "checking git usage"
}
]
}agnos.json is parsed as strict JSON (no comments, no trailing commas), so the block above is copy-pasteable as-is. ${VAR} placeholders inside mcp.env/mcp.headers are resolved at render time.
Field reference (see schema.json for the authoritative definition):
| Field | Type | Description |
|---|---|---|
schemaVersion |
1 |
Required. Config schema version; must be 1. |
agents |
string[] |
Active agent ids: "claude-code", "codex", "gemini-cli". |
docs.root |
string |
Directory the docs index is compiled from (default .docs). |
rules.files |
{ [canonical]: string[] } |
Maps each canonical rules file β fragment files whose titled sections are injected into it. |
skills.route |
string |
Canonical skills directory (default .agnos/skills); agents link their own skills dir here. |
skills.sources |
{ [name]: string } |
Local skill name β composite source ref (github:/gitlab:/bitbucket:/file:). |
mcp |
object[] |
MCP server declarations (name, transport, command, args, env, headers, β¦). |
hooks |
object[] |
Flat array of command hooks (event, matcher?, type, command, message?). |
agnos [domain] [subcommand] [args] [flags]
agnos: watch all domains and keep agent files in sync.agnos --once: run the full pipeline once and exit.agnos <domain>: run a single domain (docs|rules|skills|mcp|hooks|agents).agnos <domain> <subcommand>: mutate config or run a domain action.agnos <domain> --help: show help for a domain and its subcommands.
Available on every command:
| Flag | Description |
|---|---|
--dry |
Resolve and log planned actions; write nothing (implies --once). |
--once |
Single pass, no watchers. |
--quiet |
Errors only. |
--init |
Run initialization (bootstrap), then exit. |
-y, --yes |
Accept defaults (non-interactive). |
--cwd <dir> |
Run as if invoked from <dir>. |
--debug |
Print debug output and full stack traces on error. |
-h, --help |
Show help. |
Compiles a documentation index from docs.root. Surface it to agents by listing the generated index in rules.files. No subcommands: configure it via agnos.json or agnos docs --init.
| Command | Args | Description |
|---|---|---|
agnos docs |
none | Compile the docs index (watch mode unless --once/--dry). |
Injects titled sections (by frontmatter title) from fragment files into your canonical rules file(s). Hand-written sections are preserved; removed fragments are pruned. No subcommands: configure via agnos.json or agnos rules --init.
| Command | Args | Description |
|---|---|---|
agnos rules |
none | Inject rules (watch mode unless --once/--dry). |
Fetches, pins, verifies, and installs skills into the canonical skills dir (linked per-agent by agents).
| Subcommand | Args / Flags | Description |
|---|---|---|
add |
<skills_address...> Β Β·Β -p, --provider <p> Β Β·Β -s, --skills <names> |
Add skills from one or more sources (owner/repo[#ref] or paths); discovers skills and prompts to pick. --provider sets the default provider (github|gitlab|bitbucket|file) for un-prefixed addresses; --skills pdf,docx skips the prompt. |
remove |
[names...] |
Remove skill sources (multiselect prompt when no name is given). |
fetch |
none | Check that every skill source still resolves (reports moved). |
version |
none | Check whether skills are on their pinned commit (reports outdated). |
integrity |
none | Verify skill content matches the lock (reports changed). |
install |
none | Run the prep pipeline (fetch β version β integrity β install). |
update |
[names...] |
Re-pin + reinstall skills, accepting upstream changes (default: all). |
migrate |
[file] Β Β·Β --missing | --force | --skip |
Import skill sources from a lock file (name β ref JSON; default skills-lock.json). |
Manages MCP servers in agnos.json (rendered per-agent by the agents domain).
| Subcommand | Args / Flags | Description |
|---|---|---|
add |
[term] |
Add MCP servers from the registry (search term), or configure one manually (omit the term for an interactive prompt). |
update |
[names...] |
Update registry-managed MCP servers to their latest version (all if none given). |
remove |
[names...] |
Remove MCP servers (multiselect prompt when no name is given). |
migrate |
--missing | --force | --skip |
Import MCP servers from the active agents' native config. |
Manages hooks in agnos.json (a flat array; the agents domain regroups + renders per-agent).
| Subcommand | Args / Flags | Description |
|---|---|---|
add |
<event> <command> [matcher] |
Add a command hook. event is one of the normalized events below. |
remove |
[event] [command] [matcher] |
Remove command hooks (multiselect prompt when no args are given). |
migrate |
--missing | --force | --skip |
Import hooks from the active agents' native config. |
Normalized hook events: PreToolUse, PostToolUse, UserPromptSubmit, Notification, Stop, SubagentStop, PreCompact, SessionStart, SessionEnd. Each agent renders only the events it supports and skips the rest.
The sole config reader: renders every active agent's native files. add/remove toggle agnos.json#agents (remove also cleans up the agent's rendered files).
| Subcommand | Args | Description |
|---|---|---|
add |
[agents...] |
Enable agents (their files render on the next agnos run). Omit ids to pick interactively. |
remove |
[agents...] |
Remove agents' rendered files, then disable them. |
--missing/--force/--skip(themigrateconflict policy):--missing(default) adds only entries not already present;--forceoverwrites conflicting entries and adds missing ones;--skipaborts if any entry conflicts.
Node 24+, ESM only, TypeScript throughout. Contributions are welcome: issues and PRs at github.com/rgdevme/luxia.
pnpm install
pnpm build # bundle with tsup + copy templates
pnpm typecheck # tsc --noEmit
pnpm test # vitest
pnpm lint # eslint
pnpm format # prettier --writeCI runs format-check, lint, typecheck, test, and build on every pull request; run the same locally before pushing:
pnpm format:check && pnpm lint && pnpm typecheck && pnpm test && pnpm buildCommits are linted via Husky + lint-staged. Please keep changes focused and add tests for new behavior.
Released under the MIT license.