Skip to content

CLI

The dotagents.cli package: the Dotagents umbrella, main(), and the names an overlay-shipped or personal command module imports from it.

dotagents.cli

dotagents CLI: init / context / env / overlays / build-pyz / about built-in subcommands, plus command modules discovered from cmds directories.

The bundled command modules live in _overlay/dotagents/cmds/ (findings, launch) and are discovered from the package; init copies nothing from that dir. A .py command module a user places in <scope>/dotagents/cmds/ (a dir they create for it) is discovered like any other.

The per-command classes live in sibling modules (cli/init.py, cli/overlays.py, ...); this package base holds the shared helpers (in cli/_common.py, re-exported here), the Dotagents(LoggingArgs, Cli) umbrella, main() (the install.py shim + python -m dotagents entrypoint) and _discover (command-source resolution).

Dispatch: main() routes through duho.app (not duho.main) so command discovery runs; app's default dispatch calls each command class's __call__. Command modules are discovered from the bundled cmds dir, from each installed overlay's <overlay-root>/cmds/, and from each scope's dotagents/cmds (one Scope.paths Contract-A walk, _cmds_dirs).

DotAgentsArgs and _write_stdout are re-exported for command modules (the bundled ones and overlay-shipped ones), which always run inside a real dotagents process and should from dotagents.cli import DotAgentsArgs.

CMDS_PATH_ENV = 'AGENTS_CMDS_PATH' module-attribute

Dotagents

Bases: LoggingArgs, Cli

Umbrella CLI for installing and building the dotagents config.

cmdspath = [] class-attribute instance-attribute

Extra directory to discover command modules from (repeatable).

kebab_name(class_name)

A command class's default subcommand name: LeakCheck -> leak-check, HTTPServer -> http-server, my_cmd -> my-cmd.

Source code in src/dotagents/cli/__init__.py
167
168
169
170
def kebab_name(class_name: str) -> str:
    """A command class's default subcommand name: ``LeakCheck`` ->
    ``leak-check``, ``HTTPServer`` -> ``http-server``, ``my_cmd`` -> ``my-cmd``."""
    return kebabcase(class_name)

main(argv=None)

Source code in src/dotagents/cli/__init__.py
395
396
397
398
399
400
401
402
403
404
405
def main(argv=None) -> int:
    # `commands=` makes `run` use `duho.app` (not `duho.main`) so the resolved
    # built-ins + discovered set are the commands; dispatch calls each command's
    # `__call__`. `exit=False` returns the status, whatever ended the run.
    return duho.run(
        Dotagents,
        argv,
        exit=False,
        commands=_discover(argv),
        name="dotagents",
    )

Extension API

DotAgentsArgs and resolve_user_store are importable from dotagents.cli; they are defined in the modules below.

dotagents.cli._common.DotAgentsArgs

Bases: LoggingArgs, Cmd

Shared -g/--global + --agents-dir fields for any command whose scope is where the store lives (_scope.resolve_scope's two axes). Subclass as class Foo(DotAgentsArgs): ... -- it already inherits LoggingArgs/Cmd, do not list them again. A subclass may redeclare a field (same type/default) to narrow its help text.

Re-exported at dotagents.cli.DotAgentsArgs; an overlay-shipped command module (which always runs inside a real dotagents process) should use that import.

agents_dir = None class-attribute instance-attribute

Store root override (default: ~/.agents for -g, else /.agents).

global_scope = False class-attribute instance-attribute

Use the user scope (~/.agents) instead of the project scope.

resolve_scope(*, project_root=None)

This command's resolved Scope, from the two fields above.

Source code in src/dotagents/cli/_common.py
78
79
80
81
82
83
84
def resolve_scope(self, *, project_root: "str | os.PathLike | None" = None):
    """This command's resolved ``Scope``, from the two fields above."""
    from dotagents._scope import resolve_scope

    return resolve_scope(
        self.global_scope, agents_dir=self.agents_dir, project_root=project_root,
    )

resolve_user_store(agents_dir=None)

The USER store root, in precedence order: an explicit agents_dir (--agents-dir) -> $AGENTS_HOME -> ~/.agents.

:func:resolve_scope defaults its -g store through this; env and context -- whose Contract-A walk takes the user store as agents_dir and the project root separately, and whose -g only skips the project tiers -- call it directly, so the store never becomes the project dir.

Never logs or prints the raw env value (Leakage rule); only the resolved path is ever reported.

Source code in src/dotagents/_scope.py
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
def resolve_user_store(agents_dir: "str | os.PathLike | None" = None) -> Path:
    """The USER store root, in precedence order: an explicit ``agents_dir``
    (``--agents-dir``) -> ``$AGENTS_HOME`` -> ``~/.agents``.

    :func:`resolve_scope` defaults its ``-g`` store through this; ``env`` and
    ``context`` -- whose Contract-A walk takes the user store as ``agents_dir``
    and the project root separately, and whose ``-g`` only *skips* the project
    tiers -- call it directly, so the store never becomes the project dir.

    Never logs or prints the raw env value (Leakage rule); only the resolved path
    is ever reported.
    """
    if agents_dir:
        return Path(agents_dir).expanduser()
    value = os.environ.get(AGENTS_DIR_ENV)
    if value:
        return Path(value).expanduser()
    return Path.home() / ".agents"