Skip to content

Cli

cli

axm-vault command-line interface (cyclopts).

The CLI is a thin shell: it owns argument parsing and human-facing output, but delegates every operation to the central functions / tools so no business logic is duplicated across the CLI / MCP boundary. setup is the only genuine process-lifecycle command (interactive prompts); set/doctor are backed by the :class:~axm.tools.base.AXMTool implementations, and get/rotate/path call the resolver, store and config primitives directly. There is deliberately no import command — a bulk importer is deferred.

doctor(package=None, instance=None)

Print value-free provenance for every credential in the catalog.

Parameters:

Name Type Description Default
package str | None

Restrict the report to one contributing package.

None
instance str | None

Optional multi-instance segment.

None
Source code in packages/axm-vault/src/axm_vault/cli.py
Python
@app.command
def doctor(package: str | None = None, instance: str | None = None) -> None:
    """Print value-free provenance for every credential in the catalog.

    Args:
        package: Restrict the report to one contributing package.
        instance: Optional multi-instance segment.
    """
    for key, entry in doctor_data(package, instance=instance).items():
        print(f"{key}\t{entry['layer']}\t{'present' if entry['present'] else '-'}")

get(group, name, *, reveal=False)

Resolve group.name and print it, masking SECRET values.

Parameters:

Name Type Description Default
group str

Credential group id.

required
name str

Credential name within the group.

required
reveal bool

Print the plaintext even for SECRET specs (a deliberate opt-in reveal; no audit trail is emitted).

False
Source code in packages/axm-vault/src/axm_vault/cli.py
Python
@app.command
def get(group: str, name: str, *, reveal: bool = False) -> None:
    """Resolve ``group.name`` and print it, masking SECRET values.

    Args:
        group: Credential group id.
        name: Credential name within the group.
        reveal: Print the plaintext even for SECRET specs (a deliberate
            opt-in reveal; no audit trail is emitted).
    """
    try:
        grp = load_catalog().group(group)
        resolved = resolver.resolve(grp, name)
    except _RESOLVE_ERRORS as exc:
        _die(exc)
        return
    secret = resolved.spec.sensitivity is Sensitivity.SECRET
    print(MASK if secret and not reveal else resolved.value)

main()

Console-script entry point for axm-vault.

Source code in packages/axm-vault/src/axm_vault/cli.py
Python
def main() -> None:
    """Console-script entry point for ``axm-vault``."""
    app()

path()

Print the resolved ~/.axm home directory used for file-backed config.

Source code in packages/axm-vault/src/axm_vault/cli.py
Python
@app.command
def path() -> None:
    """Print the resolved ``~/.axm`` home directory used for file-backed config."""
    print(axm_config.axm_home())

rotate(group, name, value, instance=None)

Rotate a SECRET to value, retaining the previous one for one cycle.

The spec is resolved through the catalog first and MUST be :data:~axm_vault.models.Sensitivity.SECRET: only SECRET specs live in the keyring, so rotating a CONFIG/NONSENSITIVE spec (or an unknown name) would write an orphan into the keyring that get never reads — a silent no-op reported as success. Routing through the catalog turns that into an up-front error, mirroring set's sensitivity check.

Parameters:

Name Type Description Default
group str

Credential group id.

required
name str

Credential name within the group.

required
value str

The new secret value (never echoed back).

required
instance str | None

Optional multi-instance segment.

None
Source code in packages/axm-vault/src/axm_vault/cli.py
Python
@app.command
def rotate(group: str, name: str, value: str, instance: str | None = None) -> None:
    """Rotate a SECRET to ``value``, retaining the previous one for one cycle.

    The spec is resolved through the catalog first and MUST be
    :data:`~axm_vault.models.Sensitivity.SECRET`: only SECRET specs live in the
    keyring, so rotating a CONFIG/NONSENSITIVE spec (or an unknown name) would
    write an orphan into the keyring that ``get`` never reads — a silent no-op
    reported as success. Routing through the catalog turns that into an
    up-front error, mirroring ``set``'s sensitivity check.

    Args:
        group: Credential group id.
        name: Credential name within the group.
        value: The new secret value (never echoed back).
        instance: Optional multi-instance segment.
    """
    try:
        spec = load_catalog().group(group).spec(name)
        if spec.sensitivity is not Sensitivity.SECRET:
            msg = (
                f"cannot rotate {group}.{name}: only SECRET credentials live "
                f"in the keyring (this spec is {spec.sensitivity.value.upper()})"
            )
            raise ValueError(msg)
        rotate_secret(group, name, value, instance)
    except Exception as exc:  # noqa: BLE001 # CLI boundary: any error -> exit 1
        _die(exc)
        return
    print(f"rotated keyring:{group}.{name}")

set(group, name, value)

Store group.name in its backend (keyring for SECRET, config else).

Parameters:

Name Type Description Default
group str

Credential group id.

required
name str

Credential name within the group.

required
value str

The value to store (never echoed back).

required
Source code in packages/axm-vault/src/axm_vault/cli.py
Python
@app.command
def set(group: str, name: str, value: str) -> None:  # CLI verb
    """Store ``group.name`` in its backend (keyring for SECRET, config else).

    Args:
        group: Credential group id.
        name: Credential name within the group.
        value: The value to store (never echoed back).
    """
    result = VaultSetTool().execute(group=group, name=name, value=value)
    if not result.success:
        print(result.error, file=sys.stderr)
        raise SystemExit(1)
    print(result.data["stored"])

setup(only=None)

Interactively prompt for and store every storable credential.

Parameters:

Name Type Description Default
only str | None

Restrict setup to a single group.name (or bare name).

None
Source code in packages/axm-vault/src/axm_vault/cli.py
Python
@app.command
def setup(only: str | None = None) -> None:
    """Interactively prompt for and store every storable credential.

    Args:
        only: Restrict setup to a single ``group.name`` (or bare ``name``).
    """
    run_setup(only)