mibyan_cli/AGENTS.md (the rules) — this page holds the longer explanations.
Update pipeline
The stage-by-stage contract (plan → snapshot → apply → restart-per-kind → verify → report) and the
field failure each stage guards are documented in mibyan_cli/AGENTS.md; user-facing behaviour
(receipts, --plan, snapshot modes) is in Updating.
The systemd blunt-restart fallback waits for the unit’s TimeoutStopUSec plus
TimeoutStartUSec, with 15 seconds of client-side slack. It reads the target unit
in the same manager scope as the restart; both the initial attempt and retry use
this budget, including the catch-up restart after an interrupted update.
A start after a graceful drain uses only the start budget plus slack.
A missing, unparseable, or infinite phase limit falls back to 90 seconds
for that phase, keeping unattended updates bounded. Timing out the systemctl
client does not cancel the manager’s transaction. Custom multi-command stop
chains or EXTEND_TIMEOUT_USEC can still outlast this estimate; a real timeout
remains an incomplete restart, and successful commands still require the existing
service-health and fleet-version verification. Raw numeric *USec values are
microseconds, while formatted values use systemd’s fixed units, including days,
weeks, months and years. The combined timeout is capped below the native signed
32-bit millisecond poll limit (with rounding headroom), so exceptionally long
unit limits cannot overflow subprocess polling. Zero/unknown/infinite phase
limits use the bounded fallback. This does not change active-turn drain settings.
Process identity: never infer it from argv substrings
The bug class behind ~10 fleet-update issues (#90778, #87594, #78089, #76129, #91964, …): classifying a process by"serve" in cmdline or similar. kanban --preserve-cache contains
“serve”; a flag VALUE can equal a subcommand (-m dashboard serve); truncated cmdlines hide the real
subcommand. Rules:
- Use the canonical matchers:
gateway.status.looks_like_gateway_command_line(gateway run),mibyan_cli.update_cmd._mibyan_holder_subcommand(top-level subcommand of any Mibyan argv). Never hand-roll token scans. - Flag sets must be DERIVED from the parser (
_holder_value_flags()introspectsbuild_top_level_parser()), never hand-written lists — they drift. - Never blanket-exclude ancestors from process scans: when
/updateruns as the gateway’s child, a gateway ancestor must stay visible to the pause machinery (#87594). Exclude interactive ancestry, carve out gateway-shaped ancestors. - Match on FULL cmdlines; truncate only at display time (#78089).
- Before adding any new scan heuristic, read #92091 — the gateway control socket replaces scans as the primary coordination mechanism; scans are the fallback layer for old/crashed processes.
Skin engine — what skins customize
Built-in skins (
_BUILTIN_SKINS in mibyan_cli/skin_engine.py): default (classic gold/kawaii),
ares (crimson/bronze with custom spinner wings), mono (grayscale), slate (cool blue). Add a
built-in as a dict entry {"name", "description", "colors", "spinner", "branding", "tool_prefix"}.
User skins are ~/.mibyan/skins/<name>.yaml with the same keys, activated with /skin <name> or
display.skin: <name>; the full YAML template is in the
Skins & Themes user guide.
Profiles: multi-instance support
Mibyan supports profiles — fully isolated instances, each with its ownmibyan_HOME (config, API
keys, memory, sessions, skills, gateway). For single-profile commands (mibyan -p x <cmd>),
_apply_profile_override() in mibyan_cli/main.py sets mibyan_HOME before any module imports, so
every get_mibyan_home() reference scopes to the active profile. The multiplex gateway and the
Desktop/dashboard serve backend serve several profiles from one process instead: the active
profile is a contextvar override bound per activity, os.environ["mibyan_HOME"] stays the launch
profile’s, and a module-level constant derived from the home freezes to that launch profile (see
Gateway Internals § Multiplexed profiles). Profile
operations are HOME-anchored (_get_profiles_root() returns
Path.home() / ".mibyan" / "profiles", not get_mibyan_home() / "profiles") so
mibyan -p coder profile list sees all profiles regardless of which one is active — intentional.
Profile-safe coding rules are in the root AGENTS.md; multiplex secret-scope rules in
gateway/AGENTS.md.
