Skip to content

Repository files navigation

AI Orchestrator

Define AI instructions, agents, and skills once. Generate platform-specific config files for Claude Code and GitHub Copilot automatically.

npx aio init
npx aio validate
npx aio generate
    load.test.ts          ← parseYamlFile(), loadConfig()
    render.test.ts        ← renderFrontmatter(), renderDocument(), normalizeContent()
    schema.test.ts        ← AIO_SCHEMA
    utils.test.ts         ← normalizeConfig()
    validate.test.ts      ← validateSchema()
| What you want to define | Claude expects | Copilot expects |
|---|---|---|
| Project-wide instructions | `CLAUDE.md` | `.github/copilot-instructions.md` |
      registry.test.ts
      utils.test.ts
| Agent definitions | `.claude/agents/<id>.md` | `.github/agents/<id>.agent.md` |
| Skills | `.claude/skills/<id>/SKILL.md` | `.github/skills/<id>/SKILL.md` |

AI Orchestrator lets you write everything once in `.ai/` and generates all of the above.

---

## Installation

```bash
# one-off via npx
npx aio init

# or install globally
npm install -g aio
aio init

Requirements: Node.js 20+


Quick Start

# 1. Scaffold the .ai/ directory with examples
npx aio init

# 2. Edit the generated YAML files to match your project
# 3. Check for errors
npx aio validate

# 4. Write Claude and Copilot output files
npx aio generate

After generate, commit the outputs:

git add CLAUDE.md .claude/ .github/
git commit -m "chore: sync AI config"

Directory Structure

.ai/
  manifest.yml          # entry point — lists targets and imports
  instructions/         # global and path-scoped instructions
  agents/               # AI agent definitions
  skills/               # reusable skill definitions
  fragments/            # shared content blocks (not emitted directly)

The Manifest

manifest.yml is the root of your configuration. It declares which platforms to target and which files to include.

version: 1

targets:
  - claude
  - copilot

imports:
  - ./instructions/global.yml
  - ./instructions/frontend/react.yml
  - ./agents/code-reviewer.yml
  - ./skills/git-commit.yml

Fields

Field Type Description
version 1 Schema version. Currently always 1.
targets claude | copilot[] Which platforms to generate output for.
imports string[] Relative paths to YAML object files to include.

Object Kinds

Every file in .ai/ (other than the manifest) defines one object with a kind field.

instruction

Instructions tell the AI how to behave. They can apply globally or only to files matching a path pattern.

kind: instruction
id: global-conventions
scope: global
content:
  - Always run tests before committing.
  - Write clear, descriptive commit messages.
  - Prefer explicit over implicit code.
kind: instruction
id: typescript-rules
scope: path
applyTo:
  - "src/**/*.ts"
  - "src/**/*.tsx"
content: |
  Always use strict TypeScript. Avoid `any`. Prefer `unknown` for external data.
  Use discriminated unions over optional fields where possible.

Instruction fields

Field Required Description
kind Yes Must be "instruction"
id Yes Unique identifier (lowercase, hyphens)
scope Yes "global" or "path"
content Yes Instruction text — string or list of strings
name No Human-readable name (defaults to id)
applyTo No Glob patterns (required when scope: path)
targets No Restrict to specific targets: [claude], [copilot]
fragments No Fragment IDs to prepend to content

How instructions are rendered

Scope Claude output Copilot output
global CLAUDE.md .github/copilot-instructions.md
path .claude/rules/<id>.md with paths: frontmatter .github/instructions/<id>.instructions.md with applyTo: frontmatter

agent

Agents are autonomous AI assistants that can use tools and follow a system prompt.

kind: agent
id: code-reviewer
name: Code Reviewer
description: Reviews code for quality, security, and maintainability.
tools:
  - Read
  - Grep
  - Glob
model: sonnet
prompt: |
  You are a senior code review agent. Analyze the provided code and give feedback on:
  - Logic errors and potential bugs
  - Security vulnerabilities
  - Code style and readability
  - Test coverage gaps

  Be specific, actionable, and constructive.

Agent fields

Field Required Description
kind Yes Must be "agent"
id Yes Unique identifier
description Yes Short description of the agent's purpose
prompt Yes System prompt (Markdown)
name No Display name (defaults to id)
tools No List of tools the agent can use
allowedTools No Explicitly allowed tools
disallowedTools No Tools the agent cannot use (Claude only)
model No Model override: sonnet, opus, haiku
maxTurns No Max conversation turns (Claude only)
targets No Restrict to specific targets
fragments No Fragment IDs to prepend to prompt

How agents are rendered

Claude output Copilot output
.claude/agents/<id>.md .github/agents/<id>.agent.md

Note: disallowedTools and maxTurns are Claude-only fields and are silently dropped when generating Copilot output. Run aio validate --target copilot to see warnings.


skill

Skills are invocable capabilities that the AI can call when needed.

kind: skill
id: git-commit
name: git-commit
description: Generates concise, semantic git commit messages.
targets:
  claude:
    allowedTools:
      - shell
  copilot:
    license: MIT
    allowedTools:
      - shell
content: |
  When asked to create a commit message:
  1. Review the staged diff carefully.
  2. Identify the primary purpose of the change.
  3. Write a concise subject line (50 chars max).
  4. Add a body paragraph if the change is complex.
  5. Use conventional commit format: feat/fix/chore/docs/refactor.

Skill fields

Field Required Description
kind Yes Must be "skill"
id Yes Unique identifier
description Yes Short description of what the skill does
content Yes Skill instructions (Markdown)
name No Display name (defaults to id)
license No License identifier, e.g. MIT (set under targets.copilot.license)
allowedTools No Tools the skill may invoke (set under targets.<platform>.allowedTools)
targets No Per-target overrides for Claude/Copilot
fragments No Fragment IDs to prepend to content

Claude skill overrides (targets.claude)

Field Description
whenToUse Extra context for when Claude should invoke the skill (when_to_use)
argumentHint Autocomplete hint for expected arguments (argument-hint)
arguments Named positional arguments (string or list) (arguments)
disableModelInvocation Disable automatic invocation (disable-model-invocation)
userInvocable Hide from the / menu when false (user-invocable)
model Model override (model)
effort Effort override: low, medium, high, xhigh, max (effort)
context Execution context, e.g. fork (context)
agent Subagent type when context: fork (agent)
hooks Hook IDs to attach (hooks)
paths Glob patterns limiting auto-activation (paths)
shell Shell for command injection (shell)
allowedTools Pre-approved tools (allowed-tools)

How skills are rendered

Claude output Copilot output
.claude/skills/<id>/SKILL.md .github/skills/<id>/SKILL.md

Note: license is a Copilot-only field. It is included in Copilot output but dropped from Claude output. No error is raised — just a warning from aio validate.


fragment

Fragments are reusable content blocks that can be referenced by other objects. They do not produce any output files on their own.

kind: fragment
id: coding-standards
content:
  - Prefer explicit naming over abbreviations.
  - Avoid side effects in pure functions.
  - Write self-documenting code.

Reference a fragment from any instruction, agent, or skill:

kind: instruction
id: backend-api
scope: global
fragments:
  - coding-standards       # prepended first
content: |
  Follow the repository pattern for data access.
  Never expose raw database errors to callers.

The merged content becomes:

- Prefer explicit naming over abbreviations.
- Avoid side effects in pure functions.
- Write self-documenting code.

Follow the repository pattern for data access.
Never expose raw database errors to callers.

Fragment fields

Field Required Description
kind Yes Must be "fragment"
id Yes Unique identifier used in fragments: references
content Yes Text content — string or list of strings
name No Optional label

CLI Reference

aio init

Scaffolds a .ai/ directory with working examples for all four object kinds.

aio init

Creates:

.ai/
  manifest.yml
  instructions/global.yml
  agents/code-reviewer.yml
  skills/git-commit.yml
  fragments/coding-standards.yml

Existing files are never overwritten.


aio validate

Validates configuration without writing any files. Checks:

  • Malformed YAML
  • Missing required fields
  • Duplicate IDs across all imported files
  • Unresolved fragment references
  • Target compatibility (fields that don't map to a given platform)
aio validate                      # validate for both targets
aio validate --target claude      # claude only
aio validate --target copilot     # copilot only
aio validate --strict             # treat warnings as errors

Exit codes: 0 on success, 1 on failure.


aio generate

Generates platform-specific output files from your canonical config. Always validates first — generation is blocked if validation fails.

aio generate                      # generate for both targets
aio generate --target claude      # claude output only
aio generate --target copilot     # copilot output only
aio generate --dry-run            # print what would be written, write nothing
aio generate --watch              # watch .ai/ and regenerate on every change
aio generate --discover           # auto-discover YAML files instead of using manifest imports

Output locations

Claude:

CLAUDE.md                                   ← global instructions
.claude/
  rules/<id>.md                             ← path-scoped instructions
  agents/<id>.md                            ← agent definitions
  skills/<id>/SKILL.md                      ← skill definitions

Copilot:

.github/
  copilot-instructions.md                   ← global instructions
  instructions/<id>.instructions.md         ← path-scoped instructions
  agents/<id>.agent.md                      ← agent definitions
  skills/<id>/SKILL.md                      ← skill definitions

Field Mapping Reference

This table shows exactly how canonical fields map to each target's output format.

Instructions

Canonical field Claude (paths frontmatter) Copilot (applyTo frontmatter)
scope: global Content written to CLAUDE.md Content written to copilot-instructions.md
scope: path .claude/rules/<id>.md .github/instructions/<id>.instructions.md
applyTo paths: [...] applyTo: "glob1, glob2"
content Markdown body Markdown body

Agents

Canonical field Claude Copilot
name name: frontmatter name: frontmatter
description description: frontmatter description: frontmatter
tools tools: frontmatter tools: frontmatter
model model: frontmatter model: frontmatter
allowedTools allowedTools: frontmatter dropped
disallowedTools disallowedTools: frontmatter dropped (warning)
maxTurns maxTurns: frontmatter dropped (warning)
prompt Markdown body Markdown body

Skills

Canonical field Claude Copilot
name name: frontmatter name: frontmatter
description description: frontmatter description: frontmatter
targets.claude.allowedTools allowed-tools: frontmatter dropped
targets.copilot.allowedTools dropped allowed-tools: frontmatter
targets.copilot.license dropped (warning) license: frontmatter
targets.claude.whenToUse when_to_use: frontmatter dropped
targets.claude.argumentHint argument-hint: frontmatter dropped
targets.claude.arguments arguments: frontmatter dropped
targets.claude.disableModelInvocation disable-model-invocation: frontmatter dropped
targets.claude.userInvocable user-invocable: frontmatter dropped
targets.claude.model model: frontmatter dropped
targets.claude.effort effort: frontmatter dropped
targets.claude.context context: frontmatter dropped
targets.claude.agent agent: frontmatter dropped
targets.claude.hooks hooks: frontmatter dropped
targets.claude.paths paths: frontmatter dropped
targets.claude.shell shell: frontmatter dropped
content Markdown body Markdown body

Working with Multiple Files

As your config grows, split it across as many files as you like. The manifest controls what gets loaded.

Explicit imports (recommended)

# .ai/manifest.yml
version: 1
targets:
  - claude
  - copilot
imports:
  - ./instructions/global.yml
  - ./instructions/frontend/react.yml
  - ./instructions/backend/api.yml
  - ./agents/code-reviewer.yml
  - ./agents/test-planner.yml
  - ./skills/git-commit.yml
  - ./fragments/coding-standards.yml

Auto-discovery

Pass --discover to scan instructions/, agents/, skills/, and fragments/ automatically without listing every file in the manifest:

aio generate --discover

This is useful for large repos. Be aware that discovery order is alphabetical within each directory.


CI Integration

Add validation and generation to your CI pipeline so generated files are always in sync.

GitHub Actions

name: Sync AI config

on:
  push:
    paths:
      - '.ai/**'

jobs:
  generate:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: '20'
      - run: npx aio validate --strict
      - run: npx aio generate
      - uses: stefanzweifel/git-auto-commit-action@v5
        with:
          commit_message: 'chore: sync AI config [skip ci]'
          file_pattern: 'CLAUDE.md .claude/ .github/'

Validation-only gate (no auto-commit)

- run: npx aio validate --strict
- run: npx aio generate --dry-run

Use --dry-run to catch drift without writing files — useful when generated files are committed alongside source.


Validation Errors Reference

Error Cause Fix
Duplicate id "foo" Two objects share the same id Rename one of them
Cannot read file: ./path.yml Import path is wrong or file is missing Check the path in manifest.yml
Missing required field A required field is absent Add the field
Unknown fragment reference: "foo" fragments: [foo] but no fragment with that id exists Define the fragment or fix the id
Malformed YAML in ... YAML syntax error Check indentation, quotes, colons
Circular import detected manifest.yml imports itself or another manifest file Remove the circular import
Duplicate import detected The same file is listed more than once in imports Remove the duplicate entry

Warnings (suppressed unless --strict)

Warning Meaning
Field "license" not supported by claude license on a skill will be dropped in Claude output
Field "disallowedTools" not supported by copilot disallowedTools on an agent will be dropped in Copilot output
Path-scoped instruction has no applyTo Instruction with scope: path but no glob patterns

Development

git clone https://github.com/your-org/aio
cd aio
npm install

npm run typecheck    # type-check src + tests
npm run test:run     # run test suite once
npm run test         # run tests in watch mode
npm run build        # compile to dist/
npm run format       # format with prettier

Project layout

src/
  types/index.ts          ← canonical type system
  index.ts                ← public library exports
  cli/
    index.ts              ← Commander CLI entry point
    utils.ts              ← shared CLI helpers
    commands/
      init.ts             ← aio init
      validate.ts         ← aio validate
      generate.ts         ← aio generate
  load/
    yaml-loader.ts        ← parse individual YAML files
    import-resolver.ts    ← resolve manifest imports, loadConfig()
  validate/
    schema.ts             ← Zod schemas, validateSchema()
    compatibility.ts      ← validateTargetCompatibility()
  utils.ts                ← normalizeConfig()
  render/
    frontmatter.ts        ← YAML frontmatter serialization helpers
  targets/
    claude/index.ts       ← renderClaude()
    copilot/index.ts      ← renderCopilot()
  __tests__/              ← mirrors src/ structure
    load/
      yaml-loader.test.ts
      import-resolver.test.ts
    validate/
      schema.test.ts
    utils/
      normalize.test.ts
    targets/
      claude.test.ts
      copilot.test.ts
      snapshots.test.ts     ← golden snapshot tests
    integration/
      generate.test.ts      ← full pipeline end-to-end tests
      fixtures/
        minimal/            ← single global instruction, claude-only target
        full/               ← all four object kinds, both targets, mixed fragments
        agents-and-skills/  ← agents + skills only, no instructions

Generation pipeline

loadConfig()
  └─ parseYamlFile(manifest.yml)
  └─ resolveImports() → parseYamlFile() per import

mergeFragments()        ← inline fragment content

normalizeConfig()       ← normalize IDs, set defaults

renderClaude()          ← produce RenderedFile[]
renderCopilot()         ← produce RenderedFile[]

writeFiles()            ← mkdir + writeFile per output

Schema Versioning

The manifest version field is reserved for future migrations. All current configs should use version: 1. When breaking schema changes are introduced, a migration guide will be published and the version number will increment.


Roadmap

The current release is deliberately narrow. Planned additions:

  • Variablesvars: in manifest, {{ language }} in content
  • Target overrides — per-target field values in a single definition
  • Conditional renderingwhen: { target: claude }
  • Remote imports — fetch shared config from a URL or package
  • More targets — Cursor, Windsurf, Continue.dev, Cline, Aider

License

MIT

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages