Houmao Server Pair¶
houmao-server and houmao-mgr are the supported Houmao server architecture for managing agent lifecycles, gateways, and the TUI watch plane.
houmao-server(src/houmao/server/cli.py) is the public HTTP authority — a FastAPI application created via thecreate_app()factory insrc/houmao/server/app.pyhoumao-mgr(src/houmao/srv_ctrl/cli.py) is the manager CLI for lifecycle, agent, and server control
The two components form a single supported pair. houmao-mgr sends commands to houmao-server, which owns managed agents, gateway proxying, TUI tracking, and registry integration.
For the deeper explanation of live terminal tracking and managed-agent state, see the Houmao Server Developer Guide.
Commands¶
Primary entrypoints for the pair:
houmao-server: serves Houmao-owned root routes, managed-agent routes, terminal-tracking routes, and a legacy/cao/*compatibility namespacehoumao-mgr: exposesserver,agents,brains,project,mailbox, andadmincommand groupshoumao-cli: legacy runtime-local CLI, not part of the supported pair
Representative usage:
houmao-mgr server start --api-base-url http://127.0.0.1:9889
houmao-mgr server start --foreground --api-base-url http://127.0.0.1:9889
houmao-mgr project init
houmao-mgr project credentials codex add --name default --api-key your-api-key-here
houmao-mgr project easy specialist create \
--name gpu \
--system-prompt "You are a GPU specialist." \
--tool codex \
--api-key your-api-key-here \
--env-set OPENAI_MODEL=gpt-5.4
OPENAI_BASE_URL=https://api.example.test/v1 \
houmao-mgr project easy instance launch \
--specialist gpu \
--name gpu \
--env-set FEATURE_FLAG_X=1 \
--env-set OPENAI_BASE_URL
houmao-mgr project mailbox init
houmao-mgr server status --port 9889
houmao-mgr server sessions list --port 9889
houmao-mgr agents launch --agents your-role --agent-name gpu --provider codex --headless
houmao-mgr agents launch --agents your-role --agent-name gpu --provider claude_code
houmao-mgr agents join --agent-name gpu
houmao-mgr agents join --headless --agent-name reviewer --provider codex --launch-args exec --launch-args=--json --resume-id last
houmao-mgr mailbox init --mailbox-root tmp/shared-mail
houmao-mgr agents mailbox register --agent-name gpu --mailbox-root tmp/shared-mail
houmao-mgr agents mailbox status --agent-name gpu
houmao-mgr agents prompt --agent-name gpu --prompt "Summarize the current state."
houmao-mgr agents relaunch --agent-name gpu
houmao-mgr agents gateway attach --agent-name gpu
houmao-mgr agents gateway attach
houmao-mgr brains build --tool codex --skill skills --setup dev --auth openai
houmao-mgr admin cleanup registry --grace-seconds 0
houmao-mgr mailbox cleanup --mailbox-root tmp/shared-mail --dry-run
Gemini note:
- Project-local Gemini auth bundles now support
GEMINI_API_KEY, optionalGOOGLE_GEMINI_BASE_URL, andoauth_creds.jsonthroughhoumao-mgr project credentials gemini add|set. houmao-mgr project easy specialist create --tool geminiexposes the same maintained Gemini inputs through--api-key, optional--base-url, and--gemini-oauth-creds.- Managed Gemini homes resume follow-up headless turns with the persisted Gemini
session_idin the same recorded working directory instead of relying on--resume latest.
Prompt-policy note:
- current brain construction and recipe-backed launch flows treat omitted prompt mode as the unattended default
- use
launch.prompt_mode: as_iswhen you want provider startup posture left unchanged houmao-mgr project easy specialist create --no-unattended ...persists thatas_isposture into the specialist config and generated recipe under.houmao/agents/presets/
Easy launch env note:
houmao-mgr project easy specialist create --env-set NAME=valuestores durable non-credential launch env underlaunch.env_records- persistent
launch.env_recordssurvive recipe-backed rebuild and relaunch because they are specialist-owned launch semantics houmao-mgr project easy instance launch --env-set NAME=value|NAMEapplies one-off env only to the current live session and drops it on relaunch- inherited one-off
NAMEbindings resolve from the invoking shell environment at launch time - durable specialist env remains separate from auth-bundle env, and auth-owned or Houmao-owned reserved names are rejected
Server Startup Controls¶
houmao-mgr server start is detached by default. It starts or reuses houmao-server, waits for health, emits one JSON startup result, and returns the terminal to the operator. Use --foreground when you intentionally want the old attached houmao-server serve behavior in the current process.
houmao-mgr server start and houmao-server serve still share the same server startup flag surface. That server-owned startup chain exposes:
--compat-shell-ready-timeout-secondswith default10.0--compat-shell-ready-poll-interval-secondswith default0.5--compat-provider-ready-timeout-secondswith default45.0--compat-provider-ready-poll-interval-secondswith default1.0--compat-codex-warmup-secondswith default2.0
Setting --compat-codex-warmup-seconds 0 disables the extra Codex warmup sleep. If you raise the server-side compatibility waits above the defaults, also raise --compat-create-timeout-seconds or HOUMAO_COMPAT_CREATE_TIMEOUT_SECONDS so the client budget remains larger than the server's bounded startup chain.
Example:
houmao-mgr server start \
--api-base-url http://127.0.0.1:9889 \
--compat-provider-ready-timeout-seconds 90 \
--compat-codex-warmup-seconds 0
Detached startup result fields:
success,running,mode,api_base_url, anddetailpid,server_root,started_at_utc, andcurrent_instancewhen a server instance is knownreused_existingwhen the command reports an already-healthy listener instead of spawning a duplicate processlog_paths.stdoutandlog_paths.stderr, which point at the owned files under<runtime-root>/houmao_servers/<host>-<port>/logs/
If detached startup fails before health, inspect:
<runtime-root>/houmao_servers/<host>-<port>/logs/houmao-server.stdout.log<runtime-root>/houmao_servers/<host>-<port>/logs/houmao-server.stderr.log
Retired standalone surfaces (legacy):
houmao-cao-serverpython -m houmao.cao.tools.cao_server_launcher- standalone
houmao-clioperator flows that created or controlled rawbackend="cao_rest"sessions
Pair-Native CLI Tree¶
houmao-mgr now has one native top-level tree for covered pair workflows:
serveragentsbrainsprojectmailboxadmin
Repo-local authoring under project is intentionally split into three views:
houmao-mgr project
├── init | status
├── agents # low-level `.houmao/agents/` management
├── easy # specialist / instance authoring
└── mailbox # project-scoped mailbox-root operations
Authority is split intentionally:
server ...manages the houmao-server process and server-owned sessionsagents launchbuilds and launches locally withouthoumao-serveragents joinadopts an existing tmux-backed TUI or headless logical session into the same managed-agent control plane without pretending Houmao launched the current process itselfproject ...bootstraps the repo-local.houmao/overlay, reports discovery state, and exposesagents,easy, andmailboxviews over the project-local sourcesmailbox ...manages the shared filesystem mailbox root, address lifecycle, and inactive-registration cleanup withouthoumao-serveragents mailbox ...attaches or removes one late filesystem mailbox binding on an existing local managed agentagents cleanup ...handles one manifest-scoped local cleanup target for session envelopes, session-local logs, or session-local mailbox secretsagents ...follow-up commands discover agents through the shared registry first and only hithoumao-serverwhen neededbrains buildis a local brain-construction wrapperadmin cleanup ...is local shared-registry and runtime maintenance; useadmin cleanup registryfor the registry janitor and--print-jsononly when you need the machine-readable cleanup payload
For ordinary prompt submission, houmao-mgr agents prompt --agent-name <friendly-name> --prompt "..." is the default documented path. houmao-mgr agents gateway prompt --agent-name <friendly-name> --prompt "..." remains the explicit gateway-mediated alternative when queue admission and live-gateway execution semantics matter. For headless managed agents, agents prompt, agents gateway prompt, and agents turn submit now also accept request-scoped --model plus optional --reasoning-level; those overrides merge with the launch-resolved defaults for the current turn only, interpret reasoning through the resolved tool/model preset ladder, and TUI-backed targets reject them explicitly instead of silently ignoring them. Retry with --agent-id <authoritative-id> when the friendly name is not unique.
For local serverless mailbox usage, the preferred houmao-mgr workflow is:
houmao-mgr mailbox init --mailbox-root <path>houmao-mgr agents launch ...orhoumao-mgr agents join ...houmao-mgr agents mailbox register --agent-name <friendly-name> --mailbox-root <path>houmao-mgr agents mail ...
This keeps agents launch and agents join mailbox-agnostic. For supported tmux-backed managed sessions, including sessions adopted through agents join, agents mailbox register and agents mailbox unregister refresh the live mailbox projection without requiring relaunch solely for mailbox binding refresh. That includes joined sessions whose relaunch posture is unavailable, as long as Houmao can still update the durable session state and the owning tmux live mailbox projection safely. When direct mailbox work needs the current binding set explicitly, resolve it through pixi run houmao-mgr agents mail resolve-live. Inside the owning tmux session, selectors may be omitted; outside tmux, or when targeting a different agent, use an explicit --agent-id or --agent-name. The resolver also surfaces optional live gateway.base_url data for attached /v1/mail/* work instead of requiring ad hoc port rediscovery.
Adopting Existing Sessions With agents join¶
houmao-mgr agents join is the operator path for taking a user-started tmux session and making Houmao treat it like a normal managed agent from that point onward.
Use it when:
- the provider TUI is already running and you do not want Houmao to restart it
- you already have a native headless tmux session and want later
turn submit,state, orinterruptcommands to target it through the normal managed-agent flow
V1 assumptions are intentionally narrow:
- run the command from inside the target tmux session
- tmux window
0, pane0is the adopted agent surface - TUI join auto-detects one supported provider from that pane:
claude_code,codex, orgemini_cli - headless join requires explicit
--providerplus recorded--launch-args
Examples:
# Adopt a live TUI already running in window 0, pane 0.
houmao-mgr agents join --agent-name gpu
# Record relaunch options for a joined TUI.
houmao-mgr agents join \
--agent-name gpu \
--provider codex \
--launch-args=--model \
--launch-args gpt-5 \
--launch-env CODEX_HOME \
--launch-env OPENAI_API_KEY
# Adopt a native headless logical session between turns.
houmao-mgr agents join --headless \
--agent-name reviewer \
--provider codex \
--launch-args exec \
--launch-args=--json \
--launch-env CODEX_HOME \
--resume-id last
Operational behavior after a successful join:
- Houmao creates the normal runtime envelope: session root,
manifest.json, placeholder artifacts,gateway/, and per-agent memory metadata - the tmux session publishes the same discovery pointers as a native launch:
HOUMAO_MANIFEST_PATH,HOUMAO_AGENT_ID,HOUMAO_AGENT_DEF_DIR,HOUMAO_AGENT_MEMORY_DIR,HOUMAO_AGENT_MEMO_FILE, andHOUMAO_AGENT_PAGES_DIR - the joined session is published into the shared registry immediately and becomes eligible for normal
agents state,agents prompt,agents interrupt,agents gateway attach, and headless turn flows as appropriate
Relaunch posture is explicit:
- joined TUI sessions without recorded
--launch-argsand--launch-envremain controllable while live, butagents relaunchfails explicitly because Houmao does not know how to restart that provider honestly --launch-envfollows Docker--envstyle:NAME=valuestores a literal secret-free binding, whileNAMEmeans relaunch resolves that variable from the tmux session environment later- headless
--resume-idis optional: omitted means fresh chat,lastmeans resume the latest known chat, and any other non-empty value means one exact provider session id
Pair-Managed Gateway Attach¶
For pair-managed terminal sessions, the supported public attach command is houmao-mgr agents gateway attach.
Supported modes:
- explicit target mode:
houmao-mgr agents gateway attach --agent-name <friendly-name> --pair-port <pair-port> - exact-target mode:
houmao-mgr agents gateway attach --agent-id <authoritative-id> --pair-port <pair-port> - outside-tmux tmux-session mode:
houmao-mgr agents gateway attach --target-tmux-session <tmux-session-name> - current-session mode: run
houmao-mgr agents gateway attachfrom inside the tmux session that owns the managed agent
Current-session mode is intentionally strict:
- the tmux session must publish
HOUMAO_MANIFEST_PATHor, failing that,HOUMAO_AGENT_IDplus a fresh shared-registryruntime.manifest_path - the resolved manifest must belong to the current tmux session
- the resolved manifest must use
backend = "houmao_server_rest" - manifest-declared attach authority is authoritative
- current-session attach becomes valid only after launch has completed managed-agent registration on that persisted
api_base_url
Outside-tmux tmux-session mode reuses the same manifest-backed authority, but begins from the addressed local tmux session name. It resolves HOUMAO_MANIFEST_PATH from that session first and falls back to a fresh exact shared-registry terminal.session_name match when the tmux-published manifest pointer is missing or stale.
The matching relaunch surface is houmao-mgr agents relaunch.
- explicit relaunch resolves either
--agent-name <friendly-name>or--agent-id <authoritative-id>through the managed-agent selector contract first - current-session relaunch runs inside the owning tmux session, resolves the manifest through
HOUMAO_MANIFEST_PATHor shared-registry fallback fromHOUMAO_AGENT_ID, and refreshes the tmux-backed runtime surface without rebuilding the managed-agent home
Pair-managed tmux topology is intentionally narrow:
- tmux window
0is the only contractual agent surface forhoumao_server_rest - same-session live gateway attach may create auxiliary non-zero windows inside that tmux session
- those auxiliary windows are not public contract by name, count, or order; use
houmao-mgr agents gateway statusfor the authoritative livegateway_tmux_window_index, or inspectgateway/run/current-instance.jsondirectly when you need the full tmux execution handle
Architecture¶
The pair uses a Houmao-owned control core for session and terminal lifecycle management.
The control core owns:
- session and terminal lifecycle (creation, bootstrap, teardown)
- tmux session and window creation
- provider bootstrap quirks for the supported launch surface
- terminal-scoped inbox behavior
- launch-time native selector resolution
- registry persistence for sessions, terminals, and inbox messages
The watch and tracking plane is Houmao-owned and separate from the control core:
- direct tmux pane resolution and capture
- process-tree inspection for supported TUI availability
- official parser selection through the shared parser stack
- continuous in-memory terminal state and bounded recent transitions
The public server contract is Houmao-owned:
- callers talk to
houmao-server - legacy
/cao/*routes are served locally byhoumao-serverfor backward compatibility, not reverse-proxied to a child process - runtime-owned
houmao_server_restsessions persist the public Houmao server base URL and session identity - root
GET /healthreportshoumao_service="houmao-server" - terminal-keyed Houmao extension routes resolve through Houmao-owned tracked-session identity
The pair exposes three public server surfaces:
- Houmao-owned root and terminal-tracking routes:
/health/houmao/terminals/{terminal_id}/*- legacy compatibility routes (preserved for
cao_restbackend sessions): /cao/health/cao/sessions/*/cao/terminals/*/cao/terminals/{terminal_id}/working-directory- shared managed-agent routes:
GET /houmao/agentsGET /houmao/agents/{agent_ref}GET /houmao/agents/{agent_ref}/stateGET /houmao/agents/{agent_ref}/state/detailGET /houmao/agents/{agent_ref}/historyPOST /houmao/agents/{agent_ref}/requestsGET /houmao/agents/{agent_ref}/gatewayPOST /houmao/agents/{agent_ref}/gateway/attachPOST /houmao/agents/{agent_ref}/gateway/detachPOST /houmao/agents/{agent_ref}/gateway/control/promptGET /houmao/agents/{agent_ref}/gateway/control/headless/statePOST /houmao/agents/{agent_ref}/gateway/control/headless/next-prompt-sessionPOST /houmao/agents/{agent_ref}/gateway/requestsGET /houmao/agents/{agent_ref}/gateway/mail-notifierPUT /houmao/agents/{agent_ref}/gateway/mail-notifierDELETE /houmao/agents/{agent_ref}/gateway/mail-notifierGET /houmao/agents/{agent_ref}/mail/statusPOST /houmao/agents/{agent_ref}/mail/checkPOST /houmao/agents/{agent_ref}/mail/sendPOST /houmao/agents/{agent_ref}/mail/reply- native headless lifecycle and durable turn routes:
POST /houmao/agents/headless/launchesPOST /houmao/agents/{agent_ref}/stopPOST /houmao/agents/{agent_ref}/turnsGET /houmao/agents/{agent_ref}/turns/{turn_id}GET /houmao/agents/{agent_ref}/turns/{turn_id}/eventsGET /houmao/agents/{agent_ref}/turns/{turn_id}/artifacts/stdoutGET /houmao/agents/{agent_ref}/turns/{turn_id}/artifacts/stderrPOST /houmao/agents/{agent_ref}/interrupt
Root /sessions/* and /terminals/* are intentionally not public at this boundary.
Provider Surface¶
The preserved pair launch provider surface is explicit:
kiro_cliclaude_codecodexgemini_clikimi_cliq_cli
If a provider is retired later, that narrowing must be explicit. The absorption change does not narrow provider support implicitly.
Persistence Boundary¶
The pair boundary is intentionally split into three groups.
Filesystem-authoritative artifacts:
- runtime-owned session roots and manifests
- runtime-owned manifest-backed gateway authority plus live gateway execution records
- shared-registry
live_agents/<agent-id>/record.jsonpointers while the bridge remains in use - server-backed managed-session manifests and session roots under
sessions/houmao_server_rest/... - native headless authority and per-turn records under
state/managed_agents/<tracked_agent_id>/
Filesystem-backed debug views:
run/current-instance.jsonandrun/houmao-server.pid- delegated-launch
sessions/<session-name>/registration.json - registry snapshot under
state/registry.json - launch-scoped sidecars under
state/launch_projection/
Memory-primary live state:
- known-session registry entries rebuilt from registration records and verified against live tmux
- active watch-worker ownership
- explicit transport/process/parse state for tracked sessions
- latest parsed supported-TUI surface, derived operator state, stability metadata, and bounded recent transitions
- rebuilt managed-agent alias resolution across TUI registrations and native headless authority records
Live terminal tracking remains authoritative in server memory. houmao-server does not write per-terminal tracker logs for the public contract.
Managed-agent history retention is intentionally split:
- TUI-backed
GET /houmao/agents/{agent_ref}/historyis a bounded in-memory projection built from the live tracker's recent transitions. It disappears when the server process forgets or loses that tracked live state. - Headless
GET /houmao/agents/{agent_ref}/historyis still coarse, but it is derived from persisted server-owned turn records understate/managed_agents/<tracked_agent_id>/. - Durable headless stdout, stderr, event streams, and return codes remain on
/houmao/agents/{agent_ref}/turns/*, not on/history.
houmao_server_rest Runtime Identity¶
Runtime-owned sessions that use the pair-backed mode persist backend = "houmao_server_rest".
That backend uses dedicated persisted sections instead of overloading the older legacy backend contract:
- session manifests write a
houmao_serversection withapi_base_url,session_name,terminal_id,parsing_mode, optionaltmux_window_name, andturn_index - internal gateway bootstrap artifacts use Houmao-specific backend metadata
- shared-registry records still point back to the runtime-owned manifest and session root instead of copying runtime state into the registry
This keeps the pair-owned compatibility transport details out of the persisted public contract while preserving existing discovery and gateway flows.
Storage Model¶
houmao-server provisions control state under a Houmao-owned per-server root:
<runtime-root>/houmao_servers/<host>-<port>/
state/
registry.json
launch_projection/
<session-name>/
<terminal-id>/
context.md
Launch-time native homes and manifests remain runtime-owned under the shared runtime root:
Those paths are internal implementation details. The supported operator workflow launches directly from native selectors (--agents) resolved from the effective agent-definition root.
Supported Operator Workflow¶
The supported operator workflow is the pair itself:
houmao-serveras the HTTP authorityhoumao-mgras the management CLI
The legacy /cao/* compatibility routes remain as server-owned transport shims for existing cao_rest sessions. The following entrypoints are retired: houmao-mgr cao ..., top-level houmao-mgr launch, standalone houmao-cao-server, and raw standalone cao_rest operator entrypoints.
Source References¶
src/houmao/server/app.pysrc/houmao/server/cli.pysrc/houmao/server/config.pysrc/houmao/server/service.pysrc/houmao/server/control_core/core.pysrc/houmao/server/control_core/provider_adapters.pysrc/houmao/server/managed_agents.pysrc/houmao/agents/native_launch_resolver.pysrc/houmao/srv_ctrl/cli.pysrc/houmao/srv_ctrl/commands/admin.pysrc/houmao/srv_ctrl/commands/brains.pysrc/houmao/srv_ctrl/commands/agents/core.pysrc/houmao/srv_ctrl/commands/agents/gateway.pysrc/houmao/srv_ctrl/commands/agents/mail.pysrc/houmao/srv_ctrl/commands/agents/turn.pysrc/houmao/agents/realm_controller/runtime.py