CLI Reference
All commands are provided by the aiman binary.
Output format is unstable before version 1.0. Human-readable command output is not a stable API. For automation, wait for the upcoming
--jsonflag. All format changes are markedbreaking:in the changelog.
Global flags
| Flag | Description |
|---|---|
--help | Show help for a command |
--version | Print the binary version |
aiman init
aiman init <repo-url> [--path <dir>]Connects an inventory repository.
Arguments:
<repo-url>— URL of the inventory Git repository.
Flags:
--path <dir>— local path for cloning or registering the repository.
Behavior:
- clones or registers the inventory repository;
- creates the base structure for an empty repository;
- creates a local
aim.local.yaml; - writes the active repository to the global config;
- classifies existing files as adoptable, existing AIM, or conflicting.
aiman switch
aiman switch <path>Switches the active inventory repository without cloning.
Use this if you have multiple local inventory repositories or need to run commands from a different directory.
aiman apply
aiman apply [--dry-run]Applies the current local inventory to AI environments without any Git operations.
Flags:
--dry-run— show the sha256 delta between the local inventory and the installed AI environments without writing files.
apply does not commit, does not push or fetch, and does not update published_hash or synced_hash.
Example output — apply
On success, apply prints a result line. If any AI environment has changes, a change delta block follows — indented by two spaces, with A (new) and M (modified) markers:
applied: 21 skills, 1 MCP server → 3 environments
A skills/refactor-helper.md (new in all environments)
M skills/commit-message.md (updated in claude-code, cursor)The counters on the result line (21 skills, 1 MCP server) represent the operation volume: how many items were applied in total. The block below is the change delta: what was actually added or overwritten. These are different numbers — 21 skills means 21 skills total, not 21 changes.
If nothing changed in any environment, only the result line is printed:
applied: 21 skills, 1 MCP server → 3 environmentsExample output — apply --dry-run
Inventory matches the installed AI environments:
[dry-run] nothing to apply — environments match local inventoryChanges detected:
[dry-run] would apply 2 changes to 2 environments (claude-code, cursor):
A skills/new-skill.md (new in all environments)
M skills/existing.md (differs in cursor)
[dry-run] MCP context7 → claude-code, cursorFor MCP servers, apply --dry-run shows only the target AI environments and does not compute a delta — AIM does not compare the installed MCP configuration against the inventory descriptor. See Known limitation: MCP config delta.
If the change list exceeds 20 lines, it is truncated:
A skills/skill-1.md
A skills/skill-2.md
… and 15 moreKnown limitation: MCP config delta
For skills, AIM computes a delta: it compares the inventory content against the installed file in each AI environment and marks changes with A/M.
For MCP servers, delta is not yet computed. AI environments write MCP entries into shared config files (~/.claude.json, mcp.json, config.toml). Comparing the installed fragment against the inventory descriptor requires parsing and normalizing those configs — this is deferred. As a result, MCP entries in the output show only the target environments, without an A/M marker.
The absence of a marker for an MCP server does not mean it is unchanged. It means AIM does not check its state in the environments. For skills, that claim is verified by the delta; for MCP servers, it is not.
aiman push
aiman push [--dry-run]Validates the inventory, creates a commit, and pushes changes to the remote.
Flags:
--dry-run— show the publish plan without committing or pushing.
push is blocked if the remote is ahead of the local state or if the Git state is unsafe.
Frontmatter validation: if a frontmatter field (other than the file body) contains an error, push prints a warning: to stderr and continues. Errors in the file body are blocking: push prints an error: and aborts.
Example output — push
On success, push prints a result line with the published commit hash. If the inventory had changes, a delta block follows — showing which files were published (A for new, M for modified):
published: 96e091b · 19 skills, 1 MCP server
M skills/commit-message.md
A mcp/jira.yamlIf there were no changes, only the result line is printed.
Example output — push --dry-run
Working tree is clean:
[dry-run] nothing to publish — working tree is cleanChanges ready to publish:
[dry-run] would publish managed changes:
M skills/review-code.md
A mcp/jira.yaml
validated inventory: 5 skills, 1 MCP serveraiman sync
aiman sync [--dry-run] [--force]Fetches the published state from the remote and applies it to the local AI environments.
Flags:
--dry-run— show the plan without writing to the repository or AI environments;--force— remove untracked files conflicting with remote and apply the published state. Files without conflicts are always preserved.
sync does not perform merges. If the history has diverged, AIM stops and asks you to restore Git manually.
Untracked files in skills/ and mcp/ do not block sync unless they conflict by name with files from remote. On conflict, sync stops and lists the problematic files.
Example output — sync
On success, sync prints a result line with the hash of the applied state. If changes arrived from remote, a delta block follows — showing what changed in the inventory (A for new, M for modified, D for deleted):
synced: 67451fc · 21 skills, 1 MCP server → 3 environments
M skills/commit-message.md
A skills/refactor-helper.mdAs with apply, the counters on the result line represent the operation volume (total applied); the block below is the delta of incoming changes. 21 skills means 21 skills total, not 21 changes.
If the local state already matched origin/main and nothing came in from remote, only the result line is printed:
synced: 67451fc · 21 skills, 1 MCP server → 3 environmentsWith --force, AIM removes conflicting untracked files before applying and reports what was deleted. This report always appears before the result line:
discarded untracked files (--force):
skills/draft.md
mcp/local-only.yaml
synced: 67451fc · 21 skills, 1 MCP server → 3 environmentsThe deletion report cannot be suppressed: --force deletes files permanently, and AIM never does this silently.
Example output — sync --dry-run
Nothing to apply (local state matches origin/main):
[dry-run] nothing to sync — environments up to date with origin/mainChanges to apply:
[dry-run] would sync 2 changes from origin/main → 3 environments:
M skills/commit-message.md
A skills/refactor-helper.mdaiman status
aiman statusShows the state of the active inventory repository: position relative to origin/main, state of AI environments, and the list of changes in skills/ and mcp/ that have not yet been published.
aiman status fetches from remote. Before calculating the position, the command runs a Git fetch — it answers the question "what in my inventory has changed relative to the published state," and that question inherently includes the remote. Without a fetch, the position would be based on a stale local ref and could be wrong (showing up-to-date when the remote has already moved on).
This is a deliberate difference from git status. git status never touches the network because its question is only about the local working tree. aiman status has a different scope, so the short fetch delay is expected behavior, not a bug.
TODO: add a spinner during fetch
The fetch runs with a hard timeout. If the remote is unreachable, the command does not hang: the Position: field is set to unknown (remote unreachable), a warning: cannot reach remote repository is printed to stderr, and the exit code remains 0.
Position: possible values: up-to-date with origin/main | N commits ahead of origin/main | N commits behind of origin/main | diverged from origin/main (N ahead, M behind) | unknown (remote unreachable).
Environments: possible values: applied (synced <hash>) | unknown | needs sync (N commits not applied).
If the change list exceeds 20 lines, it is truncated with … and N more.
Example output
Repository is in sync, inventory is applied:
Repository: git@github.com:you/aim-loadout.git
Position: up-to-date with origin/main
Environments: applied (synced a1b2c3d)
Working tree matches origin/main · nothing to publishUnpublished changes present:
Repository: git@github.com:you/aim-loadout.git
Position: 2 commits ahead of origin/main
Environments: needs sync (2 commits not applied)
Changes not yet published (origin/main → working tree):
A skills/new-skill.md
M skills/existing.md
run aiman push to publish
run aiman sync to applyRemote unreachable (no network or no access to the repository):
Repository: git@github.com:you/aim-loadout.git
Position: unknown (remote unreachable)
Environments: applied (synced a1b2c3d)
Working tree matches origin/main · nothing to publishaiman doctor
aiman doctorDiagnoses the local installation:
- active repository;
- detected AI environments;
- adapter paths;
- inventory item validity;
- required MCP env variables;
- remote availability and sync state.
Example output
Everything is healthy, all environments found:
Active Repo: /home/user/.aim/aim-loadout (from /home/user/.config/aim/config.yaml)
=== AI Environments ===
✓ claude-code /home/user/.claude found
✓ cursor /home/user/.cursor found
✗ codex /home/user/.codex not found
=== Skills ===
Found: 4 valid, 0 invalid
=== Sync State ===
synced_hash: a1b2c3d
published_hash: a1b2c3d
remote HEAD: a1b2c3d
status: up-to-date
=== MCP Environment Variables ===
✓ context7 › UPSTASH_REDIS_REST_URL — set
=== Issues ===
• codex: not installed or not found at /home/user/.codexIssues present — AI environment not found, required variable not set:
Active Repo: /home/user/.aim/aim-loadout (from /home/user/.config/aim/config.yaml)
=== AI Environments ===
✓ claude-code /home/user/.claude found
✗ cursor /home/user/.cursor not found
✗ codex /home/user/.codex not found
=== Skills ===
Found: 2 valid, 1 invalid
=== Sync State ===
synced_hash: not set
published_hash: not set
remote HEAD: a1b2c3d
status: not yet synced
=== MCP Environment Variables ===
✗ context7 › UPSTASH_REDIS_REST_URL — missing (required)
=== Issues ===
• cursor: not installed or not found at /home/user/.cursor
• codex: not installed or not found at /home/user/.codex
• my-skill.md: invalid: name does not match filename
• context7 › UPSTASH_REDIS_REST_URL — missing (required)aiman add
aiman add skill <file|dir|-> [--name <string>] [--overwrite]
aiman add mcp <file|-> [--name <string>] [--overwrite]Adds an inventory item (skill or MCP server) to the local repository from a file, a directory, or stdin.
aiman add skill
aiman add skill <file|dir|->
aiman add skill ~/Downloads/my-skill.md
aiman add skill -Reads a skill from a file, a directory, or stdin (-), validates the frontmatter, determines the name, and writes the result to the active inventory repository.
Arguments:
<file|dir|->— path to the skill file, path to a folder skill (or itsSKILL.md), or-to read from stdin.
Flags:
--name <string>— override the skill name; if not set, the name is taken from the file's frontmatter (for a flat skill) or from the directory name (for a folder skill).--overwrite— overwrite an existing skill on content conflict.
Behavior:
- a single file (not named
SKILL.md) or stdin — written as a flatskills/<name>.md; - a path to a directory, or a path to a
SKILL.mdfile inside it — recognized as a folder skill and copied in full toskills/<name>/(SKILL.mdplus all reference files alongside it). Both path forms produce the same result; - if the directory does not contain
SKILL.md— returns a clear error instead of a system-level "is a directory" message; - if
skills/<name>.md(flat) orskills/<name>/SKILL.md(folder) already exists with the same content — the command succeeds with no changes; for a folder skill, onlySKILL.mdcontent is compared, reference files are not; - if the destination already exists with different content and
--overwriteis not set — returns an error with a hint to use--overwrite.
Add from a file:
aiman add skill ~/Downloads/create-spec.mdAdd from stdin:
cat ~/Downloads/create-spec.md | aiman add skill -Add a folder skill (both forms are equivalent):
aiman add skill ~/Downloads/get-team-tasks
aiman add skill ~/Downloads/get-team-tasks/SKILL.mdOutput on successful add:
added: skill create-specOutput when the skill is already in the inventory with identical content (no-op):
up to date: skill create-spec · already identicalaiman add mcp
aiman add mcp <file|->
aiman add mcp jira.yaml
aiman add mcp -Reads an MCP server description from a YAML file or stdin (-), applies env-strip, and writes the result to the active inventory repository.
Arguments:
<file|->— path to the MCP server YAML file, or-to read from stdin.
Flags:
--name <string>— override the server name; if not set, the name is taken from the file'snamefield.--overwrite— overwrite an existing MCP server on content conflict.
Behavior:
- if
mcp/<name>.yamlalready exists with the same content — the command succeeds with no changes; - if
mcp/<name>.yamlalready exists with different content and--overwriteis not set — returns an error with a hint to use--overwrite.
Env-strip: env fields with a populated value are not saved in mcp/<name>.yaml. Instead, the actual values are written to aim.local.yaml under the key mcp_env: {<name>.<VAR>: value}. The inventory stores only descriptors: name, description, required, example. Since aim.local.yaml is excluded from Git, secrets never enter the repository.
Example input file:
name: jira
description: Jira MCP server
command: npx
args: [-y, mcp-jira]
targets: [claude_code]
env:
- name: JIRA_API_KEY
description: Jira API key
required: true
value: "secret123"After the command:
mcp/jira.yamlcontains the descriptor without thevaluefield;aim.local.yamlcontainsmcp_env: {jira.JIRA_API_KEY: "secret123"}.
Add from a file:
aiman add mcp jira.yamlAdd from stdin:
cat jira.yaml | aiman add mcp -Override the server name:
aiman add mcp jira.yaml --name jira-workOverwrite on conflict:
aiman add mcp jira.yaml --overwriteOutput on successful add:
added: mcp jiraOutput when the MCP server is already in the inventory with identical content (no-op):
up to date: mcp jira · already identicalaiman import
aiman import skill <name> --from <env> [--print] [--overwrite]
aiman import mcp <name> --from <env> [--print] [--overwrite] [--targets all]Imports an inventory item (skill or MCP server) from an installed AI environment into the local repository.
aiman import skill
aiman import skill <name> --from <env>
aiman import skill create-spec --from claude-code
aiman import skill create-spec --from claude-code --printReads a skill by name from the specified AI environment, normalizes it, and writes it as skills/<name>.md in the active inventory repository.
Arguments:
<name>— name of the skill to import.
Flags:
--from <env>— import source (required). Accepted values:claude-code,cursor,codex.--print— print the skill content to stdout without writing to disk.--overwrite— overwrite an existing skill on content conflict.
Skill sources by AI environment:
| AI environment | Identifier | Skills path |
|---|---|---|
| Claude Code | claude-code | ~/.claude/skills/*.md and ~/.claude/skills/<name>/SKILL.md |
| Codex CLI | codex | ~/.codex/skills/<name>/SKILL.md |
| Cursor | cursor | No native skill concept — always returns an empty list |
Behavior:
- if the skill is not found in the specified environment — returns an error;
- if
skills/<name>.mdalready exists with the same content — succeeds with no changes; - if
skills/<name>.mdalready exists with different content and--overwriteis not set — returns an error with a hint to use--overwrite.
Import from Claude Code:
aiman import skill create-spec --from claude-codeOutput on successful import:
imported: skill create-spec · from claude-codeOutput when the skill is already in the inventory with identical content (no-op):
up to date: skill create-spec · already identicalPreview without writing:
aiman import skill create-spec --from claude-code --printaiman import mcp
aiman import mcp <name> --from <env> [--print] [--overwrite] [--targets all]
aiman import mcp context7 --from claude-code
aiman import mcp jira --from cursor --print
aiman import mcp context7 --from claude-code --targets allScans the live configuration of the specified AI environment, locates MCP servers, applies env-strip, and writes the descriptor to the active inventory repository.
Arguments:
<name>— name of the MCP server to import.
Flags:
--from <env>— import source (required). Accepted values:claude-code,cursor,codex.--print— print the YAML descriptor to stdout without writing files.--overwrite— overwrite the existing file if content differs.--targets all— set all three adapters (claude-code,cursor,codex) as target environments in the descriptor. By default, only the source environment is used.
Behavior:
- Env-strip: real env variable values are not saved in
mcp/<name>.yaml. Instead, they are written toaim.local.yamlunder the keymcp_env: {<name>.<VAR>: value}. Only descriptors —name,required— go into the inventory. Sinceaim.local.yamlis excluded from Git, secrets never enter the repository. - Deduplication: if the same server name appears multiple times with the same command and arguments, the first entry is used.
- Ambiguity (AmbiguousError): if the same server name appears with different commands or arguments, the command fails — you must explicitly specify the source via
--from. - Server not found: if no server with the given name exists in the environment config, the command fails with
MCP server "<name>" not found in <env>. - Unknown environment: if the
--fromvalue is not recognized, the command fails withunknown environment: X; available: claude-code, cursor, codex. - if
mcp/<name>.yamlalready exists with the same content — succeeds with no changes; - if
mcp/<name>.yamlalready exists with different content and--overwriteis not set — returns an error with a hint to use--overwrite.
MCP configuration sources by AI environment:
| AI environment | Identifier | Configuration file |
|---|---|---|
| Claude Code | claude-code | ~/.claude.json (key mcpServers) |
| Cursor | cursor | ~/.cursor/mcp.json (key mcpServers) |
| Codex CLI | codex | ~/.codex/config.toml (section mcp_servers) |
Import from Claude Code:
aiman import mcp context7 --from claude-codeOutput on successful import:
imported: mcp context7 · from claude-codeIf the MCP server had env variables with populated values, they are written to aim.local.yaml:
imported: mcp context7 · from claude-code · secrets stored in aim.local.yamlOutput when the MCP server is already in the inventory with identical content (no-op):
up to date: mcp context7 · already identicalPreview the YAML descriptor without writing:
aiman import mcp context7 --from claude-code --printImport with all adapters set as targets:
aiman import mcp context7 --from claude-code --targets allOverwrite if the file already exists:
aiman import mcp context7 --from claude-code --overwriteCommands outside the current public scope
aiman list may be present in the codebase as a historical command, but its full public contract is deferred until loadouts and a complete inventory view are implemented.