akm docs

Bundles

akm works toward two outcomes: bring the agent assets you already have into one library, and install (or share) reusable capability bundles with other people. Both go through the same primitive — a bundle — which can be a local directory, a git repo, an npm package, or a crawled website. Registries are discovery indexes that let you find bundles you haven't heard of yet. Together they give you a unified, searchable library that pulls from anywhere and grows over time.

Bring what you already have into one library

If you already have skills, commands, or agent configs scattered across different tools, point akm at each of them. Nothing moves — akm indexes assets in place — and every asset becomes retrievable through the same search and curate commands regardless of which agent originally created it.

akm bundle add ~/.claude               # Claude Code's project/user assets
akm bundle add ~/.config/opencode      # OpenCode's config directory
akm index                              # Bring the search index up to date
akm curate "plan a release"            # Pull the best matches from every bundle you added

This is the "one library for every agent" idea in practice: assets authored for one tool become discoverable — and usable — from any other.

akm bundle add

akm bundle add connects a new bundle. The source kind is inferred from the input: known git hosts and URLs ending in .git are git bundles, while other HTTP(S) URLs are website bundles.

akm bundle add ~/.claude/skills                          # Local directory (filesystem)
akm bundle add github:owner/team-bundle                  # GitHub repo (git)
akm bundle add @scope/bundle                              # npm package
akm bundle add npm:@scope/bundle@latest                  # npm with version pin
akm bundle add github:owner/repo#v1.2.3                 # GitHub at a specific tag
akm bundle add https://docs.example.com --name docs     # Crawled website (website)
akm bundle add https://docs.example.com --max-pages 200 --max-depth 5

# Add the official onboarding bundle:
akm bundle add github:itlackey/akm-stash

# Mark a git bundle as writable (enables akm sync to push):
akm bundle add git@github.com:org/skills.git --provider git --name my-skills --writable

# Authenticate an HTTPS Git bundle without storing a token in its URL:
GIT_READ_TOKEN=... akm bundle add https://github.com/org/private.git --provider git \
  --name private --credential '$GIT_READ_TOKEN'

# Control secondary-bundle resolution priority (the default bundle is always first):
akm bundle add github:owner/team-bundle --name team --before community
Bundle kind Input shape Behavior
filesystem local path Indexed in place, writable by default
git github:, known git-host URL, or URL ending in .git Cloned into ~/.cache/akm/registry/, read-only by default
npm @scope/pkg Installed into cache, read-only
website Other HTTP/HTTPS URL Crawled, converted to markdown, refreshed every 12 hours

akm bundle add materializes and indexes Git install refs before it reports success. A declarative --provider git add does the same, including writable checkouts. Other declarative provider entries are materialized by akm bundle update.

Bundle naming. --name sets the bundle's key — akm's config, index, and every persisted ref hang off it. It is a contract, not a hint: it must be a legal bundle slug (no : . # / or whitespace), and it must not already be taken by a different bundle, or the add fails before writing anything. Re-adding a source that is already installed under a different --name than it already carries also fails, naming the existing key — use akm bundle rename instead of trying to relabel it through add. Every akm bundle add result carries bundleId (its resolved key), so scripting against the JSON output never has to guess it back out of sourceAdded/installed. Without --name, akm derives one (the directory name, the package/repo name, or the hostname), falling back to a -<hash> suffix only on a collision — that forgiving fallback applies solely to a derived name, never to an explicit --name.

Git credentials must be symbolic references: $VAR, ${VAR}, or secret://name. AKM resolves the reference only at the Git subprocess boundary and sends it as an HTTPS bearer header; it does not put the token in the remote URL or config.json.

Website bundles. A website URL is offered to a set of specialized fetchers (YouTube, Bluesky, X, RSS/Atom feeds) before falling back to a general crawl, and crawl behavior (page/depth limits, timeouts, robots.txt) is configurable. See the website source recipe for a walkthrough and Website Sources for the full fetcher reference, X credential setup, and crawl-option details. Low-level knobs like crawlTimeoutMs and respectRobots live in the bundle's website descriptor — see Configuration.

Example: add a team bundle from GitHub

akm bundle add github:my-org/team-bundle --name team
akm index
akm search "deploy" --type script

akm bundle list

akm bundle list shows all configured bundles — local directories, managed packages, and remote providers — so you know what is in your library.

akm bundle list                          # All bundles
akm bundle list --kind filesystem        # Only local directories
akm bundle list --kind git               # Only git-cloned bundles
akm bundle list --kind npm               # Only npm packages
akm bundle list --kind filesystem,git    # Multiple kinds (comma-separated)

Valid --kind values are the four bundle providers: filesystem, git, npm, website.

akm bundle update / akm bundle remove

akm bundle update refreshes git, npm, and website bundles. Each candidate is staged outside its active root, audited for dangerous environment keys, and only then published and indexed. akm bundle remove disconnects a bundle and re-indexes without it.

Bundle refresh is deliberately explicit: Git bundles do not poll upstream on their own. Consumers that want automatic refresh should schedule akm bundle update <name> or akm bundle update --all. Scheduled invocations should pass --skip-if-locked so concurrent index or improve activity becomes a successful skip instead of exit 75.

# Update
akm bundle update @scope/bundle          # One managed bundle
akm bundle update --all                 # All managed bundles
akm bundle update --all --force         # Force fresh download even if version unchanged
akm bundle update --all --skip-if-locked # Scheduled refresh: exit 0 on DB contention
akm bundle update @scope/bundle --allow-dangerous-env-keys  # Approve reviewed dangerous env keys

# Remove
akm bundle remove @scope/bundle          # By npm id
akm bundle remove github:owner/repo     # By git ref
akm bundle remove ~/.claude/skills      # By path
akm bundle remove my-provider           # By name

Dangerous keys prompt in a terminal (default: No) and block non-interactive updates unless --allow-dangerous-env-keys is explicit. --yes only approves deletion of an obsolete moved install directory; it never approves security findings. For --all, blocked and failed bundles are reported separately and later bundles continue. A rejected or failed bundle keeps its prior bytes, lock/config state, and search-index generation.

Private bundles that intentionally version every file under env/ and secrets/ can place this documented marker anywhere in their root .gitignore:

# akm: intentionally track env and secrets

The stash scaffold then leaves the ignore file unchanged. Use this only for a private remote whose exposure policy you have reviewed.

During publication AKM holds a SQLite writer transaction across the index and the update-owned state work. Existing readers keep seeing the prior generation, but other writers may wait for a full index pass. This provides process-fault rollback for handled errors, not atomic durability across the filesystem and two WAL database files during SIGKILL, power loss, or storage failure. After such a failure, stop writers, run akm health, rerun the targeted update if its checkout/lock is not the intended revision, and run akm index --full. The index-state-generation advisory detects mismatched durable usage links; it cannot detect every theoretical cross-file split.

Example: keep bundles fresh

akm bundle update --all && akm index

akm bundle rename

akm bundle rename <old> <new> is the one command allowed to change a configured bundle's key. A bundle id is a mass identity prefix: every ref this tool minted (entries.item_ref, proposals.ref, a pending proposal's write target, a workflow's task_history.target_ref, scheduler.enabled[].ref) carries it, so hand-editing the bundles key in config.json strands all of it — the rest of akm keeps reading the old prefix out of the index and state databases while config names the new one.

akm bundle rename old-name new-name --dry-run   # See the plan first
akm bundle rename old-name new-name

<new> must be a legal, unused bundle slug — the same --name contract akm bundle add enforces. Rewritten: the config key, defaultBundle/defaultWriteTarget when they name the old id, every scheduler ref, the lockfile entry, every indexed entry's bundle_id, and this tool's own state rows that name the old bundle. Reported, never rewritten: refs inside the bundle's own content (cross-references, a task's uses:, supersededBy) — the command lists the files that still spell the old <old>// prefix so you can fix them by hand. A real run also re-syncs native scheduler bindings under the new name on its own, so scheduled tasks pick it up immediately — but the result's taskSync.ok is false when a binding fails to re-sync too, not only when the sync call itself fails, so a partial re-sync is never reported as clean; --dry-run lists the installed native rows that still name the old bundle, so you can see what that sync will replace.

akm clone

akm clone copies a single asset from any bundle into your writable bundle (or a custom destination) for local editing. After cloning, your local copy wins in subsequent searches automatically.

akm clone scripts/deploy.sh
akm clone skills/code-review --name my-code-review
akm clone scripts/deploy.sh --dest ./project/.claude
akm clone "npm:@scope/pkg//scripts/deploy.sh"   # From uninstalled package

Clone is non-destructive: use --force to overwrite an existing local copy. Skills (directories with SKILL.md) are copied recursively. All other types copy a single file.

Example: clone and customize a workflow

akm clone workflows/ship-release --dest ./project/.claude
# Edit ./project/.claude/workflows/ship-release.md
# The local copy wins in searches from this directory forward

akm sync

akm sync stages, commits, and optionally pushes your writable bundle. It is the complement to akm bundle add: once you have made changes locally, sync persists them to git. (There is no akm save command — use akm sync.)

akm sync                          # Primary bundle, auto timestamp message
akm sync -m "Add deploy skill"   # Custom commit message
akm sync my-skills -m "Update"   # Named writable git bundle

Push behavior depends on configuration: if the bundle is a git repo with a remote and writable: true, sync also pushes. Otherwise it commits only.

Writes that land on a writable git bundle via an explicit destination flag (e.g. akm remember --bundle my-skills, proposal accept/revert, consolidate) are committed automatically in a single batch at the end of the operation — one complete commit (staging .akm/ + assets together), pushed under the same writable + remote gate as akm sync. options.pushOnCommit is rejected at config load; remove it and rely on writable: true + push instead.

Example: publish your own bundle

# One-time setup (git-descriptor primary bundles only): mark it writable by
# setting bundles.<name>.writable: true in ~/.config/akm/config.json.
# A filesystem-type primary bundle is already writable by default.
akm sync -m "Add deployment skills"
# → stages, commits, and pushes to your configured remote

For the full workflow of turning a bundle into something others can install — manifest conventions, versioning, and publishing to a registry — see the Bundle Author's Guide. For how a bundle's provider kind maps to the code that indexes and fetches it, see Architecture.

Install and share reusable capability bundles

The other half of the bundle story is discovery: finding bundles other people have published, and publishing your own so others can install it. akm bundle add (above) is how you install one once you know where it lives; the registry (below) is how you find it in the first place.

akm registry

The registry is a discovery index — it lets you find and install bundles you don't know about yet. The official registry ships pre-configured.

akm registry list                             # See configured registries
akm search "deploy" --from registry           # Search registry bundles by topic
akm search "code review" --from registry --assets  # Include asset-level hits
akm registry add https://example.com/registry/index.json --name my-team
akm registry remove my-team

Once you find an interesting bundle in the registry, install it with akm bundle add:

akm search "kubernetes" --from registry
akm bundle add github:some-org/k8s-bundle
akm index

For the registry index schema, hosting a private registry, and how entries get discovered, see Registry.

See also