Status: Current

hac is the short installed operator command; home-ai-cluster is the canonical long root command. Both dispatch the same ordinary subcommands. This page uses hac for readability. From a repository checkout, verified standalone commands can also be run with uv run.

This is a lookup reference for current ordinary behavior, not a guide to the historical proof-only commands retained in the repository.

Invocation forms

Install the current published package for ordinary operator use:

uv tool install home-ai-cluster

Use either root form:

hac <subcommand>
home-ai-cluster <subcommand>

For repository-checkout development, prepare the locked environment with uv sync --locked, then use the ordinary root form through that environment, for example uv run hac local or uv run hac preflight.

Ordinary short options

The following additive short options are equivalent to their long forms. Long forms remain canonical, supported, and non-deprecated.

Short Long Commands
-h --help root hac, root home-ai-cluster
-f --file aider, code-file, summarize, classify
-d --declaration static-cluster, compatibility, preflight, status
-l --label classify
-j --json chat, code, external-information, summarize, classify, preflight, health, status

Every argparse-backed subcommand continues to provide -h/--help. Existing -v/--verbose remains available only where already supported: chat, code, external-information, summarize, and classify. Short and long spellings have the same semantics.

Quick command map

The ordinary root surface has sixteen commands.

Command Purpose
local Run one local ordinary application.
static-cluster Run one explicit static cluster with the local node and one or more declared remote nodes.
compatibility Run the narrow loopback OpenAI-compatible chat surface.
aider Run one bounded external Aider code edit.
external-information Acquire bounded evidence for one source-grounded Chat request.
chat Send one native chat request.
code Send one native bounded textual code request.
code-file Replace one selected file from one bounded code result.
code-workspace Run one bounded workspace-aware Code interaction.
classify Send one native bounded classification request.
image-generation Send one Image Generation request.
summarize Send one native bounded summarize request.
preflight Inspect static declaration coherence.
health Inspect local declared state and runtime health.
status Inspect one declared static cluster.
config Manage and inspect retained configuration.

hac config

Purpose: Manage the bounded HAC-managed retained configuration baseline.

With no concrete subcommand, hac config displays the config command map.

Common forms:

hac config local --runtime ollama
hac config local --runtime ollama --ollama-model <MODEL_IDENTIFIER>
hac config local --runtime ollama --ollama-disable-thinking
hac config local --runtime ollama --execution-limit 2
hac config local \
  --runtime llama-server \
  --llama-server-base-url http://127.0.0.1:<LLAMA_SERVER_PORT> \
  --llama-server-model <MODEL_IDENTIFIER>
hac config local \
  --runtime vllm \
  --vllm-base-url http://127.0.0.1:<VLLM_PORT> \
  --vllm-model <SERVED_MODEL_IDENTIFIER>
hac config local --reset

hac config image-generation --base-url http://127.0.0.1:<SD_SERVER_PORT>
hac config image-generation --reset

hac config node <NODE_ID> --base-url <BASE_URL>
hac config node <NODE_ID> --base-url <BASE_URL> --capability code
hac config node <NODE_ID> --remove

hac config external-information --plugin <NAME>
hac config external-information --reset

hac config chat --external-information-fallback
hac config chat --reset

hac config reset

hac config show

Important behavior: local is a complete retained local-runtime and caller-local-capability replacement. Non-reset local mutation requires explicit --runtime; supported runtimes and their validation remain the same as hac local. Repeat --local-capability <NAME> to retain an explicit caller-local capability set. Omission retains no explicit local capability restriction. --execution-limit <N> retains one positive integer HAC execution limit for this machine's ordinary HAC process. It limits overlapping HAC-owned execution intervals: it does not describe or guarantee runtime concurrency. Omitting the option while configuring a complete local record leaves the limit not retained, so the effective limit remains 1. There is no invocation-time execution-limit override. --reset removes only the retained local facts and is mutually exclusive with all local mutation options.

image-generation retains the one accepted local stable-diffusion.cpp companion endpoint. --base-url must be an explicit loopback http origin; it replaces only this companion and does not contact sd-server, inspect a model, or configure generation controls. --reset removes only the companion. The operator continues to own sd-server lifecycle and its model. When no explicit --runtime-config <PATH> is selected, ordinary hac local composes this companion with the effective textual runtime. An explicit runtime-config is complete and ignores both retained execution-composition domains.

node adds a retained remote declaration or completely replaces the existing declaration with the same node ID. New nodes append; replacement preserves that node's existing order. --base-url is required for mutation. Omitted --capability retains the existing chat, summarize compatibility default; repeated --capability <NAME> retains an explicit ordered set. --remove removes exactly one retained node, preserving all other node order, and is mutually exclusive with node mutation options.

external-information --plugin <NAME> retains one exact acquisition-plugin name for later explicit external-information operations; setting it again replaces that one choice. external-information --reset removes only that choice, leaving retained local and remote facts unchanged. Configuration validates the name syntax only: it does not inspect installation, credentials, provider configuration, or health, and it does not import a plugin or contact a provider.

chat --external-information-fallback retains the RFC-0096 Chat-specific authorization; chat --reset removes it. This configuration alone does not perform external-information acquisition. The retained RFC-0095 plugin name is a separate selection fact, and plugin selection alone grants no Chat disclosure authority. These Chat configuration forms do not inspect plugins, credentials, providers, runtime health, or network state.

reset clears all retained HAC configuration. It is an explicit whole-state, destructive recovery action for retained state HAC cannot load. For valid state, use the targeted local, node, external-information, or Chat reset/remove forms when unrelated retained facts should be preserved. reset does not make the private retained file a manually editable configuration API.

show reports HAC-managed retained facts only. It performs no runtime or node probing, health observation, plugin discovery/import, DNS, HTTP, or mutation. Its external-information section reports the retained name only, not credential, installation, compatibility, provider, or health status. The retained-state physical path and file representation are internal implementation details, not a manual-edit API or output schema. It displays a retained local HAC execution limit when one exists, otherwise HAC execution limit: not retained; this is not current work, runtime load, active interval count, or remaining allowance.

Retained configuration is the optional normal startup baseline. hac local uses retained local runtime composition when present; explicitly supplied compatible runtime options are one-invocation overrides, while parser defaults are not overrides. An explicitly different --runtime replaces that runtime domain, and --runtime-config remains a self-contained alternative. Startup never mutates retained state; show continues to report retained facts rather than current runtime or cluster truth. It does not show live health or prove a currently running cluster, and it does not mean every other command consumes retained values.

hac local

Purpose: Start the ordinary local application in the foreground.

Common forms:

hac local
hac local --host 127.0.0.1 --port 25042
hac local --receiver-host <LAN_IP>
hac local --receiver-host <LAN_IP> --receiver-port <PORT>
hac local --lan-browser-host <LAN_IP> [--lan-browser-port <PORT>]
hac local --runtime ollama --ollama-model <MODEL_IDENTIFIER>
hac local --runtime ollama --ollama-disable-thinking
hac local --runtime ollama --temperature 0
hac local --runtime-config <PATH>
hac local \
  --runtime llama-server \
  --llama-server-base-url http://127.0.0.1:<LLAMA_SERVER_PORT> \
  --llama-server-model <MODEL_IDENTIFIER>
hac local \
  --runtime vllm \
  --vllm-base-url http://127.0.0.1:<VLLM_PORT> \
  --vllm-model <SERVED_MODEL_IDENTIFIER>

Important behavior: The default runtime is Ollama. The closed runtime choices are ollama, llama-server, and vllm. --ollama-model is optional only with Ollama and omission keeps llama3.2; llama-server requires both of its explicit arguments; and vLLM requires its explicit loopback base URL and served-model identity. vLLM is a concrete runtime selection, not a generic OpenAI-compatible runtime abstraction. The application runs in the foreground. Home AI Cluster does not install, start, stop, download models for, or supervise the external runtime. Ordinary textual runtime compositions advertise and execute chat, summarize, classify, and code; image-generation requires its separately explicit Image Generation binding or companion.

--temperature VALUE is an optional finite non-negative local free-text sampling-temperature value for Ollama, llama-server, and vLLM. Explicit 0 is retained and forwarded; omission sends no temperature override and preserves the runtime's native default request behavior. It applies to Chat, Summarize, and Code (including workspace Code), not Classify. HAC neither recommends nor supplies a default temperature, and equal values do not promise equivalent behavior across runtimes.

Native/local authority is always exactly 127.0.0.1; --host accepts no other value. --receiver-host <LAN_IP> additively enables one receiver listener in the same foreground process. It requires one concrete non-loopback, non-wildcard IP address; HAC does not resolve names, choose an address, or bind 0.0.0.0. Its receiver port defaults independently to 25042; --port and --receiver-port control only their respective authorities. The receiver serves only RFC-0109's internal request and status routes. It is unauthenticated plain HTTP for a trusted LAN: route isolation is neither authentication nor confidential transport. --ollama-disable-thinking is Ollama-only and configures the process-local Ollama adapter: it requests native think: false for every adapter inference. Omission preserves the existing request shape (no think field). It is not a per-request or per-capability setting.

--runtime-config <PATH> selects one explicit TOML runtime-composition file. It accepts either the existing closed single-runtime schema or a closed multi-binding schema. A multi-binding file contains only one or more [[bindings]] entries; each entry explicitly assigns a non-empty, disjoint capability set to one adapter construction. The binding-only stable-diffusion-cpp runtime requires exactly explicit image-generation ownership and loopback HTTP base_url; it accepts no model or generation controls. Ollama accepts optional model and disable_thinking; llama-server and vLLM require base_url and model. Temperature remains limited to textual-runtime bindings. There is no implicit config-file discovery. Each covered single-runtime file may optionally use a top-level temperature fact; covered textual multi-binding entries may do the same. Runtime-config files are self-contained and never inherit retained temperature. File mode is mutually exclusive with equivalent runtime-composition options explicitly supplied by the operator; parser defaults do not conflict. The file and CLI options are not merged. It remains a self-contained alternate runtime-composition source; it does not carry an HAC execution limit.

An Ollama runtime-composition file can be:

runtime = "ollama"

[ollama]
model = "qwen3:8b"
disable_thinking = true

For Ollama, [ollama], model, and disable_thinking are all optional; omission preserves the existing defaults.

A llama-server runtime-composition file is:

runtime = "llama-server"

[llama_server]
base_url = "http://127.0.0.1:8080"
model = "model-name"

Both llama-server values are required. Runtime-composition files configure only the caller-local runtime and remain separate from static topology declarations.

A multi-binding file is request-capable only and keeps one local HAC node:

[[bindings]]
capabilities = ["chat", "summarize"]
runtime = "ollama"
model = "llama3.2"

[[bindings]]
capabilities = ["classify", "code"]
runtime = "vllm"
base_url = "http://127.0.0.1:8000"
model = "served-model"

The native authority is fixed to exact 127.0.0.1; open http://127.0.0.1:25042/ for the fixed same-origin browser page. Its visible navigation is Chat, Code, Image, Summarize, Classify, and Configuration; Image is the presentation label for the image-generation capability. Loopback Chat includes page-local automatic External Information authorization and a separate explicit External Information operation. The page keeps Chat only in memory, shows per-assistant node attribution, and shows accessible active feedback while a request is running. The browser permits at most one active capability request at a time; the selected node or runtime may still queue its execution. One explicitly selected Summarize or Classify file is read locally with strict UTF-8 decoding and populates that view's editable text area; the current textarea value is submitted through the existing JSON text request. Classify preserves ordered labels and sends no multipart data or filename. Non-127.0.0.1 generic --host values are rejected. The loopback page remains bound to native loopback authority. LAN receiver activation uses --receiver-host and adds no browser routes to receiver authority; the receiver listener is distinct from the trusted-LAN browser listener. The loopback page is not a dashboard, operator console, or compatibility interface.

--lan-browser-host <LAN_IP> additively serves the bounded RFC-0130 browser from one concrete non-loopback IP (default port 25042; --lan-browser-port overrides it) for both hac local and hac static-cluster. It exposes only Chat, text-only Code, Image, Summarize, and Classify; Configuration and Workspace remain loopback-only. It is plain HTTP: reachable peers and the network path must be trusted. Host and Origin checks protect browser authority, not client identity; this first boundary has no TLS or authentication.

See also: Canonical operator workflow.

hac static-cluster

Purpose: Start an ordinary explicit static cluster with the fixed local node and one or more declared remote nodes.

Common forms:

hac static-cluster
hac static-cluster --declaration <PATH>
hac static-cluster --declaration <PATH> --runtime ollama --ollama-model <MODEL_IDENTIFIER>
hac static-cluster --declaration <PATH> --runtime ollama --ollama-disable-thinking
hac static-cluster --declaration <PATH> --runtime-config <PATH>
hac static-cluster \
  --remote-node-id <NODE_ID> \
  --remote-base-url <BASE_URL> \
  --local-capability chat \
  --remote-capability chat \
  --remote-capability summarize

Important behavior:

Topology

  • With no explicit topology source, hac static-cluster uses retained ordered remote nodes when present; it still fails when no retained topology exists.
  • Declaration and inline topology modes are mutually exclusive and each replaces retained topology for that invocation.
  • Declaration mode supports one or more ordered remote nodes.
  • The inline mode supports exactly one remote node.
  • Topology is static and explicit. The process does not discover, start, stop, supervise, or repair remote machines or runtimes.

Local runtime composition

  • The same verified local runtime-composition options as hac local are accepted.
  • --ollama-model configures only the local Ollama runtime composition; omission keeps llama3.2. Remote declarations carry no model.
  • --ollama-disable-thinking configures only the process-local Ollama adapter and requests native think: false for every local adapter inference. It is neither per-request nor per-capability. Omission preserves the existing native request shape, and remote declarations carry no such setting.
  • --runtime-config <PATH> uses the same explicit closed runtime-composition contract as hac local; multi-binding files are accepted and topology declarations remain separate. The binding union is local execution ownership; caller-local capabilities remain independent routing permission, so local eligibility requires both. An Image Generation binding does not add image-generation to caller-local or remote static capability permission.

Capabilities

  • The accepted explicit capability names are chat, summarize, classify, code, and image-generation. image-generation is explicit and nondefault. Caller-local capability membership is routing permission, not physical local ownership; remote capability membership is caller-owned declared eligibility.
  • For remote declarations, use capabilities = ["..."] in ordered TOML entries, remote_capabilities = ["..."] in the legacy flat TOML form, or repeat --remote-capability <NAME> for the one-remote inline form.
  • Remote capability omission retains only chat plus summarize, so classify, code, and image-generation eligibility are always explicit.
  • Caller-local routing capabilities use local_capabilities = ["..."] at the TOML root or repeated --local-capability <NAME> in the complete inline form. Omission retains only local chat plus summarize; it does not make image-generation default.
  • Explicit local and remote capability sets must be non-empty and use only the accepted names; duplicates and unknown names are rejected.
  • Capability membership controls eligibility only. Capability order is not priority.

When retained caller-local capabilities are present, they apply only to static-cluster routing eligibility. Omission retains the existing chat plus summarize compatibility default; no capability is inferred from the runtime.

Routing and boundaries

  • Routing remains local-first and capability-centered.
  • Caller-local capability declarations control only which capabilities the caller-side static-cluster router may consider locally. They do not disable adapters, change runtime health, remove endpoints, configure hac local, change receiver behavior, verify remote runtime capability, select a target node, or create scheduling or preference.
  • Remote declaration order remains the only remote priority rule.
  • Declarations do not probe remotes or schedule requests.
  • config node and remote declarations contain no HAC execution-limit information. A remote caller does not learn a receiver's limit, active interval count, or remaining allowance. When a receiver refuses before its adapter is invoked, the existing exact execution-permission-denied response remains the safe refusal that can permit ordinary next-candidate handling.

See also: Canonical operator workflow for declaration examples.

hac compatibility

Purpose: Start the separate narrow OpenAI-compatible chat process.

Common forms:

hac compatibility
hac compatibility --declaration <PATH>

Important behavior: It is loopback-only by default and runs in the foreground. It provides narrow, non-streaming chat-completions compatibility, not the internal cluster protocol or general OpenAI API compatibility. Summarize, classify, and code are not supported through this Chat-only surface.

See also: README compatibility guidance.

hac chat

Purpose: Send one native chat request to an already-running ordinary process, or start one bounded foreground conversation from an ordinary terminal.

Common forms:

hac chat "Hello"
hac chat --message "Hello"
hac chat --timeout-seconds 300 "Hello"
hac chat "Hello" --verbose
hac chat "Hello" --json
hac chat

Important behavior: The command sends one request to the fixed local caller endpoint; it does not start the application. It remains topology-blind and returns cluster-owned execution attribution. The explicit-message forms remain one-shot. Ordinary Chat remains the default. An operator may separately enable hac config chat --external-information-fallback; with that authorization, a retained external-information plugin, and a question of at most 4,096 UTF-8 bytes, Chat makes one caller-local decision. Only external invokes the exact retained plugin, with the exact QUESTION as QUERY; acquisition remains caller-owned. Decision failure stays ordinary Chat, while failure after acquisition starts is visible and does not fall back. Authorized --verbose and --json identify the ordinary or source-grounded branch and preserve source provenance. Interactive Chat is excluded.

With no message, hac chat is interactive only when both stdin and stdout are TTYs; otherwise it fails locally without reading stdin or sending a request. hac chat --external-information is an explicit, session-local authorization for that TTY-only interactive mode. It snapshots the retained exact external-information plugin selection once at session entry. For an eligible turn, HAC decides using only the newest exact user text and, only on the external branch, passes that same text as the acquisition query. Prior conversation is not passed through HAC's acquisition contract. This is independent of the retained one-shot fallback authorization. It authorizes only that foreground interactive CLI session: it neither enables nor persists the native loopback browser's separate, page-local, default-OFF authorization checkbox. Interactive mode is ordinary content-only presentation: --json, --verbose, and -v are invalid without a message. Successful exchanges are retained only in the foreground process, in chronological user/assistant order, and each turn performs exactly one final ordinary or source-grounded Chat request under the accepted bounded flow. Nothing is persisted; EOF/Ctrl-D and Ctrl-C end the session.

Interactive candidate message content is limited to 65,536 UTF-8 bytes across all retained messages and the new turn. An over-limit or failed turn is not retained, sends no retry, and leaves earlier successful context intact. --timeout-seconds SECONDS accepts one base-10 integer from 1 through 3600; omission keeps the 120-second default. In interactive mode it applies separately to each request, never while waiting for terminal input. The value is the HTTP client's pool/connect/write/read scalar timeout, not a total deadline.

See also: Canonical operator workflow.

hac external-information

Purpose: Explicitly acquire one bounded source-evidence set through one selected separately installed plugin, then send it through the existing source-grounded Chat boundary.

Common forms: An explicit one-invocation selection is:

hac external-information \
  --plugin <NAME> \
  --query "<EXPLICIT_OPERATOR_QUERY>" \
  --question "<OPERATOR_QUESTION>"

Its additive short form is:

hac external-information \
  --plugin <NAME> \
  "<EXPLICIT_OPERATOR_QUERY>" \
  "<OPERATOR_QUESTION>"

The short form's first positional value is the acquisition QUERY and its second is the source-grounded QUESTION. Quote multi-word values. Both forms are equal and supported, but they must not be mixed. QUERY goes only to the selected plugin, while QUESTION does not go to the plugin.

An operator may retain one baseline selection for explicit external-information operations:

hac config external-information --plugin searxng

hac external-information \
  "<EXPLICIT_OPERATOR_QUERY>" \
  "<OPERATOR_QUESTION>"

The named --query / --question form may likewise omit --plugin when that retained choice exists. An explicit --plugin <NAME> wins for one invocation and does not change the retained selection. With neither an explicit nor a retained choice, input is invalid; installation alone never selects a plugin. An explicit hac external-information invocation authorizes its own QUERY and QUESTION pair. Separately authorized eligible one-shot Chat may also use the same bounded caller-owned acquisition boundary, where its exact QUESTION is also the QUERY; ordinary Chat remains unchanged without that authorization.

Available plugin examples:

The separately packaged home-ai-cluster-plugin-searxng provides the entry-point name searxng. It expects an operator-managed SearXNG service already running at 127.0.0.1:8888 with JSON output enabled. The plugin does not install, configure, start, stop, or manage SearXNG.

For an isolated uv tool, install HAC and the published plugin into the same tool environment:

uv tool install \
  --with home-ai-cluster-plugin-searxng \
  home-ai-cluster

Then, with hac local or hac static-cluster already running, for example:

hac external-information \
  --plugin searxng \
  "local AI inference developments" \
  "What are the main recent developments?"

A second example can separate the acquisition query from the question answered from the resulting evidence:

hac external-information \
  --plugin searxng \
  --query "Python 3.14 release notes free threading" \
  --question "What changed for free-threaded Python in 3.14?"

For repository-checkout installation and SearXNG-specific setup, see the plugin README.

The separately packaged home-ai-cluster-plugin-tavily provides the entry-point name tavily. It uses a fixed external Tavily provider service and requires TAVILY_API_KEY in the environment of the hac external-information caller. The explicit acquisition QUERY is disclosed to Tavily; the QUESTION remains within the existing RFC-0078/HAC boundary and is not passed to the plugin. Installation alone makes no provider request.

For an isolated uv tool, install HAC and the published plugin into the same tool environment:

uv tool install \
  --with home-ai-cluster-plugin-tavily \
  home-ai-cluster

Then, with hac local or hac static-cluster already running, for example:

hac external-information \
  --plugin tavily \
  --query "Python 3.14 release notes free threading" \
  --question "What changed for free-threaded Python in 3.14?"

For Tavily-specific setup, see the plugin README.

--timeout-seconds SECONDS, --verbose, and --json use the same caller presentation and HTTP conventions as hac chat. The timeout accepts one base-10 integer from 1 through 3600, with a 120-second default. Default output is generated content only; --verbose adds ordinary execution attribution. Use --json / -j when the structured result, including supplied source provenance, is needed in CLI output.

Important behavior:

  • No provider is bundled. The operator may explicitly select one compatible separately installed plugin by its exact entry-point name or retain one exact baseline selection for later explicit external-information operations.
  • Only this finite caller edge discovers and loads that plugin; the ordinary HAC server does not discover, import, configure, or invoke acquisition plugins.
  • "Separately installed" means a compatible Python distribution in the same Python environment that provides hac. HAC discovers it only through importlib.metadata.entry_points() in home_ai_cluster.external_information_acquisition.v1, not from a HAC plugins/ directory or filesystem scan.
  • For an isolated uv tool, additional plugin requirements belong in that same tool environment; for a project checkout, install them into that project's .venv. Provider-specific installation instructions belong to the provider plugin documentation.
  • Installation alone neither loads a plugin nor grants network access: ordinary HAC startup, ordinary Chat, and the ordinary server remain unchanged.
  • The plugin receives only --query, may make its own one bounded provider operation under its own configuration, credentials, and network limits, and returns bounded title/URL/content candidates.
  • HAC reconstructs and validates RFC-0077 source evidence before sending exactly one validated body to existing /v1/chat/sources; ordinary capability=chat routing then applies unchanged.
  • --timeout-seconds governs only that native HAC HTTP request. It does not impose a timeout on plugin acquisition.
  • The command has no provider selection, fallback, retry, plugin enumeration, generic plugin configuration, new capability, URL fetching, or ordinary-server network authority.

hac code

Purpose: Send one native bounded textual code request to an already-running ordinary process, or start one bounded foreground Code conversation from an ordinary terminal.

Common forms:

hac code --message "<OPERATOR_SUPPLIED_CODE_REQUEST>"
hac code "<OPERATOR_SUPPLIED_CODE_REQUEST>"
hac code --timeout-seconds 300 --message "<OPERATOR_SUPPLIED_CODE_REQUEST>"
hac code --message "<OPERATOR_SUPPLIED_CODE_REQUEST>" --verbose
hac code --message "<OPERATOR_SUPPLIED_CODE_REQUEST>" --json
hac code

Important behavior: Explicit-message forms remain one-shot: they require exactly one non-blank positional message or --message, send one request, and terminate. On a TTY, no-message hac code starts an ordinary content-only interactive session; non-TTY no-message use fails locally without reading stdin or sending a request. Successful context exists only in the foreground process: each follow-up sends all earlier successful user/result messages plus the new turn, so a refinement can refer to prior generated text. The RFC-0067 65,536 UTF-8-byte aggregate bound applies to that complete candidate; rejected or failed turns are not retained. --timeout-seconds applies independently to each submitted request. No-message --json, --verbose, and -v are invalid; the corresponding explicit-message behavior remains unchanged. The client is topology-blind and sends capability=code through the existing native POST /v1/chat endpoint. A topology with no eligible code capability produces a safe no-capability failure.

Generated code is response text only. This command grants no filesystem, repository, shell, Git, testing, tool, function, agent, or execution authority. It does not add /v1/code or a standalone home-ai-cluster-code command; code-file and aider remain separate, unchanged commands.

See also: Canonical operator workflow.

hac code-file

Purpose: Replace one explicitly selected text file from one native bounded code result, creating one explicitly named missing leaf only when its parent already exists.

Common forms:

hac code-file --file <PATH> --message "<OPERATOR_SUPPLIED_CODE_REQUEST>"
hac code-file --file <PATH> "<OPERATOR_SUPPLIED_CODE_REQUEST>"
hac code-file --file <PATH> --message "<OPERATOR_SUPPLIED_CODE_REQUEST>" --timeout-seconds 300

Important behavior: The command accepts exactly one explicit target and one non-blank message, supplied either as one positional shell argument or through --message. An existing target must be a regular, non-symbolic-link UTF-8 file. One explicitly named missing leaf may be created with exclusive non-overwriting creation only after input, parent, timeout, and empty-current-content request validation; its parent must already exist as a directory. It creates no parent, and a later failure may leave the requested new target empty without rollback deletion. It sends exactly one existing native POST /v1/chat request with capability=code; the two request messages contain a fixed response instruction plus the operator instruction and exact current file text (empty for a new target), never the target path or filename. The existing 65,536-byte aggregate code-input bound and a separate 65,536-byte UTF-8 generated-content bound apply without truncation.

Only a closed JSON envelope containing version 1 and complete replacement content is accepted. After all validation, the caller writes one private same-directory temporary file, preserves only the target's ordinary 0o777 permission bits, and atomically replaces the selected target once. It does not execute generated content, does not retry, and adds no endpoint, capability, standalone executable, or Aider behavior.

hac code-workspace

Purpose: Run bounded workspace-aware Code interactions with one explicit, caller-local workspace root and explicit filesystem-operation grants.

Common forms:

hac code-workspace --root <PATH> --grant list --grant read "<INSTRUCTION>"
hac code-workspace --root <PATH> --grant read --grant write --message "<INSTRUCTION>"
hac code-workspace --root <PATH> --grant create --grant write --message "<INSTRUCTION>"
hac code-workspace --root <PATH> --grant list --grant read

Important behavior: Exactly one explicit --root, one or more --grant values (list, read, write, or create) are required. An explicit non-blank positional or --message instruction runs exactly one interaction; both forms together or repeated --message are invalid. With neither message form, the command enters a foreground interaction only when both stdin and stdout are TTYs. It retains no history or authority after exit, accepts no piped-input protocol, and leaves blank terminal input unsubmitted.

One interactive foreground invocation constructs one fixed caller-local authority from its root and grants. Each submitted human turn starts a fresh bounded interaction (at most eight workspace actions and nine Code inferences) and uses the ordinary per-inference --timeout-seconds value. Only successful human instructions and exact non-empty final answers are retained in process memory for later turns; workspace action/outcome context is turn-local. Duplicate valid grants collapse idempotently; there is no implicit root or grant, retained workspace setting, or dynamic authority.

write replaces one existing regular UTF-8 file and still refuses a missing target. create creates exactly one empty missing regular leaf in an existing directory; it creates no parent directory and never overwrites an existing object. Creating and then populating a new file normally requires both explicit create and write grants. No grant is implicit or default.

The root and grants construct caller-local authority for this invocation only. Workspace action activity is written to stderr; a final model response alone is written to stdout. A refused action is intermediate and can still be followed by a successful final response. Ordinary Code routing still applies, so bounded workspace text (such as names and file contents) may be sent to configured remote Code nodes; the physical root and grants remain local. --root and the initial instruction are ordinary local command-line arguments and may be visible to host process inspection, shell behavior, or shell history. The command grants no shell, process, Git, general-agent, or retained authority.

hac image-generation

Purpose: Send one Image Generation request to an already-running ordinary HAC process.

Common forms:

hac image-generation "<INSTRUCTION>"
hac image-generation --output <FILE> "<INSTRUCTION>"
hac image-generation -o <FILE> "<INSTRUCTION>"
hac image-generation --output <FILE> --jpeg "<INSTRUCTION>"
hac image-generation --width <PIXELS> --height <PIXELS> "<INSTRUCTION>"
hac image-generation --timeout-seconds <SECONDS> --output <FILE> "<INSTRUCTION>"

Important behavior: hac image-generation [--output FILE] [--jpeg] "<INSTRUCTION>" [--width PIXELS --height PIXELS] [--timeout-seconds N] sends one closed request. Width and height are optional but must be supplied together as whole pixels from 64 through 2048; when supplied, the successful PNG has exactly those dimensions. Without --output, successful output is raw PNG bytes on stdout; direct TTY stdout is refused before a request is made, so use an appropriate non-TTY byte sink.

-o FILE is the exact alias of canonical --output FILE. With either spelling, stdout is not the result sink and may be a TTY. Without --jpeg, the file receives exactly the validated PNG bytes regardless of its suffix. --jpeg requires --output FILE; it creates one caller-local JPEG derivative only after HAC has fully received and validated the normalized PNG. JPEG export accepts only 8-bit RGB source PNGs, preserves dimensions, and uses fixed quality 95, 4:4:4 chroma subsampling, and non-progressive encoding. HAC creates only the explicitly selected missing leaf: its parent must already exist as a directory, HAC creates no parent directory, and it never overwrites an existing filesystem object. The file receives the selected validated PNG or JPEG derivative bytes; successful stdout and stderr are empty. The output path remains caller-local and is not sent in the request or to routing, remote nodes, or the runtime. A write or close failure after creation may leave an incomplete file; HAC performs no rollback deletion, regeneration, or routing fallback. There is no generic output-format option, JSON, verbose, node, remote toggle, model, runtime, or generation-control option.

In an ordinary non-static process, Image Generation remains local. With ordinary static-cluster wiring, it uses the same existing local-first routing as other supported remote-capable operations: an eligible local Image Generation binding is preferred, then explicitly eligible declared remotes may be used under the existing fallback and declaration-order rules. This adds no node selector, discovery, probing, or scheduling.

hac aider

Purpose: Coordinate one bounded external Aider edit of one explicitly selected file through the existing native code capability.

Common forms:

hac aider --file <PATH> --message "<REQUEST>"
hac aider --file <PATH> "<REQUEST>"
hac aider --file <PATH> --message "<REQUEST>" --timeout-seconds 300

Important behavior: This optional caller edge requires external Aider exactly 0.86.2 and an already-running hac local or hac static-cluster process. It accepts exactly one target and one non-blank message, supplied either as one positional shell argument or through --message. An existing target is read and edited by Aider; a missing target may be created only as the one named empty file after input, parent, and Aider prerequisite checks pass. Its parent must already exist as a directory, creation never overwrites an existing target, and a later failure does not delete a newly created target. Missing or wrong-version Aider creates no target.

Each invocation launches one Aider subprocess and one private, ephemeral IPv4-loopback translator. One Aider-shaped request is required; at most one additional Aider-owned follow-up is permitted, for a maximum of two native capability=code requests. The first native interaction must succeed before a follow-up is allowed; this is not HAC retry behavior, and a third request fails closed. Exactly the selected target is editable: model-proposed additional existing or missing paths are automatically rejected and do not require interactive path approval. There is no Aider chat session, Git, test, lint, or shell automation. The translator is not RFC-0031 compatibility, which remains Chat-only. HAC core remains text-only; Aider retains target-content authority. All existing privacy and execution guardrails remain unchanged. --timeout-seconds accepts one base-10 integer from 1 through 3600, with a 120-second omission default, and applies independently to each native HAC request.

hac summarize

Purpose: Send one native bounded summarize request to an already-running ordinary process.

Common forms:

hac summarize --text "Text to summarize"
hac summarize --timeout-seconds 300 --text "Text to summarize"
printf 'Text to summarize' | hac summarize
hac summarize --file README.md
hac summarize < README.md
git diff | hac summarize
hac summarize --file README.md --verbose
hac summarize --file README.md --json

Important behavior: --text and --file are mutually exclusive. With neither, stdin is used; either explicit source ignores stdin. --file accepts one regular file using ordinary operating-system path semantics: it does not expand ~, environment variables, or globs, and does not treat --file - specially. Sources must be strict UTF-8 and at most 65,536 bytes. Oversized input is rejected, never truncated. Content, --verbose, and --json are the supported output modes. --timeout-seconds SECONDS uses the same base-10 integer range (1 through 3600) and 120-second omission default as hac chat. It is the HTTP client's pool/connect/write/read scalar timeout, not a total deadline; it adds no retry or cancellation. A timeout does not prove that work has stopped elsewhere, so avoid immediately repeating a timed-out request on slow hardware unless additional work is acceptable.

See also: Canonical operator workflow.

hac classify

Purpose: Send one native bounded classification request to an already-running ordinary process.

Common forms:

hac classify --text "The invoice is due tomorrow." --label invoice --label personal
hac classify --timeout-seconds 300 --text "The invoice is due tomorrow." --label invoice --label personal
printf '%s' 'The payment failed.' | hac classify --label technical --label billing
hac classify --file <PATH> --label label-a --label label-b --verbose
hac classify --file <PATH> --label label-a --label label-b --json

Important behavior: The command accepts exactly one bounded source through --text, --file, or stdin when neither explicit source is supplied. --text and --file are mutually exclusive, and either explicit source ignores stdin. Sources are strict UTF-8 and at most 65,536 bytes; they are never truncated. Labels are supplied through repeated ordered --label options: at least two and at most 32 are required. Labels are exact values; there is no trimming, case folding, Unicode normalization, fuzzy matching, prose repair, implicit unknown, score, rationale, or multi-label result. The adapter proposes one label and the cluster accepts it only when it exactly belongs to the supplied label set. A successful minimal result contains selected_label and node_id.

Default, --verbose, and --json are the supported output modes. --timeout-seconds SECONDS has the same 1 through 3600 range, 120-second omission default, and one-shot HTTP-client ownership as chat and summarize; it adds no retry, cancellation, total deadline, server timeout, or runtime timeout. The client is topology-blind and does not start, configure, inspect, or manage the process. Safe failures do not expose source text, labels, runtime details, or raw adapter output.

See also: Canonical operator workflow.

hac preflight

Purpose: Inspect local or explicit static declaration coherence.

Common forms:

hac preflight
hac preflight --json
hac preflight --declaration <PATH>
hac preflight --declaration <PATH> --json
hac preflight \
  --remote-node-id <NODE_ID> \
  --remote-base-url <BASE_URL> \
  --local-capability chat \
  --remote-capability summarize

Important behavior: With no topology input, hac preflight performs the historical local-only static coherence inspection. It does not automatically inspect HAC-managed retained remote topology. To inspect a static multi-node topology, supply --declaration <PATH> or the complete supported inline topology form. This is static validation only: it does not observe a runtime or remote network. Default output is human-readable; --json provides compact structured output. A coherent result does not prove that a runtime or remote application is available. In an explicit static topology, each node's Capabilities are static topology declarations used for routing eligibility, not runtime capability discovery, runtime health, adapter enablement, or endpoint availability. Inline preflight projects the same caller-local routing capability set as inline hac static-cluster; declaration and inline topology modes remain mutually exclusive.

See also: Canonical operator workflow.

hac health

Purpose: Take one finite snapshot of local declared state and runtime health.

Common forms:

hac health
hac health --json

Important behavior: One completed snapshot deliberately separates static declared node metadata from direct runtime-adapter observations made for this invocation. Declared Availability and Healthy are configuration facts, not live runtime observations; adapter Status is the direct observation. An adapter unavailable may therefore coexist with declared available and healthy; this is not contradictory, and HAC does not rewrite the declaration. Declared Capabilities come from the ordinary local execution composition, not a caller-local routing restriction in an explicit static topology; they are declared composition facts, not capability probing. The command is local-only and does not observe remote nodes, monitor, poll, change routing, or predict later request success. Default output is human-readable; --json is structured output. unavailable, missing, and probe-failed observations remain completed result data rather than a whole-command failure.

See also: Canonical operator workflow.

hac status

Purpose: Inspect one declared static cluster.

Common forms:

hac status --declaration <PATH>
hac status --declaration <PATH> --json
hac status --declaration <PATH> --runtime ollama --ollama-model <MODEL_IDENTIFIER>
hac status --declaration <PATH> --runtime-config <PATH>
hac status \
  --declaration <PATH> \
  --runtime llama-server \
  --llama-server-base-url http://127.0.0.1:<LLAMA_SERVER_PORT> \
  --llama-server-model <MODEL_IDENTIFIER>

Important behavior: status requires --declaration <PATH> because that saved declaration file explicitly selects the remote topology it observes. Status also observes the fixed local node; its local runtime composition remains selected separately by the existing status runtime-selection rules. HAC-managed retained topology is not used automatically as a status target. The declaration is validated before observations. The local node is reported first and remotes follow declaration order. Observation is finite and read-only: it does not change routing, topology, lifecycle, or the declaration. Default output is human-readable; --json is compact structured output. Unreachable or unavailable nodes can appear as result data without making the command invocation invalid. With no runtime option, status uses the historical default Ollama composition. Runtime CLI options and --runtime-config <PATH> select an explicit local composition; retained local runtime configuration does not replace status runtime selection. status --runtime-config <PATH> accepts the existing single-runtime shape only; multi-binding files fail locally before status observation. health remains unchanged and accepts no runtime-config.

See also: Canonical operator workflow.

HTTPX environment boundary

HAC-owned fixed-loopback, runtime-loopback, declared-remote execution, and declared-remote status clients ignore HTTPX proxy and certificate environment variables. This does not bypass VPNs, Tailscale, DNS, operating-system routing, routers, or transparent network controls. Declared HTTPS remotes retain verifying TLS, but ambient SSL_CERT_FILE and SSL_CERT_DIR private-CA discovery is unsupported. HAC provides no proxy or explicit private-CA configuration; plugin/provider clients and Aider subprocess networking retain their separate ownership.

Output conventions

Service commands stay in the foreground. Chat, code, and summarize return content by default; classify returns its selected label. Their --verbose forms include execution attribution and their --json forms return compact structured results. Successful code-file replacement is silent. Inspection commands are human-readable by default and offer --json for automation. Individual command support is shown above.

Ordinary exit codes

This lookup covers ordinary HAC-owned command outcomes, not every external process or operating-system outcome.

Exit Ordinary meaning
0 Successful invocation or operation, including completed health and status observations that report an unavailable or failed observed state.
1 Operational failure, or a completed preflight report that found incoherence.
2 Invocation, input, or parser error.

A preflight exit 1 with a completed incoherent report is distinct from failure to construct the report. health and status may exit 0 with negative observations because the observation itself completed. After HAC completes its own pre-start validation and application construction, foreground Uvicorn/OS lifecycle failures remain owner-defined non-zero outcomes; HAC does not promise specific third-party exit codes for them.

Common failure boundaries

Commands use stable project-owned failures and avoid exposing runtime URLs, private addresses, raw exceptions, source contents, and stack traces. Where a command contract requires it, local input is validated before network activity. See the relevant command section for its specific boundary.

Repository-checkout commands

After uv sync --locked, use uv run hac <subcommand> for ordinary checkout use. The following retained standalone launchers remain available where their direct mapping is useful for compatibility or reference:

Ordinary root Retained standalone launcher
hac local uv run home-ai-cluster-local
hac static-cluster uv run home-ai-cluster-static-cluster
hac compatibility uv run home-ai-cluster-openai-compatibility
hac chat uv run home-ai-cluster-chat
hac preflight uv run home-ai-cluster-preflight
hac health uv run home-ai-cluster-health
hac status uv run home-ai-cluster-status

hac code, hac code-file, hac image-generation, hac summarize, and hac classify are available through the ordinary root command; none has a separate installed checkout script.

Specialized compatibility commands

The retained standalone launchers home-ai-cluster-explain-routing, home-ai-cluster-explain-request, home-ai-cluster-history, and home-ai-cluster-clear-history are specialized diagnostic/history compatibility surfaces. They remain installed and supported in their bounded roles, but are not ordinary commands in the sixteen-command hac root and have no ordinary hac equivalents.

Historical proof commands

RFC-0075 retired four historical proof-only installed launchers. Their names remain only in historical material and require the corresponding historical repository revision for reproduction.

See also: Documentation index, retained proof documents, and the RFC index.