Skip to content

Configuration

Amir Olyaei edited this page Oct 5, 2026 · 5 revisions

Configuration

Directory structure

User-global (~/.agents/)

~/.agents/
  config/
    config.json        # unified config: all providers read this
    mcp-config.json    # shared MCP servers
    AGENTS.md          # shared rules
  skills/              # shared skills (one dir per skill, each with SKILL.md)
  data/
    memory/            # long-term memory, datasets
    plugins/           # plugins
  state/
    logs/              # logs
    history/           # chat history, active sessions
  cache/
    models/            # model caches
    venv/              # isolated environments

Project-local (.ai/ in the repo root)

.ai/
  config.json            # shared team settings (commit this)
  config.local.json      # personal overrides (gitignored)
  mcp-config.json        # project MCP servers
  mcp-config.local.json  # personal MCP overrides (gitignored)
  skills/                # project skills
  AGENTS.md              # project rules

ai-config init-project adds the two *.local.json files to .gitignore automatically.

Unified config format

~/.agents/config/config.json:

{
  "shared": {
    "model": "default-model",
    "theme_mode": "dark",
    "permissions": {
      "allow": ["Read(**)", "Exec(git)"],
      "deny": ["Exec(sudo)"],
      "ask": ["Write(**/.env*)"]
    }
  },
  "providers": {
    "devin": {
      "model": "provider-specific-model",
      "permissions": {
        "allow": ["Read(**)", "Exec(git)", "Exec(npm)"]
      }
    }
  },
  "skills": {
    "enabled": ["skill-name"],
    "paths": ["~/.agents/skills/", ".ai/skills/"]
  }
}

Top-level keys:

Key Purpose
shared Settings applied to every provider unless overridden
providers Per-provider overrides keyed by provider name
context_servers MCP server definitions (lives in mcp-config.json, merged in at read time)
skills enabled list plus paths to search for skills

MCP servers

MCP servers live in ~/.agents/config/mcp-config.json under the context_servers key:

{
  "context_servers": {
    "github": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-github"]
    }
  }
}

The legacy mcpServers key is still accepted on read; writes always use context_servers.

A server can be kept in the store without being exported by flagging it "disabled": true - sync skips disabled servers entirely, even when they are named in a provider's include list. Useful for dormant entries you may re-enable later.

Project MCP servers go in .ai/mcp-config.json, personal additions in .ai/mcp-config.local.json.

Per-provider MCP scoping

Sync is opt-in per provider: "providers.<name>.sync": true enables export, otherwise ai-config sync (no flags) writes nothing to that provider. Once enabled, providers.<name>.mcp scopes which servers it gets:

{
  "providers": {
    "cursor": { "mcp": { "include": ["github", "filesystem"] } },
    "claude": { "mcp": { "exclude": ["internal-tools"] } }
  }
}
  • include: allowlist, only these servers are written to that provider
  • exclude: these servers are dropped from the full set
  • Neither key: provider gets everything

--prune honors the same scope: it removes only servers outside the provider's scoped set, and only from that provider's MCP file.

Precedence

From highest to lowest:

  1. .ai/config.local.json (project, personal)
  2. .ai/config.json (project, shared)
  3. providers.<name> in ~/.agents/config/config.json
  4. shared in ~/.agents/config/config.json

A provider integration should deep-merge in that order. See Provider Integration.

Trust boundary: project .ai/ directories are only loaded when both the .ai directory and its parent are owned by the current user. Configs owned by other users are skipped with a SecurityWarning — this blocks config injection from shared directories. On platforms where ownership cannot be verified (Windows), the config loads with a warning instead.

Permissions model

Permissions are three rule lists:

  • allow: patterns permitted without asking
  • deny: patterns always blocked
  • ask: patterns that require confirmation

Patterns look like Read(**), Exec(git), Write(**/.env*).

Secrets

Never store API keys in config files. Use system keyrings or environment variables. The *.local.json files are for personal non-secret overrides; they are gitignored by init-project but that is not a substitute for proper secret storage.

universal-ai-config

Getting started

Using it

For integrators

For maintainers


Repository | Issues | PyPI

Clone this wiki locally