blevene/aenv/aenv
Claude Code and agent skill by blevene/aenv
- community
- ext:[{"type":"hook","description":"Pre/post lifecycle hooks"}]
Checking that the SKILL.md file is still in the repository.
Use when the user wants to set up, switch between, or manage `aenv` namespaces — named bundles of CLAUDE.md, skills, MCP entries, and other AI-coding-harness config — in a project OR globally across `$HOME`. Triggers include `aenv …` mentioned directly, "switch namespace/profile", "activate/deactivate", "create/snapshot a namespace", "install a skill (from GitHub)", "auto-activate on cd", "what namespace am I using"; and for the global scope: "swap my global/user-level config (`~/.claude`, `~/.codex`)", "use a different Claude Code setup globally", "onboard a config repo like claude-ctrl", "swap back to my old setup". Don't use for secrets, Python venv, or Claude Code plugin marketplace ops.
Install
npx vskill@latest install blevene/aenv/aenvSemi-extensibleMentions customization, but needs skill-specific knowledge. Read the extensible skills standard
SKILL.md
aenv
aenv is a CLI that manages named bundles of AI-coding-harness configuration (CLAUDE.md, .cursorrules, .mcp.json, skills, agents, etc.) — pin a project to a namespace, activate it, and the bundle materializes into the project as symlinks. Deactivate restores the project to its pre-activation state byte-for-byte.
Mental model in three sentences
Namespaces live at ~/.aenv/envs/<name>/ and own a manifest (aenv.toml) plus the actual files. A project gets pinned to a namespace via a one-line .aenv file at its root; aenv activate reads the pin, walks the extends chain, and materializes the resolved bundle. State lives in .aenv-state/state.json and the displaced originals (if any) sit in .aenv-state/backup/<timestamp>/ until aenv deactivate puts them back.
Two scopes: project vs global
aenv works at two scopes, and the verb prefix tells them apart:
- Project scope (
aenv <verb>) — materializes a namespace's project files into a pinned project directory (the section above). State under<project>/.aenv-state/. - Global scope (
aenv global <verb>) — materializes a namespace's user-scope files (declared asuser_files) into$HOME(~/.claude/,~/.codex/, …). One global activation lives per user; activating another swaps it in a single transaction. State at~/.aenv/global-state.json, displaced originals stashed under~/.aenv/global-stash/<ts>/. This is how you swap your whole Claude Code / Codex setup. See the Global profiles section below.
User request → command map
| User wants… | Run this | |||
|---|---|---|---|---|
| Set up a new namespace from scratch | aenv create <name> --adapter claude-code (also creates an empty CLAUDE.md; user edits it) | |||
| Build on top of an existing namespace | aenv create <name> --extends <parent> (composition; child overrides win section-by-section) | |||
| Capture a hand-shaped project as a reusable namespace | aenv snapshot <name> from inside the project | |||
| Pin + activate in a project | aenv use <name> then aenv activate. (Avoid aenv activate <name> without use first — it activates without writing a .aenv pin, leaving the project in a half-state where aenv status works but no future invocation knows what namespace was intended.) | |||
| Switch active namespace in a project | aenv deactivate && aenv use <other> && aenv activate | |||
| Restore project to pre-aenv state | aenv deactivate (then aenv unpin if they want the .aenv pin file gone too) | |||
| Add a skill they wrote themselves | aenv skill new <skill-name> --ns <namespace> | |||
| Install a skill from a public GitHub repo | aenv skill import git+<url> --ns <ns> --pin <ref> [--path <subdir>] — see "Pin selection" below | |||
| Install MANY skills from a monorepo at once | aenv skill import-all git+<url> --ns <ns> --base <dir> --pin <ref> [--only a,b] — clones once, imports every <base>/<subdir>/SKILL.md; malformed skills are warned + skipped, re-runs are idempotent | |||
| Copy non-skill content (agents, commands, reference docs) from a repo | aenv vendor git+<url> --ns <ns> --pin <ref> --path <subtree> --as <dest> — copies into the namespace tree, declares it under the adapter's files, records [[vendored]] provenance. --force to overwrite, re-run to refresh + report drift | |||
| Remove a skill | aenv skill remove <skill-name> --ns <ns> | |||
| Reclaim cache space (orphaned skill clones) | aenv cache prune | |||
| See what's active in the current project | aenv status | |||
| See where a managed file came from | aenv which <project-relative-path> | |||
| Show the resolution chain + parameters + policies | aenv status (text) or aenv status --json (structured) | |||
| Compare two namespaces | aenv diff <ns_a> <ns_b> | |||
| Detect drift between project and active namespace | aenv diff (no args; runs against active) | |||
| Bump a pinned skill ref | edit ~/.aenv/envs/<ns>/aenv.toml, change ref = line, then re-activate in any project using the namespace | |||
| Auto-activate on cd between projects | `aenv init-shell <bash\ | zsh\ | fish>` printed once into the user's rc file |
Pin selection (for aenv skill import --pin <ref>)
When the user wants to import a skill, ask which form of pin they want (or pick a default and tell them):
- Tag (
v1.0,v2.39.0) — when the source repo has releases. Semantic; reads cleanly. Find via repo's Releases tab. - Commit SHA (40-char hex) — when there are no tags, or for absolute immutability. Find via repo's Commits view; the URL ends with the full SHA.
- Branch name (
main) — only when the user actually wants to track that branch's head at the moment of import. aenv freezes the resolved SHA either way; re-import to follow main later.
--pin is optional. Without it, aenv re-resolves to the default branch HEAD on every activation. Always pin for anything reproducible.
Global profiles (aenv global — user scope)
Swapping the user-level config that every Claude Code / Codex session reads. aenv global use is the one-command front door.
| User wants… | Run this | ||
|---|---|---|---|
| Onboard a config repo (e.g. claude-ctrl) and turn it on | `aenv global use <git-url\ | local-path> — imports it as a namespace (if not already present) **and** activates it, in one command. --as <name> to name it; --pin <ref>` for a git ref | |
| Switch to an already-installed global profile | aenv global use <name> | ||
| Swap back to the profile you were just on | aenv global use - (toggles to the previous) | ||
| Swap back to your original pre-aenv setup | aenv global use baseline (auto-captured on the first-ever global activation) | ||
| Author a global profile from scratch | aenv global new <name> (scaffolds an editable ~/.aenv/envs/<name>/user/.claude/CLAUDE.md + manifest), then aenv global use <name>. Add --shared to scaffold it as dual-scope (shared_files) from the start. | ||
| Add a skill to a global profile | aenv skill import git+<url> --ns <name> --scope user [--path <subdir>] [--pin <ref>] (or aenv skill new <skill> --ns <name> --scope user). `--scope user` is required for global profiles — without it the skill is project-scope and won't materialize on aenv global use. User-scope skills land in ~/.claude/skills/<skill>/. | ||
| Add an arbitrary file to a global profile (settings.json, RTK.md, statusline/, …) | No CLI command — edit by hand: place the content at ~/.aenv/envs/<name>/user/<rel-path> (mirroring its $HOME target, e.g. user/.claude/RTK.md), then add <rel-path> to the manifest's [adapters.<adapter>] user_files (a trailing / declares a whole directory), then aenv global use <name>. user_files is not capped by the adapter. | ||
Capture the current ~/.claude/ as a reusable namespace | aenv global snapshot <name> [--include <path>…] [--shared] (--shared declares the captured content as shared_files so it serves project scope too) | ||
| Import a source without activating it | aenv global import <source> [<name>] [--pin <ref>] [--shared] (--shared → dual-scope shared_files) | ||
| What global profile is active / what it manages | aenv global status (--json for structured) | ||
Which namespace owns ~/.claude/<file> | aenv global which <path> (--json adds content_hash) | ||
| List global (user-scope) namespaces | aenv global list | ||
| Check a namespace's policies / clean orphan stashes | aenv global doctor [<ns>] [--fix] (--fix deletes orphan stash dirs) | ||
Turn off the global profile (restore $HOME) | aenv global deactivate (add --force only if a broken on_deactivate hook blocks it) | ||
| Run the whole sequence non-interactively (CI) | append --yes to use/activate |
Deprecated: aenv global activate <ns> still works but prints a deprecation notice — prefer aenv global use <ns> (a superset that also imports sources and records a swap-back point).
Unified scope flags (equivalent to the `aenv global` tree): the project verbs accept --global to act on user scope without switching command trees — aenv create <ns> --global (= global new), aenv activate <ns> --global [--yes] [--no-baseline], aenv deactivate --global [--force]. Either spelling is fine; aenv global … is not going away. Guards: --global can't be combined with a --project <path> override, --yes/--no-baseline/--force are global-only, and --prune is project-only.
One copy serving both scopes (`shared_files`): to reuse one profile's content both globally and inside a project without storing it twice, declare those paths under shared_files in the adapter block instead of user_files — e.g. [adapters.claude-code] shared_files = [".claude/CLAUDE.md", ".claude/agents/"]. Content is stored once under ~/.aenv/envs/<ns>/user/; aenv activate <ns> --global materializes it into $HOME, and aenv use <ns> + aenv activate (project) materializes the same bytes into the repo, with role-tagged files remapped to each scope's layout (.claude/CLAUDE.md → repo-root CLAUDE.md in a project). Emit shared_files directly at creation/capture time with the opt-in --shared flag on aenv create <ns> --global --shared, aenv global new --shared, aenv global snapshot --shared, or aenv global import --shared (default is unchanged — user_files; on create, --shared requires --global). Or migrate an existing global-only profile by renaming its user_files key to shared_files (no files move). files/user_files still mean project-only / user-only. Heads-up: declaring the same project destination via both files and a shared_files remap makes aenv activate print a collision warning — keep one declaration per path.
Global gotchas — surface these proactively
- One activation per user.
aenv global use <b>while<a>is active deactivates<a>and activates<b>atomically; on failure<a>is restored. There's no "both at once." - First activation auto-captures `baseline`. Your pre-aenv
~/surface is saved as thebaselinenamespace so you always have a return point (aenv global use baseline/use -).--no-baselineopts out. An empty$HOMEcaptures nothing. - Running sessions keep their config until restart. aenv swaps files on disk; a live Claude Code / Codex process read its config at launch. Tell the user to quit and relaunch the harness for a swap to take effect — aenv prints this caveat on every activation.
- Lifecycle hooks are opt-in, never inferred. A namespace runs a setup script on activation only if it declares
[lifecycle] on_activatein its manifest or a source repo'saenv-namespace.toml. aenv does NOT auto-run a repo'sinstall.sh(those are self-installers that fight aenv). First run prompts for approval (SHA-pinned at~/.aenv/envs/<ns>/.approved);--yesskips the prompt. - Recovery / lockout. If an activated namespace's hooks lock you out of a Claude Code session (e.g. a
settings.jsonhook calls a missing runtime), open a non-Claude shell and runaenv global deactivate --force, oraenv-rescue(a standalone binary that restores$HOMEfromglobal-state.jsonvia direct fs ops, never running lifecycle scripts).
Gotchas — surface these proactively
This is the start of the file. Read the full SKILL.md on GitHub.
Security
- Security scanPassed, 90 of 100Pattern checks on the skill's files.
- Model reviewPassed
Quality evaluation
- Task evaluationNot runNo evaluation yet. Run one in Skill Studio.
Source
- SKILL.md in the repositoryCheckingskills/aenv/SKILL.md
Popularity
- Repository stars
- 2
- 7-day trend score
- 5
Stars and forks are for the whole GitHub repository, not this skill alone. Not refreshed yet.
Extension points
hookPre/post lifecycle hooks
Works with
Any agent vskill installs to: 56 targets in all. These 39 have a page on this site.
- Claude Code
- Cursor
- GitHub Copilot
- Windsurf
- Codex
- Gemini CLI
- Cline
- Amp
- Roo Code
- Goose
- Continue
- Kilo Code
- Junie
- Trae
- OpenHands
- Qwen Code
- AI Agent
- Tabnine Chat
- Sourcegraph Cody
- Amazon Q
- Firebase Genkit
- Sweep
- Devin
- Phind
- Mentat
- Claude Desktop
- Aider
- GPT Pilot
- Plandex
- bolt.new
- v0
- Replit Agent
- Anse
- TypingMind
- BetterChatGPT
- LibreChat
- Warp AI
- Pieces
- Fig AI
Embed badge
[](https://verified-skill.com/skills/blevene/aenv/aenv)