aidem
AI development environment manager.
One content library, one-time tool bridges, one repo standard.
aidem solves two fragmentation problems caused by the wave of AI coding assistants:
- Content fragmentation — every AI tool wants skills, rules, and MCP configs in a different directory format. You maintain content in one aidem location (
~/.aidem/<kind>/) organized by kind;aidem setuplinks each tool's global directory to it once, so every skill you add afterwards surfaces as a native skill in whatever IDE the developer uses — with no per-skill-per-tool wiring. - Tool isolation — experimental AI agents each demand their own Python/Docker setup. You register a repo once, and
aidem run <tool>executes it from an aidem-owned isolated env at~/.aidem/envs/<tool>/— never polluting your global PATH or system Python. Runtime adapters (uv / prebuilt binary / docker) handle each ecosystem.
aidem does not ship skills — it ships the tools to manage them. It also does not pollute each repo with per-tool config files: repo-level standards collapse to a single committed AGENTS.md (read natively by Cursor, Copilot, and Kilo).
The Problem
Every major AI coding tool wants its own skills directory:
~/.cursor/skills/ # Cursor
~/.claude/skills/ # Claude Code
~/.kilo/skills/ # Kilo
A developer with 5 skills and 3 tools manually maintains 15 files across their home directory. Adding/removing a skill means touching 3+ places and cleaning up scattered stale files later.
Architecture: Centralized Bridging
┌──────────────────────────────────────────────────────────────────┐
│ aidem CLI │
│ │
│ aidem registry add <url> <name> ← clone a skill repo + link it │
│ aidem create <name> --skill ← author a skill locally │
│ aidem setup ← one-time dir bridges │
│ aidem init [path] ← write AGENTS.md into a repo│
│ aidem run <tool> <args> ← execute a registered tool │
└──────────────────────────────────────────────────────────────────┘
│ │ │
▼ ▼ ▼
┌─────────────────┐ ┌──────────────────┐ ┌──────────────────┐
│ Layer 0 │ │ Layer 1 │ │ Layer 2 │
│ Registry │ │ Central staging│ │ Execution │
│ │ │ + repo init │ │ │
│ git clone │ │ │ │ read manifest │
│ clone + │ │ A: aidem init │ │ find binary │
│ uv tool install │ │ → repo/AGENTS.md│ │ os.execvp │
│ │ │ │ │ pass-through │
│ │ │ B: ~/.aidem/skills│ │ │
│ │ │ (shared lib) │ │ │
│ │ │ │ │ │
│ │ │ aidem setup: │ │ │
│ │ │ ~/.<tool>/... │ │ │
│ │ │ →→→ config/... │ │ │
└─────────────────┘ └──────────────────┘ └──────────────────┘
Layer 0 — Registry
Skill/tool repos are git cloned into ~/.aidem/registry/<kind>/<name>/. On add, the repo's skill.md (or skills/**/SKILL.md) is symlinked into ~/.aidem/skills, along with any supporting subdirectories (e.g. rules/, references/). Repos that define a console script (pyproject.toml [project.scripts]) are also installed as uv tool in editable mode. Rule repos (--kind rule) link their rule.md/rules/*.md into ~/.aidem/rules as flat files instead.
Layer 1 — Central staging + repo conventions
aidem keeps one shared skill library — ~/.aidem/skills/. aidem setup links each tool's global skills dir to it once:
| Tool | IDE dot-folder | Bridged to |
|---|---|---|
| Kilo | ~/.kilo/skills |
~/.aidem/skills |
| Claude | ~/.claude/skills |
~/.aidem/skills |
| Cursor | ~/.cursor/skills |
~/.aidem/skills |
| OpenCode | ~/.config/opencode/skills |
~/.aidem/skills |
| Windsurf | ~/.codeium/windsurf/skills |
~/.aidem/skills |
Add/remove a skill in ~/.aidem/skills and every bridged tool sees it instantly.
The same model now extends to rules via ~/.aidem/rules/. Rules have no cross-tool standard (unlike skills), so each tool is bridged in the shape it supports:
| Tool | Global rules target | Bridge |
|---|---|---|
| Claude | ~/.claude/rules |
passthrough dir symlink → ~/.aidem/rules |
| Kilo | instructions[] in ~/.config/kilo/kilo.jsonc |
config-array glob entry |
| OpenCode | instructions[] in ~/.config/opencode/opencode.json |
config-array glob entry |
| Windsurf | ~/.codeium/windsurf/memories/global_rules.md |
concat mirror (6,000-char Windsurf cap; warns on overflow) |
| Cursor | — | skipped (User Rules are UI-only; project rules are repo-level .mdc) |
| GitHub Copilot | — | skipped (repo-level only) |
Add/remove a rule in ~/.aidem/rules and every bridged tool sees it on the next aidem setup.
For repo-level standards, aidem init <path> writes a single AGENTS.md. Tools that read it natively (Cursor, Copilot, Kilo) consume it directly — no per-tool files, no duplication. Commit it so every contributor gets the standard on clone with no aidem install required.
User data (~/.aidem/) is separated from the shipped package and survives upgrades. Override with AIDEM_DATA_DIR.
Layer 2 — Execution
aidem run <tool> <args> reads registry/manifest.json, resolves the tool's binary from its aidem-owned isolated env at ~/.aidem/envs/<tool>/bin/<binary>, and execs it with all args passed through via os.execvp. Exit codes and stdio are preserved; --help is passed through.
aidem never installs tool CLIs onto the global PATH (~/.local/bin). Each registered tool lives in its own isolated env, so same-named binaries never collide and the host system stays clean. The runtime kind (uv / binary / docker) is auto-detected from file markers and dispatches to a per-ecosystem adapter:
| Runtime | Mechanism | Host deps | Isolation | Example tools |
|---|---|---|---|---|
| uv (default for Python) | uv venv + uv pip install into ~/.aidem/envs/<n>/ |
Python + uv | full app isolation, no global PATH | headroom, any pyproject tool |
| binary | fetch GitHub release asset → extract → envs/<n>/bin/ |
none | fully sandboxed (single binary) | rtk, any release-asset tool |
| docker | docker run --rm -v $PWD:/work <image> <args> |
Docker only | OS-level sandbox, reproducible | any Dockerfile/image tool |
Auto-heuristics make aidem registry add <url> <name> one-command magic for the common cases (no flags required):
- uv: prefers a published PyPI wheel over an editable-from-clone build (avoids native-toolchain builds); defaults to the
[all]extras group if the clone declares it. Override with--spec "<pkg>[extras]"/--extras "...". - binary: queries the repo's GitHub Releases and picks the asset matching
{os}-{arch}(rtk shipsrtk-<arch>-<os>.tar.gz). Override with--asset "<glob>". - docker: pulls a
--image <ref>if given, else builds the clone'sDockerfileasaidem/<name>.
Detected-but-deferred ecosystems (npm, cargo, go) register as skills-only with a clear note until their runtimes ship.
Repository Structure
Shipped package (read-only, travels with the install):
aidem/ # the package
├── aidem_cli.py # CLI entry point
├── aidem_paths.py # Centralized path resolution (data dir vs package)
├── pyproject.toml # Package definition
├── README.md
├── LICENSE.md / CLA.md / NOTICE.md / CONTRIBUTING.md
├── tests/ # pytest suite (fake HOME/data dir via fixtures)
└── config/ # shipped assets (read-only)
├── AGENTS.md # Canonical agent context (repo template source)
├── overlays/ # Per-project-type AGENTS.md templates
│ ├── web-app/AGENTS.md
│ └── python-cli/AGENTS.md
├── generators/ # Per-tool bridge logic (one file per tool)
│ ├── base.py # Generator interface (skills + rules bridges)
│ ├── cursor.py # skills passthrough; rules skipped (no global path)
│ ├── kilo.py # skills passthrough/config fallback; rules → instructions[]
│ ├── claude.py # skills + rules passthrough → ~/.aidem/{skills,rules}
│ ├── github.py # no global path (repo-level only, both kinds)
│ └── windsurf.py # skills passthrough; rules → concat global_rules.md
└── runtimes/ # Per-ecosystem execution adapters (one file per runtime)
├── base.py # Runtime interface (install/resolve_binary/run/uninstall)
├── uv_venv.py # Python: uv venv + pip install into envs/<n>/
├── binary.py # Prebuilt: fetch release asset → envs/<n>/bin/
└── docker.py # Container: docker run --rm -v $PWD:/work
User data (writable, persistent, ~/.aidem/ — overridable via AIDEM_DATA_DIR):
~/.aidem/
├── skills/ # Shared skill library (real files + source symlinks)
├── rules/ # Shared rules library (flat *.md, one file per rule)
├── mcp/ # MCP server configs (when registered with --kind mcp)
├── envs/ # Layer 2: isolated tool envs (one dir per registered tool)
│ └── <name>/bin/<binary> # aidem resolves+execs from here, never global PATH
└── registry/ # Layer 0: git clones + manifest
├── manifest.json
└── skill/ # repos registered with --kind skill (singular kind label)
Installation
Requires Python 3.11+ and uv.
git clone https://github.com/bhave-sh/aidem.git ~/aidem
cd ~/aidem
uv tool install --editable .
aidem --help
Add aidem's bin to PATH if prompted (once, in your shell rc):
export PATH="$HOME/.local/bin:$PATH"
aidem stores user data (skills, registry, manifest) in ~/.aidem/ by default.
Override with the AIDEM_DATA_DIR env var (e.g. for testing or a non-default
profile). Shipped package assets (generators, overlays, canonical AGENTS.md)
travel with the install and are read-only.
Quick Start
1. Build the one-time tool bridges (once per machine)
aidem setup
This symlinks each tool's global skills dir into aidem's staging:
~/.kilo/skills -> ~/.aidem/skills~/.claude/skills -> ~/.aidem/skills~/.cursor/skills -> ~/.aidem/skills
Safe to re-run (idempotent). If a tool's parent directory isn't found (tool not installed), aidem skips it gracefully. Kilo falls back to a ~/.config/kilo/kilo.jsonc config entry when the symlink can't be created. aidem setup also bridges rules where a tool supports them (Claude dir symlink; Kilo/OpenCode config-array; Windsurf concat mirror; Cursor/GitHub skipped).
2. Create a skill or rule (author your own)
aidem create my-review-skill --skill
# opens $EDITOR with a skill template; save to commit it
# or non-interactively:
aidem create my-review-skill --skill --body "$(cat <<'MD'
# Skill: my-review-skill
## Purpose
Review code for correctness and style.
## When to Apply
During PR review.
MD
)"
Writes ~/.aidem/skills/my-review-skill/SKILL.md. Kilo, Claude, and Cursor see it instantly through their dir bridges.
aidem create no-emoji --rule --body "# Rule: no-emoji\nDo not use emojis in code or docs."
Writes ~/.aidem/rules/no-emoji.md (flat, one file per rule). Bridged tools see it on the next aidem setup. --skill is the default if neither flag is given.
3. Add a skill repo from the registry
aidem registry add https://github.com/example/my-scanner my-scanner --kind skill
Clones the repo into ~/.aidem/registry, symlinks its skill.md into ~/.aidem/skills. It now appears in Kilo, Claude, and Cursor — no per-tool wiring.
4. Update the standard in a repo
cd ~/projects/my-web-app
aidem init --template web-app
Writes a single AGENTS.md (no per-tool files). Commit it so teammates inherit the standard on clone.
5. Run a registered tool
aidem run my-scanner .
aidem run my-scanner --format json --output report.json
Tools install into an isolated, aidem-owned env — no global PATH pollution, no same-name clashes. The runtime is auto-detected:
# Python tool with a pyproject.toml -> uv runtime (PyPI wheel preferred, [all] extras if declared)
aidem registry add https://github.com/headroomlabs-ai/headroom headroom
aidem run headroom doctor
# Rust/Go single-binary tool -> binary runtime (GitHub release asset, platform-matched)
aidem registry add https://github.com/rtk-ai/rtk rtk
aidem run rtk git status
# Tool shipping a Dockerfile -> docker runtime (ephemeral container, cwd mounted)
aidem registry add https://github.com/example/container-tool ctool
aidem run ctool scan .
Command Reference
Registry commands (aidem registry ...)
aidem registry add <git-url> <name> [--kind skill|rule|mcp|memory|plan]
[--runtime uv|binary|docker] [--spec "<pkg>[extras]"] [--extras "..."]
[--asset "<glob>"] [--image "<ref>"] [--no-install]
# Clone a repo, link its content into ~/.aidem/<kind>, and install its tool
# binary into an aidem-owned isolated env (~/.aidem/envs/<name>/) — never the
# global PATH. Runtime is auto-detected from file markers (pyproject->uv,
# Cargo/go->binary, Dockerfile->docker); flags override the auto-heuristic.
# Defaults to --kind skill. Deferred ecosystems (npm/cargo/go) register as
# skills-only with a note until their runtimes ship.
aidem registry setup
# Re-clone missing registered repos and install those that define binaries.
aidem registry update
# Pull updates for all cloned repos (then run `aidem setup` to refresh links).
aidem registry install <name>
# Install or reinstall a single registered tool into its isolated env.
aidem registry remove <name>
# Unregister, remove clone, tear down the isolated env, and unlink content.
aidem registry list
# Show registered skills/tools, runtime kind, and env install state.
Skill & rule authoring & bridging
aidem create <name> --skill|--rule [--body <text>]
# Author a skill (~/.aidem/skills/<name>/SKILL.md) or a rule
# (~/.aidem/rules/<name>.md) in aidem's central library. Opens $EDITOR, or
# use --body. --skill is the default when neither flag is given.
aidem setup
# Build/regenerate the one-time dir bridges for skills and rules. Idempotent.
Repo standard & execution
aidem init [project_path] [--template <name>] [--link/--copy] [--force]
# Write one AGENTS.md into a repo. Prompts if writing to cwd; refuses inside the aidem package dir unless --force.
aidem run <tool> [args...]
# Execute a registered tool from its isolated env (~/.aidem/envs/<tool>/bin),
# passing all arguments through. Exit codes and stdio preserved; --help works.
# A legacy global-PATH install still runs but prints a one-time migration nudge.
How the Centralized Model Works
┌──────────────────────────────────────┐
│ ~/.aidem/skills (single lib) │
│ ├── my-review-skill/ │
│ │ └── SKILL.md (created) │
│ ├── my-scanner/ │
│ │ └── SKILL.md → symlink │
│ └── ... │
└───────────────┬───────────────────────┘
│
┌──────────────────────────────┼──────────────────────────────┐
▼ ▼ ▼
~/.kilo/skills ~/.claude/skills ~/.cursor/skills
→→→ ~/.aidem/skills →→→ ~/.aidem/skills →→→ ~/.aidem/skills
(passthrough dir symlink) (passthrough dir symlink) (passthrough dir symlink)
- One maintenance point: edit
~/.aidem/skills; all tools update live (they dereference the dir symlink). - Adding a skill = one write into
~/.aidem/skills— not N writes across the home directory. - Removing a skill = one unlink in
~/.aidem/skills— not hunting through~/.cursor,~/.claude,~/.kilo. - Cleanup =
rm -rf ~/.aidem/skills/*and the few dir symlinks. No scattered stale files.
Rules work the same way from ~/.aidem/rules — Claude gets a passthrough dir symlink, Kilo/OpenCode get an instructions config-array entry, Windsurf gets a concat mirror; edit once, re-run aidem setup.
To add support for a new AI tool, add a generator in config/generators/<tool>.py that sets global_path and staging_dir for skills, and rules_global_path (or an ensure_rules_bridge / regenerate_rules override) for rules. Override format_skill/regenerate only if its format differs, and is passthrough otherwise. Register it in config/generators/__init__.py.
Why This Architecture?
| Concern | Without aidem | With aidem |
|---|---|---|
| Skill duplication | Copy each skill into every tool's dir, in each tool's format | One ~/.aidem/skills library; tools dir-symlink into it once |
| Scattered home pollution | N×M files across ~/.cursor, ~/.claude, ~/.kilo |
A few dir symlinks; skills live under ~/.aidem/ |
| Adding a skill | Write into 3+ home dirs | One directory in ~/.aidem/skills |
| Removing a skill | Hunt across home dirs for stale links/copies | One unlink in ~/.aidem/skills |
| Live skill updates | Edit the file in every tool | Edit ~/.aidem/skills; all tools update instantly |
| Repo config bloat | 5+ per-tool files per repo | One AGENTS.md per repo, no per-tool files |
| Tool isolation | Install every agent into system/project Python | Each tool has its own aidem-owned env (~/.aidem/envs/<n>/); runtime adapters (uv/binary/docker) keep the global PATH clean |
| New AI tool support | Re-wire every skill into its new format | Add one generator file; one-time bridge |
| Repo contribution friction | Contributors must install your config tool | They just clone — AGENTS.md is a static committed file |
Future Work
aidem centralizes skills and rules. The same architecture extends naturally to other AI development artifacts:
Rules (done)
A ~/.aidem/rules/ library with per-tool bridges now ships: Claude gets a passthrough dir symlink, Kilo/OpenCode get an instructions config-array entry, and Windsurf gets a concat mirror (capped at Windsurf's 6,000-char global_rules.md limit). Cursor and GitHub Copilot have no file-based global rules path and are skipped. Author rules with aidem create <name> --rule; register rule repos with aidem registry add <url> <name> --kind rule. Project-level rule init (writing per-tool .cursor/rules/*.mdc, .devin/rules/*.md, … into a repo) is deliberately out of scope — it would reintroduce the per-tool file bloat aidem's single AGENTS.md model avoids.
MCP server configuration
Configuring MCP servers once and having them available in every tool is the top pain point for multi-tool users. Each tool uses a different config format, so this needs per-tool transform generators (like aidem originally had for Cursor .mdc mirrors) — not just passthrough symlinks. Higher complexity, higher user value.
Plans and memory
These concepts are deeply vendor-specific with no emerging standard. Aidem would need a canonical format plus per-tool transformers. Lower priority until the ecosystem converges.
Runtimes (done + deferred)
Layer 2 execution uses a runtime-adapter model: aidem owns an isolated env per tool (~/.aidem/envs/<n>/) and resolves+execs the binary from it, never the global PATH. Shipped: uv (Python, PyPI-wheel-preferred + [all]-extras heuristic), binary (prebuilt release asset, platform-matched), docker (ephemeral container, cwd mounted). Detected but deferred: npm, cargo, go (register as skills-only until their runtimes ship). To add a new runtime, create config/runtimes/<name>.py subclassing Runtime (implement install/resolve_binary/run/uninstall/is_installed), add a marker in config/runtimes/__init__.py, and add the kind to RUNTIME_KINDS.
Kind-specific content formats
The --kind flag drives which plural container content is linked into (~/.aidem/skills, ~/.aidem/rules, etc.). Content detection is now kind-aware (_content_source_for looks for rule.md/rules/*.md for rules, SKILL.md/skills/**/SKILL.md for skills). Remaining work: recognize richer per-kind conventions (e.g. .mdc frontmatter for project rules, JSON for MCP) when those kinds are built out.
To add support for a new artifact type, add a generator in config/generators/<tool>.py that implements the kind's bridge method (e.g. ensure_rules_bridge), register the kind in REGISTRY_KINDS, and extend _content_source_for / _add_shared_content for the new shape.
Contributing
Contributions are welcome — see CONTRIBUTING.md for the development setup, how to run the test suite, how to add a generator for a new AI tool, and code style.
By contributing, you agree to the Contributor License Agreement.
License
aidem is licensed under the Apache License 2.0.
See NOTICE.md for third-party dependency licenses and registry tool licensing details.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file aidem-0.1.0.tar.gz.
File metadata
- Download URL: aidem-0.1.0.tar.gz
- Upload date:
- Size: 44.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3b14497199519ba5dd60acf7bc16170d6c3f33f7be28074642eac01789d37dce
|
|
| MD5 |
99219e0b4cbcffd8f55955339cf46dee
|
|
| BLAKE2b-256 |
d76387cf06d82a6c987282720152632cc5156f889ffeefd77bb10d141846597f
|
Provenance
The following attestation bundles were made for aidem-0.1.0.tar.gz:
Publisher:
release.yml on bhave-sh/aidem
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
aidem-0.1.0.tar.gz -
Subject digest:
3b14497199519ba5dd60acf7bc16170d6c3f33f7be28074642eac01789d37dce - Sigstore transparency entry: 2216629913
- Sigstore integration time:
-
Permalink:
bhave-sh/aidem@95afbdb797ebe50a765863ed2e811f58731094f0 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/bhave-sh
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@95afbdb797ebe50a765863ed2e811f58731094f0 -
Trigger Event:
push
-
Statement type:
File details
Details for the file aidem-0.1.0-py3-none-any.whl.
File metadata
- Download URL: aidem-0.1.0-py3-none-any.whl
- Upload date:
- Size: 47.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
700b24c7c7e7b7df833594cb144f190e0256efb3d4fcbc99b0c565fcdf2caabd
|
|
| MD5 |
7725a7d6481482e72bce4a563e3d3e2c
|
|
| BLAKE2b-256 |
5a0b471b4202ceb9d099f66a90f40672fd2da73ba6b9c9711dbe081e22b27d01
|
Provenance
The following attestation bundles were made for aidem-0.1.0-py3-none-any.whl:
Publisher:
release.yml on bhave-sh/aidem
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
aidem-0.1.0-py3-none-any.whl -
Subject digest:
700b24c7c7e7b7df833594cb144f190e0256efb3d4fcbc99b0c565fcdf2caabd - Sigstore transparency entry: 2216630002
- Sigstore integration time:
-
Permalink:
bhave-sh/aidem@95afbdb797ebe50a765863ed2e811f58731094f0 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/bhave-sh
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@95afbdb797ebe50a765863ed2e811f58731094f0 -
Trigger Event:
push
-
Statement type: