Skip to content

Workflows

Adding a skill from a file

To add a ready-made skill to your inventory:

bash
aiman add skill path/to/skill.md

If a file with that name already exists in the inventory with different content:

bash
aiman add skill path/to/skill.md --overwrite    # overwrite
aiman add skill path/to/skill.md --name new-name  # save under a different name

From stdin:

bash
cat skill.md | aiman add skill -

After adding, run aiman push to publish the change.

Adding an MCP server from a file

To add an MCP server configuration to your inventory:

bash
aiman add mcp path/to/server.yaml

If a file with that name already exists in the inventory with different content:

bash
aiman add mcp path/to/server.yaml --overwrite    # overwrite
aiman add mcp path/to/server.yaml --name new-name  # save under a different name

From stdin:

bash
cat server.yaml | aiman add mcp -

If the input file contains value fields in the env block, AIM automatically moves them to aim.local.yaml and does not write them to mcp/<name>.yaml. This ensures secrets never end up in Git.

After adding, run aiman push to publish the change.

Importing a skill from an AI environment

Import writes only to the active inventory repository. If none is connected yet, the command fails with no active inventory repository; run 'aiman init' first and creates nothing in the current directory — run aiman init <url> or aiman switch <path> first.

If a skill is already installed in one of your AI environments, you can import it directly:

bash
aiman import skill hello --from claude-code
aiman import skill review-code --from codex

Preview the content without writing:

bash
aiman import skill hello --from claude-code --print

Supported sources: claude-code, cursor, codex.

The skill is transferred in full: if the environment stores it as a folder (<name>/SKILL.md plus references/ and scripts), both SKILL.md and every resource file end up in the inventory. File permissions are not preserved along the way — the executable bit on scripts is lost, see Troubleshooting.

After adding, run aiman push to publish the change.

Importing an MCP server from an AI environment

If an MCP server is already configured in one of your AI environments, you can import it directly:

bash
aiman import mcp context7 --from claude-code
aiman import mcp jira --from cursor

Preview the content without writing:

bash
aiman import mcp context7 --from claude-code --print

Import and set all three AI environments as targets:

bash
aiman import mcp context7 --from claude-code --targets all

Supported sources: claude-code, cursor, codex.

AIM reads the live configuration of the specified environment, extracts the MCP server descriptor, and applies env-strip: real env variable values are written to aim.local.yaml, while only descriptors without secrets go to the inventory and Git. Env variable descriptors are sorted by name, so re-importing an unchanged server produces no spurious Git diffs.

Only stdio servers can be imported — those that define a command in the environment config. A server declared with "type": "http", "type": "sse", or a bare "url" is not imported: the command fails with the reason and writes nothing to the inventory.

If a server with that name already exists in the inventory with different content, the command fails. To overwrite, use --overwrite:

bash
aiman import mcp context7 --from claude-code --overwrite

After adding, run aiman push to publish the change.

Local iteration: edit → apply → test

Use aiman apply when you want to test a change before publishing.

bash
$EDITOR skills/review-code.md
aiman apply

What apply does:

  • reads local skills/ and mcp/;
  • validates items;
  • applies valid items to detected AI environments;
  • does not commit;
  • does not contact the remote;
  • does not update published_hash or synced_hash.

This cycle is intended for skill development: edit, apply, check in your AI tool, edit again. Most AI environments read skills at session start — after aiman apply, restart the agent session to pick up the changes.

Context switching: apply --loadout

As the inventory grows, not every skill is needed for every task. A loadout — a named subset of the inventory — lets you keep only the relevant set in your AI environments.

Describe the set in loadouts/<name>.yaml:

yaml
# loadouts/documentation-work.yaml
name: Documentation Work
description: Skills and MCP servers for documentation work
items:
  - skill:create-spec
  - skill:wpage
  - mcp:context7

Review the plan, then apply it:

bash
aiman apply --loadout documentation-work --dry-run
aiman apply --loadout documentation-work

The apply is declarative: environments are brought to exactly the loadout's set. Inventory items outside the loadout are removed from environments (D in the change delta), while files outside the inventory are left untouched. Always start with --dry-run — it shows exactly what will be removed:

text
[dry-run] would apply loadout "Documentation Work" — 4 changes to 1 environment (claude-code):
  A skills/create-spec.md   (new in all environments)
  D skills/review-code.md   (would remove from all environments)
  M skills/wpage.md   (differs in all environments)
  A mcp/context7.yaml   (new in all environments)

To go back to the full set, run a plain aiman apply or aiman sync.

To make a loadout available on other machines, publish it — aiman push validates the files in loadouts/ and publishes them together with the rest of the inventory:

bash
aiman push

Updating from remote while staying in a loadout: pinning

By default, aiman sync is the transport for the full inventory: it applies everything and expands the environment back to the full set, even if you had narrowed it earlier with apply --loadout. For a one-off sync, you can work around this with the syncapply --loadout <name> pattern, but if you update from remote often, you'd have to repeat it every time.

If you work in a narrow loadout for an extended period — say, you spend a few days doing nothing but documentation work — and want sync to apply that same set on its own, pin the loadout:

bash
aiman apply --loadout documentation-work --pin

A pin is persisted state in the global config, not a one-off action: it stays active across CLI runs until you explicitly change it. While the pin is set, aiman sync declaratively brings environments to the pinned loadout's set instead of the full inventory — the same way as apply --loadout <name>, including removing items outside the set:

bash
aiman sync
text
applying loadout "documentation-work" (pinned)
synced: 67451fc · 2 skills, 1 MCP server → 1 environment
  A skills/create-spec.md   (new in all environments)
  M skills/wpage.md   (updated in all environments)

To check which loadout is currently pinned, run aiman status — the Pinned loadout: field shows its name or none.

To go back to the full inventory and clear the pin in one action:

bash
aiman apply --default

To just clear the pin without applying anything (for example, if you want to pick the next loadout manually):

bash
aiman apply --unpin

If the pin points to a loadout that no longer exists (renamed, deleted, or switch moved to a repository without a loadout of that name), sync stops with an error instead of silently falling back to the full set:

text
error: pinned loadout "documentation-work" not found in inventory

Clear the pin (aiman apply --unpin or --default) or restore the loadout under the expected name — see Troubleshooting for details.

aiman switch to a different inventory repository always clears the pin unconditionally, even if the new repository has a loadout with the same name — pin it again with apply --loadout <name> --pin if you need to.

For how a pin differs from a one-off apply --loadout <name>, see Concepts. For the full description of flags and output, see the CLI Reference.

Publishing: status → push

When a local change is ready:

bash
aiman status
aiman push

status shows the repository position relative to origin/main, the state of AI environments, and the list of changes in skills/, mcp/, and loadouts/ that have not yet been published.

status is a network command: it runs a Git fetch before calculating the position, so the result reflects the actual remote state rather than a stale local ref. A short fetch delay is expected behavior. See Concepts for the reasoning.

TODO: add a spinner during fetch

Example output when there are unpublished changes:

text
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

push validates the inventory, creates a commit, and pushes it to the remote repository. If the repository has a loadouts/ directory, the loadout files are validated too: their format and the referential integrity of items (a broken reference blocks publishing). After publishing, it shows the delta of what was published:

text
published: 96e091b · 19 skills, 1 MCP server
  M skills/review-code.md
  A mcp/jira.yaml

push --dry-run shows the publish plan without writing to Git:

bash
aiman push --dry-run

Moving to another machine: init → sync

On a new machine:

bash
aiman init git@github.com:you/aim-loadout.git
aiman sync

sync runs a Git fetch, verifies history, fetches the published state, and applies it to the local AI environments. After applying, it shows the delta of incoming changes:

text
synced: 67451fc · 21 skills, 1 MCP server → 3 environments
  M skills/commit-message.md
  A skills/refactor-helper.md

The counters on the result line are the operation volume (total applied); the block below is the change delta. If nothing came in from remote, the block is omitted.

Protecting against lost changes

sync does not block on untracked files in skills/, mcp/, or loadouts/ unless they conflict by name with a file being introduced from remote. A new skill or loadout that has not been committed yet is preserved.

If an untracked file matches the name of a file coming from remote, sync stops and lists the conflicting files:

bash
aiman sync
# error: untracked file conflicts with remote: skills/review-code.md

At that point you have three options:

  • publish the conflicting file with aiman push, so it becomes part of the remote state;
  • rename or move the file manually, then retry aiman sync;
  • apply the published state and permanently delete the conflicting files:
bash
aiman sync --force

Warning: sync --force permanently deletes conflicting files from the working tree. This cannot be undone.

--force never deletes files silently: before applying the state, AIM prints a list of what was removed:

text
discarded untracked files (--force):
  skills/draft.md
  mcp/local-only.yaml
synced: 67451fc · 21 skills, 1 MCP server → 3 environments

This protection covers skills/, mcp/, and loadouts/: an untracked file in any of these directories is either preserved or explicitly listed as a conflict.

History states

After fetch, AIM distinguishes several situations:

StateBehavior
Local is already equal to remoteapply inventory without reset
Local is behind remotefast-forward reset and apply
Local has unpublished commitsstop and ask for aiman push
History has divergedstop and ask for manual Git recovery

When to use which command

TaskCommand
Add a skill from a fileaiman add skill <file>
Add an MCP server from a fileaiman add mcp <file>
Import a skill from an AI environmentaiman import skill <name> --from <env>
Preview a skill without writingaiman import skill <name> --from <env> --print
Import an MCP server from an AI environmentaiman import mcp <name> --from <env>
Preview an MCP descriptor without writingaiman import mcp <name> --from <env> --print
Test a local skill without publishingaiman apply
Apply a named subset of the inventoryaiman apply --loadout <name>
Review the loadout plan before applyingaiman apply --loadout <name> --dry-run
Publish a new or changed loadoutaiman push
Pin a loadout so sync applies it instead of the full inventoryaiman apply --loadout <name> --pin
Check which loadout is pinnedaiman status
Go back to the full inventory and clear the pinaiman apply --default
Clear the pin without applying anythingaiman apply --unpin
See what has changedaiman status
Publish the ready inventoryaiman push
Apply published inventory on a machineaiman sync
Check environment and configsaiman doctor

Released under the Apache 2.0 License.