Skip to content

axm-doctor

Env bootstrap + auth-status doctor (detect, propose, orchestrate)

CI axm-init axm-audit Coverage Python 3.12+


Installation

Bash
uv add axm-doctor

Quick Start

Python
from axm_doctor import detect_tool, detect_auth

# Is a tool on PATH? (stdlib + pydantic only, no AXM dependency imported)
print(detect_tool("uv"))      # ToolStatus(state='present', version='0.5.1', ...)

# Is a third-party CLI logged in? (read-only: exit code / credential-file existence)
print(detect_auth("gh"))      # AuthStatus(state='logged_in', login_cmd=None)
print(detect_auth("claude"))  # AuthStatus(state='logged_out', login_cmd='claude login')
Python
from axm_doctor import install_command, run_install

# Propose the official install command — runs nothing.
plan = install_command("uv")     # InstallPlan(human_command='curl -LsSf https://astral.sh/uv/install.sh | sh', ...)

# Dry-run by default — NEVER installs silently.
run_install(plan)                # InstallResult(executed=False, ...): echoes the command it would run
run_install(plan, confirm=True)  # opt-in install, then re-detects via detect_tool
Python
from axm_doctor import missing_secrets, provision_missing

# Which credential specs resolve to 'missing'? Reads vault's catalog + value-free provenance.
missing_secrets()                # [MissingSecret(group='research.fred', name='api_key', setup_hint='axm-vault set research.fred.api_key'), ...] — never a value

# Dry-run by default — NEVER prompts or stores.
provision_missing()              # ProvisionResult(provisioned=False, groups=['research.fred']): the groups it WOULD prompt for
provision_missing(confirm=True)  # delegates to vault's run_setup(only=...) — doctor never writes a secret itself

Features

  • Bootstrap layerdetect_tool / detect_auth depend on stdlib + pydantic only; importing them pulls no AXM package (deferred axm-config import + PEP 562 lazy re-exports), so they run before the rest of AXM is installed.
  • Config-resolvability checksdetect_git_identity (a [git].default in the axm-config store, else git config --get user.email exit code) and detect_gh_config (gh config get git_protocol exit code; not_installed when gh is absent) report whether a git committer identity and gh base config are resolvable — value-free (presence + exit code only, never the value), degrading to unconfigured on error. The env_doctor tool surfaces them under a config key.
  • Read-only auth — state comes from an exit code or a non-empty credential-file check (a 0-byte file is logged_out); on macOS, claude is probed via the login Keychain entry Claude Code-credentials (exit code only). The file is stat'd, not opened, and the Keychain value is never read, so the token value is never read.
  • Frozen models — immutable ToolStatus / AuthStatus / GitIdentityStatus / GhConfigStatus; AuthStatus carries a login_cmd to recover from logged_out, never a token.
  • Install plans, never silent installsinstall_command proposes the official command for a known tool; run_install is a dry-run by default (confirm=False) and installs only on explicit opt-in (confirm=True), then re-detects the tool.
  • Orchestrates, never possessesmissing_secrets lists the vault credential specs that resolve to missing (value-free, with a setup_hint); provision_missing is a dry-run by default and on confirm=True delegates to vault's run_setup — the secret never transits axm-doctor.