aidem
AI development environment manager.
One content library, one-time tool bridges, isolated tools.
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.
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 registry add -> ~/.aidem/registry + ~/.aidem/skills
aidem create -> ~/.aidem/skills or ~/.aidem/rules
aidem setup -> global tool bridges and config
aidem run -> isolated registered tool environment
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) and regular supporting content are copied into ~/.aidem/skills; symlinked or special files are rejected. Rule repos (--kind rule) copy their rule.md/rules/*.md into ~/.aidem/rules as flat files. aidem registry update pulls the clones and refreshes these materialized copies.
Layer 1 — Central staging
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.
Capability Coverage
This matrix shows what Aidem currently syncs from its central libraries. It describes Aidem support, not every capability offered by each tool.
| Tool | Skills | Rules | MCP | Memory | Transcripts | Hooks | Plans | |---|---|---|---|---|---|---|---|---| | Kilo | Done | Done | Done | Planned | Planned | Planned | Planned | | Claude Code | Done | Done | Done | Planned | Planned | Planned | Planned | | Cursor | Done | Planned | Done | Planned | Planned | Planned | Planned | | OpenCode | Done | Done | Done | Planned | Planned | Planned | Planned | | Windsurf | Done | Partial | Planned | Planned | Planned | Planned | Planned | | GitHub Copilot | Planned | Planned | Planned | Planned | Planned | Planned |
Status legend: Done is currently synced, Partial uses a tool-specific format or limitation, Planned is not synced yet, and N/A has no direct compatible location in the current bridge model.
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 pinned GitHub release asset → verify SHA-256 → extract → envs/<n>/bin/ |
none | isolated env | rtk, any release-asset tool |
| docker | hardened docker run with read-only worktree by default |
Docker only | network-disabled, non-privileged container | any Dockerfile/image tool |
Auto-heuristics make aidem registry add <url> <name> one-command magic for the common cases (no flags required):
- uv: installs the checked-out clone by default;
--spec "<pkg>[extras]"is an explicit PyPI override.--extras "..."selects optional dependencies from the clone. - binary: requires a pinned
--release <tag>and--sha256 <digest>, then picks the asset matching{os}-{arch}. Override with--asset "<substring>". - docker: pulls a digest-pinned
--image <ref>if given, else builds the clone'sDockerfileasaidem/<name>. Runtime worktree writes require--write-worktree.
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)
├── 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 (materialized regular files)
├── 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+. uv is required for aidem's isolated tool runtime.
Install from PyPI
For an isolated global CLI, use uv or pipx:
uv tool install aidem
# or: pipx install aidem
For a virtual environment with pip:
python3 -m venv .venv
source .venv/bin/activate
python -m pip install aidem
Verify the installation:
aidem --help
When using pip, activate the virtual environment before running aidem.
Install from source
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 and runtimes)
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 and copies its tool-specific content into ~/.aidem/skills. It now appears in Kilo, Claude, and Cursor — no per-tool wiring.
4. 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 (clone installed by default)
aidem registry add https://github.com/headroomlabs-ai/headroom headroom
aidem run headroom doctor
# Rust/Go single-binary tool -> binary runtime (pinned release + digest)
aidem registry add https://github.com/rtk-ai/rtk rtk \
--release v1.0.0 --sha256 <64-hex-digest>
aidem run rtk git status
# Tool shipping a Dockerfile -> hardened Docker runtime
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 "<substring>"] [--release <tag>] [--sha256 <digest>]
[--image "<digest-pinned-ref>"] [--write-worktree] [--no-install]
# Clone a repo, copy its content into ~/.aidem/<kind>, and optionally 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, refresh materialized skill/rule copies, and regenerate mirrors.
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.
Execution
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 (copied) │
│ └── ... │
└───────────────┬───────────────────────┘
│
┌──────────────────────────────┼──────────────────────────────┐
▼ ▼ ▼
~/.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 through the top-level dir bridge. - 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 |
| Registry updates | Reclone and rewire every tool | aidem registry update refreshes copies, then tools see the same library |
| 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 |
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 setup (planned)
Repository setup will be added under aidem project ...; the global aidem setup command remains limited to user-level bridges and libraries.
MCP server configuration
Organization MCP definitions are validated and disabled by default. Enable them explicitly during login or sync with --allow-org-mcp; each tool uses a different config format, so per-tool transform generators remain responsible for the final config shape.
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, clone-first with explicit PyPI override), binary (pinned release asset with mandatory SHA-256), docker (hardened ephemeral container, read-only worktree by default). 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.3.tar.gz.
File metadata
- Download URL: aidem-0.1.3.tar.gz
- Upload date:
- Size: 59.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8a5a72a854ea0437e1c0f9101aa604870a073afde2f21d9876df3e49ae9fd26e
|
|
| MD5 |
dc64af7c9659743e597df0117044f351
|
|
| BLAKE2b-256 |
afd2b8a6727c621d714fbd07ccda0101925035f8d11514bdc8263db44a22839d
|
Provenance
The following attestation bundles were made for aidem-0.1.3.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.3.tar.gz -
Subject digest:
8a5a72a854ea0437e1c0f9101aa604870a073afde2f21d9876df3e49ae9fd26e - Sigstore transparency entry: 2405077781
- Sigstore integration time:
-
Permalink:
bhave-sh/aidem@9238c2d91006dea9f4d74240b20589e73eef7e6c -
Branch / Tag:
refs/tags/v0.1.3 - Owner: https://github.com/bhave-sh
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@9238c2d91006dea9f4d74240b20589e73eef7e6c -
Trigger Event:
push
-
Statement type:
File details
Details for the file aidem-0.1.3-py3-none-any.whl.
File metadata
- Download URL: aidem-0.1.3-py3-none-any.whl
- Upload date:
- Size: 62.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e1d8e0727291e6af40588b6d37932ee72c289e16157f4a9e875ac10185b38ca5
|
|
| MD5 |
09d256db5bac7d2d9b23f6668df72ad5
|
|
| BLAKE2b-256 |
abe5d3eedf82a6ae13d51375468ea927a3dda3b0271c8c77172211a636507329
|
Provenance
The following attestation bundles were made for aidem-0.1.3-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.3-py3-none-any.whl -
Subject digest:
e1d8e0727291e6af40588b6d37932ee72c289e16157f4a9e875ac10185b38ca5 - Sigstore transparency entry: 2405078223
- Sigstore integration time:
-
Permalink:
bhave-sh/aidem@9238c2d91006dea9f4d74240b20589e73eef7e6c -
Branch / Tag:
refs/tags/v0.1.3 - Owner: https://github.com/bhave-sh
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@9238c2d91006dea9f4d74240b20589e73eef7e6c -
Trigger Event:
push
-
Statement type: