A reconciler for units (skills, agents, commands, mcp-servers, hooks, and Claude plugins) across many tool homes and source repos. State lives in three YAML files — no database. Everything you press maps to an event and a real effect on disk.
← Back to the user guide| File | What it holds |
|---|---|
| manifest.yaml | Your source of truth: the sources you've added (with a target_layout mapping) and the units you manage. User-authored, git-diffable. |
| lock.yaml | Tool-authored resolved state: each unit's pinned SHA, where it deployed on each tool, and usage telemetry (invocation count + last-used). |
| library.yaml | Your own authored skills — a first-class personal library, kept separate from installed units. |
All three live under ~/.agents-in-a-box/. Reads and writes are plain serde load/save — reviewable in a PR, never an opaque store.
# Class-A walker — Claude marketplace plugins ~/.claude/plugins/cache/<marketplace>/<plugin>/<version>/.claude-plugin/plugin.json → marketplace:<plugin>@<marketplace> # Class-C walker — orphan units across 9 tool homes ~/.{claude,codex,copilot,gemini,cursor,amazonq,claude-desktop,cline,roo}/{skills,agents,commands,...}/ → one DiscoveredOrphanUnit per on-disk candidate # Provenance matcher — attribute each finding to its REAL source (pure) attribute(classA, classC, sources) → Vec<AttributedUnit> Marketplace | ExternalRepo (external-dependencies.yaml) | Toolkit | AlreadyAdopted | Local
plugin.json and treats a plugin as a bundle of skills — the exact layout other skill managers deliberately filter out. The provenance matcher resolves an externally-cloned skill back to its gh: upstream (via external-dependencies.yaml) instead of mislabelling it local:.A source maps unit globs to per-tool destinations, so one upstream publishes to arbitrary subdirs across many tools:
sources:
- name: my-skills
uri: gh:owner/repo
ref: main
target_layout:
- glob: "skills/*/SKILL.md"
home: ".claude/skills" # where it lands on your machine
repo: "skills" # where it lives in the repo
The pure resolve_pair(source, unit_path) translates each unit's path into its (home, repo) pair (first-glob-wins); an empty target_layout falls back to the bootstrap defaults.
SyncPlanner::plan_sync(source, mappings, units) # pure: decide direction per unit → Vec<SyncAction { direction: ToHome | ToRepo | NoOp }> ToHome → apply_to_home() # fetch upstream bytes, atomic write ToRepo → apply_to_repo() # copy, git add/commit/push (per-source lock)
Unlike one-way installers, ainb does push-back: edit a deployed file, press s, and apply_to_repo commits + pushes your change to the source. A per-source advisory lock at .git/ainb-sync.lock keeps two concurrent syncs from racing.
| Subsystem | Production | Tests |
|---|---|---|
| Drift | GitLsRemoteBackend — git ls-remote, compares deployed SHA vs upstream tip → ✓ / ⚠ / ▲ / ⟷. Background poll on screen open. | MockBackend |
| Catalog | SkillsShHttpBackend — reqwest to skills.sh; API key from config.toml [skills].api_key or AINB_SKILLS_API_KEY. | MockCatalogBackend (zero network) |
| Key | Event | Effect |
|---|---|---|
| m | GoToSkillManager / RefreshDiscovery | reload from disk · background drift poll · run walkers · (re-)show banner, clearing any skip-marker |
| Enter (banner) | SkillManagerDiscoveryImport | reconcile walker output → write manifest |
| i | OpenAddSource → InputSubmit | ainb source add <uri> in-process → reload |
| b | OpenBrowse → search → Enter | CatalogBackend.search → results modal → install selected |
| l | OpenLibrary | render library.yaml owned skills |
| u / r | Update / Remove | ainb skill update/remove <uri> on the selected unit → notification + reload |
| c | Check | re-trigger background drift scan → status glyphs refresh |
| s | Sync / ConflictFlip | no peer → SyncPlanner intent + sync: toast; conflict pair → flip shadowed_by |
| / | OpenSearch | filter Units case-insensitively (name / source / kind) |
A feature-gated sandbox fixture (build_skill_manager_sandbox) seeds a fake ~/.claude/~/.codex + a bare git remote — used by both in-process tests and a scripts/skill-manager-sandbox.sh up/down launcher for manual TUI testing. Coverage is three tiers: pure unit tests (mapping / uri / sync / provenance / catalog), CLI integration tests (real dispatch), and live tmux tripwires that spawn the real binary, press keys, and assert the captured pane — so every keybind is proven end-to-end against the actual program, not a stub.