Commands
Every command accepts --color <auto|always|never> (default auto). Run
llmenv <command> --help for the authoritative flag list. Global flags:
-h/--help, -V/--version.
init
llmenv init [PATH] [--repo URL]
Initialize llmenv configuration. Writes a template config.yaml into the config
directory (or PATH if given). With --repo URL, clones an existing config
repository instead of writing a template. No-op if a config already exists.
export
Deprecated (as of v3.10.0): superseded by llmenv launch <engine>
(#1056), a supervised,
ambient replacement landing in v4.0.0. export/the shell-hook flow keeps
working through v4.0.0 — this is advance notice, not a removal.
llmenv export [--scope ID] [--tag TAG] [--explain] [--compress]
Resolve the current environment and print shell export lines. This is what the
shell hook runs on every prompt. It also materializes the agent config directory
and emits the introspection env vars (LLMENV_ACTIVE_*, LLMENV_PROJECT_ROOT,
LLMENV_ICM_CONTEXT) and the adapter's pointer var (CLAUDE_CONFIG_DIR).
--tag TAGfilters to bundles carrying that tag.--scope IDnarrows the export to that scope's tags (plus OS/extra tags) when the scope is active in the current environment. If the requested scope isn't active, a warning is printed and all matching tags are exported instead.--explainannotates each exported variable with a# source:comment line showing whether it comes from the adapter (with the firing bundle names) or from llmenv introspection.--compressstrips trailing whitespace and collapses repeated blank lines in the materializedCLAUDE.md/AGENTS.mdto reduce token cost.
regenerate
llmenv regenerate
Regenerate the materialized config without emitting shell export lines. Use
after editing config.yaml or bundle files when the current shell already has
the right env vars.
When one engine can't be rendered
(added in v3.11.0)
Each installed engine is regenerated independently, so a config that one engine rejects doesn't stop the others — that engine simply keeps its previous config.
regenerate exits non-zero whenever any adapter failed, naming them, even
though the rest succeeded. Before v3.11.0 it exited 0 as long as one adapter
worked, so a rejected permission rule scrolled past as a warning above a ✓
line and looked like success
(#1346).
export is the exception: it runs on every prompt through the shell hook, so a
partial failure there stays exit 0 — failing would break your prompt for as
long as the config is bad, and the vars the other engines produced are still
correct. It prints one summary line naming the engines whose output is missing,
and llmenv regenerate will show the full error.
hook
llmenv hook <zsh|bash>
Print shell integration code for the given shell. Add eval "$(llmenv hook zsh)"
(or bash) to your shell profile. The emitted hook calls llmenv export on each
prompt.
status
llmenv status [bundles|tags|scopes|mcps|marketplaces|plugins]
Show the current environment status: active scopes and tags, and whether the config parses. With a subcommand, show a detailed listing for that category:
status bundles— list configured bundles, marking those that fire for the current environment.status tags— list all tags across scopes and contributors, marking active and orphaned tags.status scopes— list configured scopes (network/host/user/content/project), marking which are active and which are orphaned.contentscopes joined this listing in v3.10.0 — they were previously omitted entirely (#845).status mcps— list MCP servers selected for the current environment, with each server's resolved role and transport (stdio / http / sse).status marketplaces— list configured plugin marketplaces, marking those referenced by selected plugins.status plugins— list configured plugins, marking those selected by the active scope and showing their source collection.
statusline
llmenv statusline
Render an ANSI-styled status line. Reads the engine's session JSON from
stdin, config from config.yaml's statusline: section (see
Configuration reference), and llmenv's own
stats from the materialized llmenv-status.json, then prints one line per
configured row to stdout.
Not meant to be invoked manually — it's wired automatically as the engine's
statusline hook (Claude Code seeds it into settings.json on first
materialization; Crush has no statusline hook to wire it into yet). Never
fails on missing/malformed input: unknown widgets, a missing data file, or
unparseable stdin all degrade to an empty render for that widget rather than
an error.
Broken config renders an error row
(added in v3.8.0)
A config.yaml that can't be loaded or parsed is the one failure that does
not degrade to empty. Instead of rendering nothing, the statusline prints a
single row naming the problem and the remedy:
⚠️ llmenv: config error — run 'llmenv doctor'
The command still exits 0, so the engine keeps rendering the status line. The
row deliberately omits the underlying parse error — it's multi-line and
arbitrarily long, where a status line is one short row. Run
llmenv doctor to see the actual error and its location.
Previously a config parse error exited non-zero with empty stdout, so the statusline silently vanished from every open terminal with the real error going only to a stderr the engine discards — leaving no signal that the config was broken.
context
llmenv context [--bundle NAME] [--why] [--json]
Show the resolved environment and active scopes in detail — the fuller view
behind status, including which contributors fired.
--bundle NAMEnarrows the view to a single named bundle, showing its env vars, hooks (with event, matcher, type, and handler), MCPs, plugins, and skills.--whyshows activation tracing: which scope triggered each active tag, and which tags caused each bundle to fire.--jsonemits the full context as machine-readable JSON.
validate
llmenv validate
Check the config for structural issues. Reports duplicate bundle names. Exits non-zero if any issues are found.
edit
llmenv edit [BUNDLE-NAME]
Open config.yaml (or, if BUNDLE-NAME is given, the matching
bundles/<name>.yaml file) in $EDITOR. Falls back to $VISUAL, then vi.
completions
llmenv completions [SHELL] [--install] [--dir DIR] [--force]
Generate shell completion scripts for bash, zsh, or fish. With no flags,
prints the script to stdout — pipe it to a file your shell loads at startup:
# zsh — add to your .zshrc or drop into $fpath
llmenv completions zsh > ~/.zfunc/_llmenv
# bash — add to your .bashrc
llmenv completions bash > ~/.local/share/bash-completion/completions/llmenv
# fish
llmenv completions fish > ~/.config/fish/completions/llmenv.fish
(added in v3.8.0) --install writes the script to the shell's standard
completion directory instead, so you don't need to know the path yourself:
llmenv completions --install # detect $SHELL, install to the standard location
llmenv completions zsh --install # install for a specific shell
llmenv completions --install --dir DIR # install to a custom directory
llmenv completions --install --force # overwrite an existing completion file
Standard locations: $BASH_COMPLETION_USER_DIR/completions/ (falling back to
~/.local/share/bash-completion/completions/) for bash, $ZSH_CUSTOM/completions/
(falling back to ~/.zsh/completions/) for zsh, and ~/.config/fish/completions/
for fish. Refuses to overwrite an existing file unless --force is passed.
Restart your shell (or exec $SHELL) afterward — for zsh, add the printed
fpath+=(...) line to ~/.zshrc first, before compinit.
plugin-sync
llmenv plugin-sync
Sync plugin marketplaces into the cache — clone git sources that are missing, fast-forward those already present. Local-path marketplaces are used in place and need no sync.
sync
llmenv sync [--dry-run]
Sync the config repository with GitHub: git add, commit, and push the
config directory. Use this to propagate config changes to other hosts.
--dry-runpreviews pending changes (git status --short) without committing or pushing.
check-stale
llmenv check-stale [--auto-fix]
Warn if the running agent's config has drifted from what llmenv would
materialize now. Invoked automatically by the Claude Code SessionStart hook: it
compares the content hash in the booted CLAUDE_CONFIG_DIR against the
freshly-computed one and prints a restart hint on drift. Safe to run manually.
--auto-fixre-materializes the config automatically on drift instead of only printing a warning.
hook-run
llmenv hook-run <event>
Engine-neutral lifecycle hooks that inject ICM memory context over MCP and
drive session_log:. Invoked by the agent
runtime (not by users directly).
Lifecycle/memory events (session_start, session_end are auto-registered by
the Claude Code adapter; turn_start is not yet wired in, see
#499):
session_start— injects the session wake-up pack (icm_wake_up); also creates the correlated ICM transcript session and emits the baselinelifecycle_start+ scope-header session-log eventsturn_start— injects recalled context (icm_memory_recall): a project-scoped recall for the active tags, plus one project-unfiltered recall per active tag keyed onllmenv-tag:<tag>and one per active bundle keyed onllmenv-bundle:<bundle>, so tag and bundle memory crosses project boundariessession_end— best-effort store of the active scope context (icm_memory_store); also emits the baselinelifecycle_endsession-log event
Verbose events (auto-registered only when session_log.verbose: true):
user_prompt_submit, pre_tool_use, post_tool_use, notification, stop,
subagent_stop, pre_compact — each captures the corresponding Claude Code
hook payload (prompt text, tool name + input/response, notification message,
etc.) as a session-log event.
Each hook talks to the configured ICM MCP over HTTP. Failures degrade
gracefully: a missing or unreachable backend logs a warning and exits cleanly
(exit code 0) so lifecycle hooks never block the agent. The session-log file
sink is independent of MCP reachability — it still writes even when ICM is
down. Per-event transcript records dispatch via a short-lived detached child
(llmenv session-log-record, internal plumbing) so hook-run itself never
blocks on the network round trip.
memory
llmenv memory stats|list|diff|prune [--dry-run]
Inspect ICM memory state for the active scope.
memory stats— record counts by tag/bundle/type, last-written.memory list— list stored memories for the active scope.memory diff— show what changed since the last session.memory prune [--dry-run]— preview or apply TTL-based forgetting.
prune
llmenv prune [--all] [--older-than DUR] [--dry-run]
Clean stale cache folders. Exits non-zero if any plugin cache entry could not be removed (added in v3.11.0) — the per-entry failures are printed above the summary.
- (no flags) — remove folders from previous binary versions and orphaned
*.tmpstaging dirs. --all— remove every cache folder unconditionally (nextexportre-materializes).--older-than DUR— remove only current-version folders older thanDUR(e.g.14d,1w).--dry-run— preview deletions without removing (works with--alland--older-than).--plugin-cache— also remove the shared plugin cache directory.
read-once
llmenv read-once clear
Manage the read-once file dedup cache (#318). read-once clear clears all
cached read-once entries — use after reorganizing bundle content to force
re-ingestion on the next turn.
task
llmenv task add <title> [--parent SLUG | --no-parent] [--session <id>]
llmenv task start <id> [--force]
llmenv task done <id>
llmenv task wait <id> [reason]
llmenv task ls [--format json] (--session <id> | --all) [--current-project]
llmenv task show <id> | --current | --next
llmenv task note <id> [text]
llmenv task block <id> --on <other>
llmenv task edit <id> [--title <t>] [--parent SLUG | --no-parent]
[--block-on <id>]... [--unblock <id>]... [--add-note <text>] [--delete-note <index-or-timestamp>]
llmenv task clear <id>... | --session <id>
llmenv task session start [name] [--description <text>] [--resume <id> | --replace | --new]
llmenv task session finish [<id>]
llmenv task session show [<id>]
llmenv task session summary [<id>] [--format json]
llmenv task session ls
In-engine task tracker (#231): durable, cross-session "what am I working on"
state, backed by one JSON file per task. <id> accepts an exact slug or any
unambiguous prefix of one.
task add <title> [--parent SLUG | --no-parent] [--session <id>]— create a task (openstate). (added in v3.10.0) Omitting--parentno longer means "no parent": it defaults to the most recently created task in the same session, so a run of plaintask adds forms an ordered chain by default — the order agents add tasks in is usually the order they intend to execute them. Pass--parent SLUGto nest under a specific task instead (bypassing the chain), or--no-parentto force a deliberate top-level task (the two flags conflict with each other). The chain never crosses sessions — a new session's first task always starts with no parent, regardless of what was last added in a different session. A task must belong to a session (see below): with exactly one session open for the current project it auto-resolves; pass--session <id>when two or more are open; errors with actionable guidance when none is open.task start <id> [--force]— claim a task, moving it towip. Also the resume action for awaitingtask — it accepts any non-donestate as its starting point.parentandblocked_on(added in v3.8.0) are enforced differently: an undone parent only warns — organizational grouping, not an ordering guarantee, so starting a child while the parent is still open is often fine. An undoneblocked_onreference (task block, below) hard-blocks — refuses to start — since that's an explicit dependency the user configured on purpose; pass--forceto override. Ablocked_onreference resolves as done only once the target task and every one of its descendants are done, so blocking on a parent task alone covers its whole child set (seetask block, below).task done <id>— mark a task complete.task wait <id> [reason]— mark a taskwaitingon something outside the agent's control (a human review, a decision, external system access) instead ofwip.reasonis recorded as a note; reads from stdin if omitted. Distinct fromwipin how the lifecycle reminders (below) treat it: awiptask is surfaced on every Stop and pushed toward action, while awaitingtask is silent on Stop — it appears only in the SessionStart reminder, as a plain FYI with no "take action" framing, since the correct behavior is to wait for the reason to clear, not keep retrying (and re-injecting the FYI every turn would just nag about a state meant to be quiet).task ls [--format json] (--session <id> | --all) [--state <s>]... [--hide-done] [--current-project]— list tasks. Requires--session <id>or--all(added in v3.8.0) — no silent default to every session's tasks; pass--allto deliberately see everything. The human output groups tasks by session (current-project sessions first), indents subtasks under their parent, prefixes each row with a state glyph + label (open/wip/waiting/done), and annotates blocked tasks with theirblocked_onrefs; color follows TTY /NO_COLOR/CLICOLOR_FORCE.--format jsonis the stable machine format.--state <open|wip|waiting|done>(repeatable) keeps only those states;--hide-done(alias--active) drops completed tasks;--current-project(added in v3.8.0) further narrows to tasks whose session is tagged to the current project — any session ever tagged to it, open or closed, so a finished session's tasks still show — but doesn't substitute for--session/--all, since it narrows by project, not by session. Tasks with no session are excluded under--current-project. Filters compose with each other, and apply to the JSON output too when passed.task show <id>— full detail for one task (notes, parent, blockers).task show --current/task show --next(added in v3.8.0, mutually exclusive with each other and with<id>) resolve the task in progress for the current project instead of naming one:--currentis thewiptask (falling back to the most recently updated non-donetask) in each open session for the current project;--nextis the next actionable task after it, in the same parent-before-children ordertask lsdisplays, skippingdonetasks and any task whoseblocked_onrefs aren't alldone. A single open session prints the same bare JSON astask show <id>; two or more each get a# <name> (<id>)header, separated by a---rule. Errors if no session is open for the current project.task note <id> [text]— append a progress note; reads from stdin iftextis omitted.task block <id> --on <other>— record thatidis blocked onother: a hard ordering dependency (seetask start, above) — prefer this over relying on--parentnesting to imply an order it doesn't actually enforce. For a downstream step that must wait on a whole set of sibling tasks (e.g. several parallel analyzer tasks under one parent step), block on the parent rather than hand-wiring ablockedge to each sibling — ablocked_onreference isn't satisfied until the target task and every one of its descendants are done.task edit <id> [--title <t>] [--parent SLUG | --no-parent] [--block-on <id>]... [--unblock <id>]... [--add-note <text>] [--delete-note <index-or-timestamp>]— mutate an existing task. (added in v3.10.0) Every flag is optional and independent; aneditwith none of them is a no-op that still bumps the task'supdated_at.--parent/--no-parentre-parent or detach the task (same conflict astask add's flags) and reject a change that would make the task its own ancestor.--block-on/--unblock(repeatable) add or removeblocked_ondependencies, idempotently — adding an already-present id or removing an absent one is a no-op, not an error.--add-noteappends a note (reads from stdin if given as an empty string, e.g.--add-note '');--delete-noteremoves one by its 0-based index intask show'snotesarray, or by its exactattimestamp.task clear <id>.../task clear --session <id>— delete task(s) outright, for a batch that's being deliberately abandoned rather than just detached from a session (that's whatsession start --replacedoes, below). Exactly one of explicit ids or--sessionis required.
Task sessions (#905)
Sessions are mandatory: every task belongs to one, and a session is
tagged with the project it was started in (resolved from the git root, else
a .llmenv.yaml marker, else the cwd). The task/session store stays global
per engine — task ls --all can show everything — but task add's auto-resolve and
session start's checkpoint scope to the current project's open sessions, so
two windows in the same project can't silently collide. Any number of
sessions may be open at once. The SessionStart/Stop wip/waiting lifecycle
reminders (below) are likewise scoped to the current project's sessions, so a
task from a different project sharing this store never nags the wrong
project's hook.
-
task session start [name] [--description <text>] [--resume <id> | --replace | --new]— start a session for the current project. Pass--descriptionto attach free-text context (e.g. "dev-sprint issue 493"), shown insession lsand the checkpoint; it's separate fromnameand never feeds id generation. Name the session after the high-level work (e.g.oauth-token-refresh,v3.6.1-task-tracker-fixes), not a placeholder — an omitted or auto-numbered name (session-2,session-3) defeats the point ofsession lsas the recovery path after a compaction. If one or more sessions are already open for this project, the command errors and lists them (id, name, description, idle time), requiring one of:--resume <id>— adopt an existing open session instead of creating a new one (e.g. after a context compaction wiped the agent's memory of it); no new id is generated.--replace— abandon every open session for this project (untagging their still-incomplete tasks with an orphan note; already-donetasks keep their tag as a historical record), then start fresh.--new— create a new session anyway, leaving the existing one(s) open — true concurrency for two windows genuinely working in parallel.
Tasks created with
task addwhile a session is open are tagged with it permanently, so a task's session membership reflects when it was created. -
task session finish [<id>]— close out a session; auto-resolves when exactly one is open for the current project, otherwise pass an id. Never touches its tasks' session tag — a finished session (even with incomplete tasks) is a legitimate historical record. -
task session show [<id>]— print a session's progress; auto-resolves likefinish. -
task session summary [<id>] [--format json]— (added in v3.10.0) roll up a session's tasks, notes, and states into one artifact — e.g. for a memory write or a status report at the end of a session. Auto-resolves likefinish. The human format prints a header (name or id, description, done/total) followed by each task's state glyph and notes, in the same parent-before-children ordertask lsgroups a session's tasks in.--format jsonis the stable, memory-ingestion-friendly form: session metadata plus an array of tasks (slug/title/state/parent/blocked_on/notes). -
task session ls— list every currently open session (id, name, project, description), current-project matches first. This is the recovery path after a compaction: with one session open for the project there's exactly one match to resume.
When every task in an open session is done, the SessionStart/Stop hook
reminders (below) nudge the agent to run task session finish or add more
work to the session instead.
The CLI subcommands always work. The injected llmenv skill guidance and
the SessionStart/Stop lifecycle reminders are gated behind
features.task_tracker.enabled (default false). Each wip task in a
reminder is tagged with the session that started it; since a hook has no
reliable way to tell whether that session is this conversation's own (two
terminals in the same project is a normal pattern), the reminder never
presumes ownership — it conditions resuming/finishing a task on the agent
recognizing it as its own earlier work. Separately, once every task in an
open session is done, the reminder nudges to close out that session or add
more work to it (see above), likewise conditioned on recognizing it:
features:
task_tracker:
enabled: true
With the tracker enabled, llmenv also redirects Claude Code's built-in task
tools (TaskCreate/TaskList/TaskUpdate) into this tracker via an
auto-injected PreToolUse hook, so a skill or agent that reaches for the native
tools still lands durable tasks here rather than Claude's ephemeral per-session
state. TaskCreate records a task (auto-starting a session when none is open),
TaskList returns the tracker's view, and TaskUpdate maps its status to
start/done/delete. The native tool is suppressed and the agent is told the
llmenv task id to use for follow-up. This is Claude-Code-specific (those tools
are Claude Code's) and off when the tracker is disabled. (#985)
Set features.task_tracker.block_engine_task_tools: false (added in v3.10.0,
default true) to keep the CLAUDE.md fragment and reminders while letting
Claude's native Task tools through unblocked — for example, when a project
genuinely uses them for multi-agent teammate coordination rather than solo step
tracking. See features.task_tracker:
for the full field reference. (#980)
login
llmenv login [--global]
Capture Claude Code auth credentials and store them in the llmenv auth cache.
Runs claude auth login in a temporary directory, extracts the resulting
oauthAccount, and saves it so new materialized folders inherit it automatically.
The OAuth token is captured too, not just the account identity (added in v3.8.0) — so an inheriting folder is actually logged in rather than merely knowing which account you use. See Inherited Claude Code state.
- (no flags) — if
CLAUDE_CONFIG_DIRis set and managed by llmenv, updates both that folder's auth and the global cache. Otherwise falls back to global-only (same as--global) and prints a note directing you to runllmenv exportfirst. --global— store credentials in the user-level Claude config (~/.claude/) rather than the project cache. Use this whenCLAUDE_CONFIG_DIRis not set or not managed by llmenv.
llmenv init includes auth setup; use llmenv login to authenticate separately
or to re-authenticate.
setup
llmenv setup [PATH] [--repo URL] [--no-launch] [--rescan]
Interactive setup wizard for new llmenv users. Walks through auth setup (login
fresh via claude auth login, import from ~/.claude, or skip) and settings
import (choose which keys to seed from your global settings.json into the
materialized config). Writes a template config.yaml and an agent orientation
guide, then optionally hands off to the AI engine for further configuration.
--no-launchskips the AI engine handoff at the end.--rescanre-scans existing configs without overwriting files.
config-context
llmenv config-context
Print source config paths as agent context (used by the auto-registered
SessionStart hook). Prints the paths of config.yaml and the bundles/
directory so the agent knows where to direct config edits. Invoked automatically — not normally run by users.
config-guard
llmenv config-guard
Warn when the agent tries to write a managed cache path (used by the
auto-registered PreToolUse hook with matcher Write|Edit|MultiEdit). Checks
whether the target path is inside the llmenv cache and prints a redirection hint
pointing at the source config. Always exits 0 (fail-soft — the write is not
blocked). Invoked automatically — not normally run by users.
upgrade
llmenv upgrade [--check] [--track beta|release]
Upgrade llmenv to the latest version from GitHub releases. Downloads the platform-appropriate pre-built binary, performs a safe install cycle (backup → write temp → sync → rename → verify → remove backup), and restores the original binary on failure.
-
--checkcompares the current version against the latest release and prints the result. Exits 1 if an update is available. -
--track betauses the first non-draft GitHub release instead of the latest stable release. The track can be configured persistently viafeatures.upgrade.trackinconfig.yaml:features:upgrade:track: beta # "release" (default) or "beta"
Supported platforms: macOS (aarch64, x86_64), Linux (aarch64, x86_64).
doctor
llmenv doctor [--gc] [--all] [--verbose]
Validate adapter wiring and configuration. By default runs checks only for the active context (active bundles, active MCP servers, etc.). Checks:
-
config parsing
-
cache directory writability
-
git connectivity
-
orphans — scopes/tags/bundles/MCP/plugins that can never activate, a memory
server_hostmissing fromhost:, unknown fields in project markers, and a network scope whosematchhas nogateway_mac(added in v3.8.0) — onlygateway_macis evaluated today, sossid/cidralone can never match -
lifecycle hooks (added in v3.11.0) — lists which lifecycle events (
session_start,session_end,turn_start,stop) are wired forclaude_codein the active scope, and for any that aren't, what would enable them.session_start/session_endare always registered;turn_startneeds a memory backend;stopneeds session logging orfeatures.task_tracker. Read from the same gate the adapter writessettings.jsonfrom, so the report can't disagree with what's on disk. -
dead
native_<feature>.<engine>keys (added in v3.8.0) — warns when a key innative_permissions,native_hooks,native_plugins,native_mcp,native_model_providers, ornativenames no registered engine (a typo), or names an engine whose adapter never reads that map (e.g.native_model_providers.claude_code,native_hooks.opencode). Either way the block parses and merges but is never rendered. Checked against the merged config, so bundle-contributed keys are covered.llmenv exportandllmenv regeneratewarn about the same thing, as doesllmenv check-stale --auto-fix(since v3.10.0 — it re-materializes too, but didn't run this check before then, #1075), andllmenv validatefails on an unknown engine id. See Engines. -
Claude-only permission patterns under opencode (added in v3.8.0) — warns when a
capabilities.permissionspattern uses Claude Code's colon-prefix syntax (a trailing:*command prefix likegit commit:*, or adomain:/url:field filter) while opencode is also installed and enabled. opencode matches a pattern as a plain glob, so the rule never applies there. A deaddenyis called out specially: it fails open, so the thing it was written to block isn't blocked. Use a space-separated pattern (git commit *) for a rule both engines honour, or move the Claude-only form tonative_permissions.claude_code.llmenv exportandllmenv regeneratereport this too, as doesllmenv check-stale --auto-fixsince v3.10.0 (#1075). -
legacy shell tools without their recommended replacement (added in v3.8.0) — warns when
capabilities.permissions.allowgrantsgrep/findwithout also grantingrg/fd, the replacements this project's own bundled rules recommend — a nudge towardcapabilities.permissions.preset: safe-readonlyeven without adopting it.doctor-only: unlike the two checks above, anallowd legacy tool with no replacement is working config, not something silently dropped, soexport/regenerate(sourced on every shell prompt) don't report it. See Configuration. -
glob-shaped hook matchers — warns when a
hook.matcherlooks like a file-extension glob (e.g.*.rs,.py) instead of a tool-name pattern; Claude Code matcheshook.matcheragainst tool name only, never file path, so such a matcher silently never fires. Use ascope.contentglob to gate the hook's bundle by file type instead. -
token-efficiency settings — warns when
BASH_MAX_OUTPUT_LENGTH,MAX_MCP_OUTPUT_TOKENS,ENABLE_PROMPT_CACHING_1H, andCLAUDE_AUTOCOMPACT_PCT_OVERRIDEare not set; reports (info) whetherCLAUDE_CODE_SUBAGENT_MODELis set; and checks whether a context-mode MCP server is registered -
cached OAuth credential (added in v3.8.0) — reports whether a token is cached in the durable state dir, and warns when the cached token has expired. See Inherited Claude Code state.
-
--allruns the full orphan analysis across the entire config (all bundles and scopes, not just active ones). -
--gcruns cache garbage collection after the diagnostics. On macOS this also drops the keychain credential item belonging to each cache folder it deletes (added in v3.8.0); matched by folder path, so your default~/.claudelogin is never affected. -
--verboseprints detailed per-check reasoning alongside each pass/fail result.
Deprecated commands
The following top-level listing commands are hidden shims that print a
deprecation warning and delegate to status <subcommand>. Use the
status equivalents directly:
| Deprecated | Replacement |
|---|---|
llmenv scope-ls | llmenv status scopes |
llmenv tag-ls | llmenv status tags |
llmenv bundle-ls | llmenv status bundles |
llmenv mcp-ls | llmenv status mcps |
llmenv marketplace-ls | llmenv status marketplaces |
llmenv plugin-ls | llmenv status plugins |