AI Decision System
Replayable, offline-verifiable records for AI-assisted go/no-go decisions: experiment promotions, typed model answers and human-approved actions.
mac은 다중 에이전트 조정자입니다
Multi-agent coordinator
개발 도구Python · ShellGitHub @jordanhubbard직접 설치운영자 미확인
써 보셨어요? 한 번만 눌러 주세요. 로그인은 필요 없어요.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
설치형 프로젝트는 배포 도메인 없이도 확인할 수 있습니다. 개인 저장소는 GitHub 로그인으로, 조직 저장소는 위의 저장소 확인 파일로 직접 확인해 주세요.
README 전체를 불러오는 중입니다. 아래는 저장된 발췌입니다.
Multi-agent coordinator control plane.
mac is a clean-room control plane for fleets of AI agents. It is designed to
sit underneath a human-facing agent runtime such as OpenClaw under OpenShell, NemoClaw Hermes, or a compatible system.README 전문 보기 ↗Multi-agent coordinator control plane.
mac is a clean-room control plane for fleets of AI agents. It is designed to
sit underneath Hermes, the human-facing agent runtime.
The human-facing runtime owns conversation, personality, adaptive memory,
skills, and messaging gateways. mac owns durable operational truth: tasks,
leases, routing, reviews, evidence, secrets, runtime manifests, and audit
trails. Hermes is the only human interface and chat gateway
(gateway_impl: hermes). Internal agents may share a stable public identity.
The goal is to let a user talk to an agent with a real personality and memory, then let that agent create durable work that a broader fleet can execute, review, publish, and recover.
If you are new to the project, start with the
production documentation book or read the
versioned HTML edition. It begins with
the system model and local operation, then advances through fleet deployment,
security, review, publication, and a complete request-to-production exercise.
Every chapter's shell example is executed by make docs-check as part of the
documentation build.
mac's control-plane code is clean-room work, but the system is not built in a
vacuum. It has learned from, interoperates with, or substantially relies on the
following projects. The relationship is stated explicitly so that an
integration or protocol influence is not mistaken for copied source:
3ebde2dd); see the vendor-fate record.
The gateway runtime is installed separately. First-party mac.hermes_adapter is
clean-room MAC code, not a copy of that snapshot. ADR 0001 is superseded
on the vendoring premise.relay extra is enabled.mac-firecrawl-gateway implements the Firecrawl v2 request/response
surface expected by Hermes. It is a clean-room compatibility gateway, not a
vendored copy of Firecrawl.mac task ledger is
now authoritative; MAC does not run Beads or Dolt.docs/superpowers were developed
with its agentic planning and execution workflow; it is not a runtime
dependency.This is a direct-lineage and architectural acknowledgement, not an exhaustive transitive dependency list. Python and Node dependencies remain documented in their manifests and lockfiles. Each upstream project remains subject to its own license.
This project provides durable contracts for coordinating a fleet:
mac task) — a beads-equivalent that avoids the
beads/dolt sync problems. .tickets/<id>.md is optional, gitignored local
compatibility output for human/IDE viewing when a .tickets/ directory already
exists; it is not cross-host sync and is not authoritative.mac task create --no-dispatch writes metadata.no_dispatch: true, ready/dispatch skip that
task, and mac task release clears that metadata key. Absence of the key is
the dispatchable state; project-level dispatch pause is a separate gate.eval_sets (scoring direction, baseline, regression threshold) and eval_runs against runtime environments or agent builds.With the default Hermes gateway, Hermes owns interaction:
SOUL.md, USER.md, MEMORY.md, skills, and session memory belong to Hermes.mac, but should pass only the sanitized operational context needed by the task.mac deliberately does not implement agent souls or personal memory. Its
memory_records are for operational provenance: imports, task evidence,
decisions, and durable facts needed to audit work. User memory
and personality memory stay in Hermes.
Shared long-term recall is hub-managed infrastructure. The hub runs Qdrant for
shared level-2 memory, while each agent keeps its local Hermes soul,
conversation state, and private memory under HERMES_HOME. Fleet deploy writes
a Hermes-visible memory topology file that tells every agent where those
boundaries are and which hub endpoint owns shared services.
The identity framework reflects that split:
tenant: an organization or isolated user deployment.user: a human identity inside a tenant.persona: a named Hermes personality with a soul_ref and memory_scope.persona_instance: a running or durable persona identity such as worker-1 (formerly hermes_instance).platform_binding: a Slack workspace/channel, Telegram chat, or similar binding.The guide is in docs/guide/:
| System Architecture | what the pieces are and how work flows — mostly diagrams |
| Getting Started | stand up a fleet, run a task, diagnose one that does not move |
| Advanced Concepts | leases, evidence, review, publication, and the known gaps |
| The UI | the read-only console the hub serves at /ui, and the unshipped Fleet IDE prototype |
| Developer Guide | how to hack on mac |
| Trust workflow | one request through acceptance, recovery, and measured results |
| Contributing | filing issues and PRs that are actually tested |
| Presentations | capabilities decks, including the v1.5.0 deck, each pinned to the commit it describes |
v1.5.0 capabilities (c7be3a5a) | current release deck: upfront validation, PostgreSQL test isolation, Hermes readiness and task outcomes — |
Those pages are written from the code and gated by
tests/test_guide_docs_are_true.py, which checks that every file they name
exists, every mac command they show resolves against the real parser, and
every edge in the task state diagram is one the control plane allows.
Every current documentation file is linked from the
complete documentation index, and
historical material — ADRs, field notes, and design specs kept for provenance —
lives behind the visibly-labelled historical archive,
which is not current product behaviour. The automated docs-graph gate
(scripts/check-docs-graph.py, run by make docs-check) traverses the internal
links out of this README.md and fails the build on any current doc that is
orphaned, any broken internal link, or any current doc missing from the index.
# See every supported lifecycle target. Bare `make` prints the same help.
make help
# Install/link the CLI and build the hub UI.
make install
# Verify the checkout, or log in and run the hub UI against that hub.
make test
mac admin login
make run-gui
The hub serves its UI at <hub>/ui — the observability console built from
observe/. make run-gui runs that same source tree locally. The bare hub root
and the /dashboard/* routes require a bearer token, so an unauthenticated
browser gets 403 there; /ui is the front door.
make test runs the complete hermetic pytest suite with statement, branch, and
Python-subprocess coverage for MAC-owned src/mac code. Coverage is a
regression safety floor rather than a target for generating tests; see
the test portfolio strategy. Use make coverage
for the same full-suite report, make test-portfolio to audit redundant
execution, and make fault-replay to prove tests detect known historical bugs.
A single shared Ruff configuration lives in
[tool.ruff] in pyproject.toml, so linting and formatting are byte-identical
on every host instead of ad-hoc per-directory settings.
make lint # diagnose: ruff check + ruff format --check
make lint-fix # apply those same fixes (ruff check --fix + ruff format)
The enforced lint set starts at the always-green correctness floor (pyflakes
logic errors and undefined names, plus syntax errors). Formatting is in the
same gate, so make lint-fix cannot rewrite files make lint never mentioned.
Widen [tool.ruff.lint].select as the codebase is cleaned up. Ruff is a
dev-only tool pinned in the dev extra and fetched on demand with
uv run --with ruff; it is not a runtime dependency.
The common lifecycle is deliberately conventional:
make install # CLI + the hub UI bundle
make build # Python wheel + the hub UI bundle
make clean # generated artifacts only
make distclean # also remove .venv and node_modules
Use make install-cli or make install-gui when only one surface is needed.
Installation requires Python 3.14.7 (pinned in .python-version), uv, Git,
GitHub CLI (gh), and npm. uv python install provisions the reviewed Python
version. See the Python baseline for environment
updates. Fleet provisioning and updates are separate: see
Updating the fleet with fleet-update.
For local control-plane/API development after installation:
# Required: a 32+ char secret used to derive the Fernet key for the secrets table.
# Without it, the CLI and API both refuse to start.
export MAC_SECRET_KEY="$(openssl rand -base64 32)"
# PostgreSQL is the only supported backend. scripts/start-test-postgres.sh
# finds a local server or starts a container and prints the DSN to export.
eval "$(scripts/start-test-postgres.sh)"
export MAC_DB="$MAC_TEST_PG_URL"
uv run --extra postgres mac --db "$MAC_DB" admin init
uv run --extra postgres uvicorn mac.api:app --reload
uv run mac-hermes --url http://127.0.0.1:8789 --help
For standalone local work, pass --db <postgres-dsn>. MAC_DB is server
configuration; it does not implicitly opt CLI commands into direct database
access. Without --db, the CLI selects a configured hub (--hub-url,
MAC_API_URL, MAC_URL, MAC_HUB_URL, or ~/.mac/fleets.yaml) and otherwise
refuses to run rather than guessing an authority. On a deployed hub, where
MAC_DB and MAC_HUB_URL are both present, operator commands use the HTTP API.
Control-plane server startup likewise requires an explicit MAC_DB /
MAC_DATABASE_URL PostgreSQL DSN.
--db selects a direct PostgreSQL authority. It is appropriate for a
standalone development database, tests, explicit migrations, and stopped-hub
maintenance; it is not an offline cache, and its tasks are never uploaded,
merged, or reconciled with a remote hub. Aiming --db at a deployed hub's
configured authority therefore requires --local-authority. MAC also probes
the configured local health endpoint and refuses that maintenance mode while
the hub is running.
Normal operations against a running hub omit both flags:
mac task stats
mac task show task_...
For exceptional direct-database maintenance, stop mac-api first, preserve its
existing MAC_DB environment, and make the override explicit:
mac --local-authority task stats
Restart the hub before resuming fleet work. Opening an existing database through
this direct path does not run schema DDL. Schema creation and additive migrations
run at control-plane startup or through an explicit mac --db <dsn> admin init.
The hub ledger is intentionally not rooted in one checkout. It coordinates leases, agents, reviews, workflows, evidence, A2A work, non-repository operations, and tasks spanning multiple repositories. A task reaches source through its project repository registration and execution contract.
Fleet deployment assigns MAC_CONTROL_PLANE_ROLE=hub only to the selected hub.
That host receives the explicit database configuration and runs mac-api.
Spokes have MAC_CONTROL_PLANE_ROLE=client, no MAC_DB, and register their
workers and Hermes identities through the hub API.
GitHub issues remain external project-planning records. .tickets/ is ignored
local migration/compatibility state, not another execution authority. Bridges
may create a hub task from an external issue, but the resulting mac task
record in the selected control-plane authority is what agents claim and run.
One-time imports into a hub authority are available through
mac admin migrate import, which replays a JSONL record stream. Run
mac admin migrate help for the current set.
mac admin login bootstraps a new client from verified SSH access to the hub. It
pins the host identity, opens the hub-local API tunnel, requests an independently
revocable scoped credential over SSH, validates that credential through the
tunnel, and only then atomically installs the local profile and mode-0600
secret. Managed tunnels reconnect on the next profile-backed command if their
SSH process has exited.
mac admin login --ssh [email protected] \
--identity-file ~/.ssh/mac-production \
--known-hosts-file ~/.ssh/mac-production-known-hosts \
--fleet production --profile production --client-id my-laptop
mac admin login status --profile production
mac task stats
mac agent list
mac admin login renew --profile production
mac admin logout --profile production --revoke
# Directly reachable scoped endpoint (automation/operator provisioning):
export MAC_API_URL=https://mac.example.internal
export MAC_API_TOKEN=<scoped-client-token>
mac admin diagnostics
mac task stats
# Shared-admin recovery for an existing operator workstation only:
mac admin fleet sync-token --fleet my-fleet
mac --fleet my-fleet diagnostics
Prefer environment or mode-0600 files over --token, which can expose a
token through shell history or process inspection. fleet sync-token copies
the historical administrator token; do not use it for routine new-client
onboarding. See SSH Client Bootstrap Contracts
and Production Deployment.
Task cancellation records why its worker branches should be preserved or may
eventually be removed. Missing dispositions default to preserve; duplicate
and superseded work must name the replacement task. Audit and prune are
fail-closed, and manual prune is read-only unless --execute is explicit. Fleet
deployment enables a daily prune reconciler on the hub only; the runtime
default remains off for standalone API processes and stateless replicas.
mac task close task_old --cancelled --disposition superseded \
--replacement-task task_new --reason "replacement published"
# Immediate operator stop: revoke the live lease and make the owning loop
# worker terminate its active executor tree on the next cancellation poll.
mac task cancel task_running --reason "operator stopped obsolete work"
git fetch --prune origin
mac --json admin repo refs audit --repo .
mac --json admin repo refs prune --repo . # dry-run
mac --json admin repo refs prune --repo . --execute --actor operator
# Hub-wide automatic reconciler status and immediate admin-triggered passes.
mac --json admin repo refs status
mac --json admin repo refs reconcile --mode audit --actor operator
mac --json admin repo refs reconcile --mode prune --actor operator
See Managed Repository Ref Hygiene for the schedule/configuration, disposition policy, exact-SHA deletion contract, grace periods, monitoring, and recovery.
The Quick Start above installs the CLI from a checkout. This creates a fleet:
a named hub plus the workers that join it. A fleet is a first-class object —
~/.mac/fleets.yaml holds as many as you like, each with its own hub URL and
token, selected with --fleet <name> or $MAC_FLEET.
Each host runs MAC from a git checkout at ~/.mac/src/mac. Provision the hub
and each worker by hand with the "Provision a new host" checklist in
Updating the fleet with fleet-update. You
need SSH key access from the hub to every worker and at least one upstream LLM
provider API key (nvidia / openai / anthropic / perplexity).
~/.mac/fleets.yaml and the env files are not in this
repository, and should never be committed: fleet topology and provider keys
are yours, not the product's.
From the hub, move the hub and every worker to a commit, one host at a time:
scripts/fleet-update --dry-run all <sha>
scripts/fleet-update all <sha>
mac --fleet <name> agent list # who joined, and what hardware they have
mac --fleet <name> task ready # what the fleet could pick up right now
Open the console in a browser at http://<hub>:8789/ui. It is read-only, and
shows tasks and agents actually moving through states rather than a snapshot of
counts.
mac --fleet <name> task create "the thing you want done" \
--description-file=brief.txt
The fleet claims it, works it in a sandbox, and publishes through review. Watch the transitions land in the console's live view while you talk to Claude Code, Codex or Cursor in the other window.
mac admin mcp serve exposes the ledger to a coding agent as MCP tools, so the
agent can read and file tasks directly instead of shelling out and parsing
tables.
mac --fleet <name> admin diagnostics # what the hub thinks is wrong
mac --fleet <name> task why-unclaimed <id> # why a specific task is not moving
mac --fleet <name> task preflight ... # before filing: could this ever be claimed?
The most common cause of a task that is created and never claimed is asking for
a capability the fleet does not advertise. Host facts like linux are not
capabilities — see Requirements: capabilities versus
hardware.
Run the REST API with MAC_SECRET_KEY and an explicit database set:
MAC_SECRET_KEY="..." MAC_DB="postgresql://..." uv run uvicorn mac.api:app --reload
# or use factory mode to be explicit:
MAC_SECRET_KEY="..." MAC_DATABASE_URL="postgresql://..." \
uv run uvicorn mac.api:create_app --factory --reload
Set MAC_API_TOKEN for one admin token, or MAC_API_TOKENS as JSON such as
{"reader":["read"],"worker":["agent","dispatch"]} to require scoped bearer
tokens. Hub-local mac admin client enroll writes independently revocable hashed
principals to MAC_CLIENT_PRINCIPALS_FILE; the API hot-reloads that registry.
With no static token or enrolled client configured, the local prototype API
remains open for development.
The observability console is served at /ui (and /ui/console). Static assets
are public so the browser can load the shell, while data requests use the same
API token rules as the REST API.
It is READ-ONLY, and that is the point rather than a limitation. It answers what the fleet is doing — tasks and agents moving through states — with views for live movement, stuck work, agents, projects, pipelines, telemetry, the merge queue, and a per-task drill-down. The live view charts state transitions per time bucket, because a count tells you 360 tasks are blocked and only a series tells you whether they are arriving or draining.
Two properties it will not trade away:
degraded, never
rendered as a plausible zero. observe/tests/readonly.test.ts asserts the
whole app is read-only./dispatch/tick, /agents/bulk, /roles/seed,
/notifier/deliver and /secrets; a UI whose job is to observe cannot also
be the one that commands.The console is built from observe/ (React + Vite) into src/mac/ui/console/,
which is committed, so serving it needs no Node.js at runtime. Rebuild with
npm --prefix observe run build after changing the source; CI fails if the
committed bundle drifts from it.
Mutating operations live in the CLI (mac ...), the REST API, and the Fleet
IDE (ide/).
Key route groups:
/tenants, /users, /personas/persona-instances, /persona-instances/{id}/context, /persona-instances/{id}/work-context, /platform-bindings/dashboard/state, /dashboard/stream, /dashboard/observe, /dashboard/observe/tasks/{id}, /dashboard/observe/projects/{project}/graph, /dashboard/workflow-plan/preview, /dashboard/workflow-plan/accept/tasks, /tasks/{id}/evidence, /tasks/{id}/reviews, /reviews/default/tick, /publications/machines, /agents, /agents/{id}/heartbeat, /agents/{id}/claim-next, /dispatch/tick, /dispatch/dead-letters/roles, /agents/{id}/role, /agents/{id}/identity/workflows, /workflows/import-yaml, /workflows/seed, /workflows/{id}/start, /workflows/runs, /workflows/runs/tick/messages/agentbus, /agentbus/streams, /agentbus/streams/{id}/chunks, /agentbus/streams/{id}/events/agentbus/repo-update, /agentbus/artifact-publish/command-audit, /agents/{id}/command-audit/secrets, /secrets/{id}/access, /secrets/{id}/reveal, /secret-audits/runtimes, /runtime-runs/artifacts, /artifacts/{id_or_digest} — canonical record for deliverables (kind, digest, uri, sbom_uri, signers); re-registering the same digest augments signers/metadata/fleet/build-distribution — aggregate live agents by running_digest; agents declare their build via heartbeat/bridge/items, /memory/eval-sets, /eval-sets/{id}/baseline, /eval-sets/{id}/events, /eval-runsThe hub serves one browser UI: the read-only observability console, at
<hub>/ui. Its source is observe/; npm run build there writes the committed
bundle in src/mac/ui/console/, which is what the hub's /ui/assets mount
serves. From the repository root:
make install-gui # build the bundle the hub serves
mac admin login
make run-gui # run that same tree locally on http://127.0.0.1:5274
make build-gui
make package-gui # writes dist/mac-hub-ui.tar.gz
make run-gui proxies /dashboard/* to $MAC_API_URL (default
http://127.0.0.1:8789) and sends the bearer from MAC_UI_PROXY_TOKEN,
MAC_DEPLOY_HUB_TOKEN or MAC_API_TOKEN — sourced from ~/.mac/.env if
present, never printed. tests/ui/test_hub_ui_is_one_tree.py asserts that what
run-gui runs and what the hub serves are the same tree.
ide/)The React + Monaco fleet IDE in ide/ is a local prototype that no hub
serves, kept runnable behind its own targets. make install, make build and
make package do not produce it, and no deploy step installs it. See
ADR 0025.
make ide-install
mac admin login
make ide-run # Vite on http://127.0.0.1:5273
make ide-build
make ide-package # writes dist/mac-ide-web.tar.gz
For local auth, make ide-run first reuses the active scoped client profile
created by mac admin login, including its managed SSH tunnel. In an interactive
terminal it then prompts for the target hub URL; press Enter for the profile
endpoint, enter another http:// or https:// host, or set IDE_API_URL
beforehand to skip the prompt. The credential stays inside the local Vite proxy
and is not exposed to browser storage. If no active profile exists, the launcher
can read a deploy-created owner-only handoff file:
IDE_HANDOFF_FILE="$HOME/.mac/fleet-ide-handoff.json" IDE_OPEN=1 make ide-run
The handoff file keeps the bearer out of browser-visible environment, argv,
stdout, and deploy logs. As a final compatibility fallback the launcher sources
~/.mac/.env and selects a token without printing it. Set IDE_FLEET=<fleet> to
prefer the matching MAC_API_TOKEN__<FLEET> key; otherwise the launcher falls
back to MAC_DEPLOY_HUB_TOKEN and then MAC_API_TOKEN. The Electron dashboard
wrapper in desktop/ renders this prototype and is maintenance-only.
Agents work on dispatchable tasks, not on repositories by implication. The
operator flow is below. Use --db for local mode, or omit it when your CLI is
already pointed at a hub through --hub-url, environment, or ~/.mac/fleets.yaml.
mac --db "$MAC_DB" project register [email protected]:ORG/REPO.git#main --project my-project
# After the onboarding task has produced .mac/project.yaml and that contract
# exists in a hub-visible checkout:
mac --db "$MAC_DB" bridge repository register my-project /srv/repos/my-project --project my-project
# or, for a non-repository/manual project:
mac --db "$MAC_DB" project create my-project --active
mac --db "$MAC_DB" task create "Fix failing tests" \
--project my-project \
--description-file desc.txt \
--required-capabilities python
mac --db "$MAC_DB" project activate my-project # if the project was staged/paused
mac --db "$MAC_DB" task release task_... # if the task was created with --no-dispatch
mac --db "$MAC_DB" dispatch tick --limit 10 # assign ready work now
The canonical project registration is GIT_URL#BRANCH; omitting the fragment
means #main. The same Git URL can therefore have independent MAC projects for
different branches, while registering the same URL and branch twice is rejected.
When --project is omitted, a non-main branch is named REPO@BRANCH.
Project records have a complete operator surface:
mac project list
mac project show my-project
mac project update my-project --branch release/next
mac project update my-project --registration [email protected]:ORG/REPO.git#other
mac project unregister my-project --force
unregister refuses projects with linked tasks or internal checkout attachments unless --force is
given; forced removal detaches historical tasks and disables linked checkout
attachments rather than deleting their history.
Loop-mode agents claim matching work from mac task ready. For explicit manual
assignment, use mac task claim <task_id> <agent_id> followed by
mac task start <task_id> <agent_id> with the same transport flags.
For repository-backed work, the production path is:
mac project register from
a checkout, pass another local checkout path, or use mac project register <git-url>[#branch] for remote-first onboarding. Registration creates the
contract-authoring onboarding task. Follow it with mac bridge repository register <name> <path> --project <project> once .mac/project.yaml exists
in a hub-visible checkout. The mac task ledger is canonical; ready work is
mac task ready.mac.worker_evidence.v1
verification manifest. Repository work must report pushed/clean git state
and passing checks before it can enter review.review.require_independent_reviewer: true in task metadata when a task
must wait rather than use this fallback. For remote repositories it consults shared
fleet_learning:repository_access memory: a recent successful clone is
preferred, while a newer authentication or authorization failure makes that
agent temporarily ineligible for the same project, host, and operation.origin, and
record a secret-free success or failure learning. An authentication failure
triggers immediate reviewer re-evaluation instead of repeating the same
credential pattern.review_verdict evidence targeting the
immutable executor evidence selected when the attempt entered review. Hub
verify (deterministic contract tests, signed by the virtual hub-reviewer)
owns the verdict. There is no LLM semantic reviewer on the default path —
that gate rejected already-passing, already-pushed work on the 2026-08-23
release blockers. Independent build and test checks may still veto an
approval. Review nudges are capped by durable delivered attempts, so a
verifier that cannot produce a verdict is retracted instead of being
nudged indefinitely.mac records the complete ledger in task history, evidence, reviews, publications, command audit, observability, and notifications — all in the mac task store, which is authoritative. Lease renewals stay internal to avoid noise.
Repository-access failure cooldown defaults to 30 minutes
(MAC_REPOSITORY_ACCESS_FAILURE_COOLDOWN_SECONDS=1800), successful access is
preferred for 24 hours (MAC_REPOSITORY_ACCESS_SUCCESS_TTL_SECONDS=86400), and
review verdict nudges default to 10 delivered attempts
(MAC_REVIEW_NUDGE_MAX_ATTEMPTS=10). Stale workflow advancement reservations
are recovered after 60 seconds by default
(MAC_WORKFLOW_ADVANCEMENT_RESERVATION_SECONDS=60). See
Fleet Operational Learning for the record
schema, credential boundaries, inspection commands, and failure semantics.
mac has an API-level workflow system for turning an agentic multi-step plan into durable tasks:
Workflow runs are deliberately single-current-node routing state machines, not parallel fan-out engines. Cooperative fan-out uses task children and dependencies: each child is assigned to a distinct executor, completed child evidence contributes immutable commit/ref inputs to the reopened parent, and a different integration executor must merge every exact child commit and verify the combined result before the parent can enter review.
Node advancement uses a durable reservation containing the preallocated next task ID. Task creation, workflow linkage, and task-created history commit atomically; a stale reservation can therefore recreate or adopt that same task without duplication. Workflow history for pre-decided approval chains is staged until the downstream task and run transition finalize together. Cancelling a run commits the run state, current-task cancellation, history, and transition outbox atomically, so the cancellation callback cannot create downstream work.
Dispatcher recovery reads bounded pages selected by the indexed
workflow_runs.next_action_at deadline; it does not scan workflow-definition
JSON to discover timeouts. A malformed run records a run-scoped failure and
does not stop later candidates. Default-review sweeps query only needs_review
and reviewing rows. Autonomous workflow/review cursors and short leases live
in reconciliation_state, so traversal survives restarts and competing hub
replicas do not process the same page.
Each dispatch tick performs one bounded expired-lease page, one bounded
blocked-task page, and one bounded task/agent inventory pass before assigning a
batch. Dead-letter output is bounded too; /dispatch/dead-letters/page exposes
its opaque next_cursor for complete traversal.
The REST API and CLI can create, import, seed, start, cancel, and tick workflow
runs today, and /dashboard/state includes workflow-run summary data for UI
clients. The checked-in dashboard does not yet provide a full visual workflow
authoring UI for humans to edit plans and answer all agent questions up front.
mac --db "$MAC_DB" machine register workstation-1
mac --db "$MAC_DB" agent register machine_... worker --capabilities python,review
mac --db "$MAC_DB" tenant register personal
mac --db "$MAC_DB" persona register tenant_... AssistantOne --soul-ref hermes://personal/assistant-one/SOUL.md --memory-scope hermes://personal/assistant-one/memory
mac --db "$MAC_DB" hermes register tenant_... assistant-one --persona-id persona_... --home-ref hermes://personal/assistant-one
mac --db "$MAC_DB" binding register tenant_... hermes_... slack T123/C456 --display-name "#ops"
mac --db "$MAC_DB" interaction task hermes_... "Investigate deployment failure" --platform-binding-id binding_...
mac --db "$MAC_DB" task create "Implement feature" --required-capabilities python
mac --db "$MAC_DB" dispatch tick
mac --db "$MAC_DB" task show task_...
# Inspect secret-free repository-access outcomes used by reviewer routing.
mac --db "$MAC_DB" --json memory search \
--record-type fleet_learning:repository_access --order desc --limit 50
# Secrets: prefer stdin or file input over argv to keep values out of shell history.
echo -n "$GH_TOKEN" | mac --db "$MAC_DB" secret set github-token \
--from-stdin --scopes '{"capabilities":["deploy"]}' --created-by human
mac --db "$MAC_DB" secret set release-key --from-file ./release.key \
--scopes '{"capabilities":["deploy"]}' --created-by human
# Runtime manifests must pin images and dependencies.
mac --db "$MAC_DB" runtime create mac-runtime \
--manifest '{"image":"python:3.12@sha256:abc123","dependencies":["fastapi==0.111.0"]}' \
--created-by human
# Evaluation: define a scored eval set and record runs against a runtime.
mac --db "$MAC_DB" eval set create task-success-rate \
--scoring higher_is_better --baseline-score 0.90 --regression-threshold 0.02
mac --db "$MAC_DB" eval run record evalset_... runtime_environment runtime_... 0.93
# Unified audit stream: one query across task/agent/project/fleet/eval_set/secret events.
mac --db "$MAC_DB" events list --limit 50
mac --db "$MAC_DB" events list --subject-type eval_set --subject-id evalset_...
mac --db "$MAC_DB" events list --prefix task. --since 2026-05-17T00:00:00+00:00
mac --db "$MAC_DB" events list --actor monitor --event-type eval_set.baseline_changed
mac --db "$MAC_DB" observability list --layer control_plane --subject-type fleet
# Artifact registry + fleet build inventory.
mac --db "$MAC_DB" artifact register image sha256:abc... artifact://mac/v1.2.0 \
--created-by ci --sbom-uri sbom://mac/v1.2.0.spdx --signers ci,release-manager
mac --db "$MAC_DB" agent heartbeat agent_... --running-digest <runtime-digest>
mac --db "$MAC_DB" fleet build-distribution
# Minimal worker harness: register/heartbeat first without claiming, then run
# an executor-backed claim/start/evidence/submit loop.
mac-agent --url http://hub.example.internal:8789 --register --agent-name worker-1 \
--hostname worker-1.local --capabilities python,ops,review \
--resources '{"capacity":2}' --heartbeat-only
mac-agent --url http://hub.example.internal:8789 --register --agent-name worker-1 \
--capabilities python,ops,review --allowed-projects mac-canary --claim-only-canary-tasks \
--dry-run-claim
mac-agent --url http://hub.example.internal:8789 --agent-id agent_... \
--workspace ~/.mac-agent/workspaces --allowed-projects mac-canary \
--claim-only-canary-tasks --executor ~/.mac/bin/mac-hermes-task-executor
mac-agent --url http://hub.example.internal:8789 --register --agent-name worker-1 \
--capabilities python,ops,review --loop --workspace ~/.mac-agent/workspaces \
--allowed-projects mac-canary --claim-only-canary-tasks \
--executor ~/.mac/bin/mac-hermes-task-executor
# Typed AgentBus: durable ordered content chunks; this is transport, not exec.
mac --db "$MAC_DB" agentbus publish agent_sender --recipient-agent-id agent_recipient \
--content-type application/vnd.mac.delta+json \
--payload '{"kind":"delta","content":"hello"}'
mac --db "$MAC_DB" agentbus read bus_... agent_recipient
Hermes-facing API adapter:
mac-hermes --url http://127.0.0.1:8789 register \
--tenant personal \
--persona AssistantOne \
--instance assistant-one \
--soul-ref hermes://personal/assistant-one/SOUL.md \
--memory-scope hermes://personal/assistant-one/memory \
--binding slack:T123/C456:#ops
mac-hermes --url http://127.0.0.1:8789 task hermes_... \
"Investigate deployment failure" \
--summary "The Slack deployment thread reports a failed publish step." \
--platform-binding-id binding_... \
--conversation-ref slack://T123/C456/1712345678.000100 \
--required-capabilities ops
mac-hermes --url http://127.0.0.1:8789 reply task_...
mac-hermes --url http://127.0.0.1:8789 writeback hermes_... task_...
Clients read fleet topology from the home-scoped registry ~/.mac/fleets.yaml;
each fleet is keyed by its hub node name. Hosts are provisioned and updated as
described in Updating the fleet with fleet-update.
Fleet mesh networking is selected in that registry with network.provider;
tailscale is the default, while headscale is advanced opt-in and requires an
explicit login server, enrollment-key source, DNS assumption, and health check.
Part 18 of an ongoing chronicle. ← Part 17: PythonOS | Part 19: c26 → Chronicle index · Ordered by first recorded AI-assisted commit.
The programmer had discovered that asking an agent to do something and knowing what had actually happened were different problems.
Sir Reginald von Fluffington III had spent years exploiting this distinction. A request to leave the keyboard did not imply a departure, and a statement that dinner would be served shortly was not evidence of dinner.
“I need durable operational truth,” the programmer announced.
The cat remained where he was. At least one fact was stable.
MAC became a control plane for fleets of agents. Conversation and personality could belong to the human-facing runtime. Tasks, leases, dispatch, reviews, publication records, and recovery needed somewhere less dependent on everyone remembering the last conversation in precisely the same way.
The task ledger lived in PostgreSQL. A registry described machines and agents. Dispatch matched work to capabilities and capacity. Leases expired, workers failed, and recovery had to mean more than asking the same question more emphatically. The programmer could see the beginnings of an institution. Sir Reginald saw a new filing system in which to be marked unavailable.
Evidence became central. A worker's assertion that a change was ready was not the same thing as tests passing, an independent review approving that attempt, and the resulting commit being published. The records needed to agree about which work had been inspected. Otherwise a perfectly valid approval could end up vouching for something that had changed since lunch.
Sir Reginald inspected lunch. It had changed insufficiently.
The message bus acquired ordered streams. The fleet acquired runtime manifests, secrets handling, health records, and rollout state. External runtimes and execution tools kept their own roles; MAC kept the record of what the fleet had been asked to do and what it could prove it had done.
“It is coordination,” the programmer said, “with a memory.”
Sir Reginald rose, stretched, and returned to the same patch of keyboard. His state transition was observable, his lease appeared indefinite, and no review had authorized his publication of kkkkkkkk into the terminal.
The programmer called the design elegant. Sir Reginald withheld endorsement, citing insufficient tuna and a control plane that continued to misclassify the actual household administrator as a pet.
mac CLI.mac-hermes adapter for registration, sanitized task creation, status replies, and memory write-back payloads./eventssubject_typesubject_idactorevent_typeevent_type_prefixsinceuntillimit/observability, /observability/metrics, /observability/logs, /observability/summary, /observability/stream — low-level metric/log ingestion, query, summary, and NDJSON subscription across API, control-plane, worker, Hermes, deploy, and external-agent layers/notifications, /notifications/{id}/delivered/integrations/findings, /integrations/observations/agents/{id}/mood, /agents/{id}/mood/history — agent-self-reported emotional state (warm/cheerful/sad/curt/cold/irritated/angry/enraged) with reason + optional TTL; transitions flow through /events as subject_type=agent/agents/{id}/nap-schedule, /agents/{id}/nap-schedule/next, /nap-schedules, /nap-runs, /nap-runs/{id}/complete, /nap-runs/{id}/fail — daily memory-consolidation lifecycle. Offset defaults to md5(agent.name) %% 360 minutes (spreads the fleet across the 0–6h UTC window). mac coordinates begin → DRAINING → complete/fail; summarization and vector storage are off-process and linked via evidence + vector_refs.