Why local automation needs two layers: the connector/muscle split for macOS
The first wrong answer
Our first pass at Mac automation was direct: a Tauri Rust command (applescript_run_jxa), a local SQLite database for provenance, and a React settings panel to manage capability grants. It worked on macOS. It felt complete.
It was wrong.
Not wrong in a "this code has a bug" way. Wrong in a "we're building a parallel governance system" way. HUMΛN's entire value proposition is a single fabric for provenance, delegation, and policy. The moment we wrote a local SQLite provenance table, we created a second fabric — one that nobody else in the system could see, verify, or audit.
If an agent ran builtin.mail.send on your Mac at 2 AM, what answered the question "did it happen, and who authorised it"? Not HumanOS. A file in /Users/you/Library/Application Support/human-app/mac_bridge_invocations.db that only your device could read.
That's not provenance. That's a log file.
The second wrong answer
So we moved the logic server-side. A server-side agent would call an API endpoint, that endpoint would somehow reach the macOS machine, run osascript, and log the result to the canonical provenance trail.
The problem: osascript does not run on Linux. The BRIDGE_PLATFORM_UNSUPPORTED error is not a temporary limitation — it is a permanent architectural constraint. AppleScript/JXA is a macOS-only runtime. Any JXA execution must happen on a Mac, either the agent machine itself (Path A) or the user's Companion app (Path B).
The correct answer: two explicit execution paths, both first-class
The HUMΛN architecture already had the vocabulary for this. We just had to use it correctly.
Connectors are transport
A connector is a bidirectional gateway to an external system. @human/connector-applescript is exactly that — it knows how to run JXA via child_process.execFile('/usr/bin/osascript'), it validates parameters against a command catalog, and it surfaces structured errors. It has no opinion on whether the human approved the action. It has no idea what organisation is calling it. It just runs the JXA and returns the output.
Critically: BaseConnector.invoke does not receive ExecutionContext. It cannot log provenance. It cannot request approval. It is transport.
Muscles are orchestration
A muscle is an intelligent runtime capability. MacAutomationMuscle extends BaseMuscle receives a MuscleInvocationContext — which includes ctx.provenance.log, ctx.approval.request, ctx.feedback.emit. The muscle knows the tier of the command being run. It knows whether human approval is required. It logs every significant step to the canonical HumanOS provenance trail.
The connector is a dependency of the muscle. The muscle tells the connector what to run. The muscle decides whether it's safe to run it.
Agent → muscle (HumanOS: policy, provenance, HITL) → connector (transport: JXA execution)
The tier model enforces this
Tier 0–1 commands (reads, pings) go straight through. Tier 2–3 commands (mutations, sends) hit ctx.approval.request() first — routing to the Workforce Cloud inbox where a human reviews and approves. That approval decision is in the canonical provenance trail. The reviewer's identity, the decision timestamp, the exact parameters reviewed — all cryptographically attributed.
This is what "single fabric" means. Not "we have a local log too."
Where local state belongs
The device-local PermissionStore (mac_capability_grants SQLite table via sqlx in apps/human-app) does still exist — but its role is tightly constrained. It answers a single question: "Has this device's user ever granted or denied this capability?"
This is device-local consent, not provenance. It supplements the server-side HITL gate — the Companion checks it before invoking JXA so that a tier: 2 command the user previously approved ("always" scope) doesn't re-prompt unnecessarily. But the authoritative record of what ran is the HumanOS provenance trail, not this table.
Local state for consent. Server-side for provenance. Never the other way around.
The two paths
Once the connector/muscle split was right, two natural execution paths emerged:
Path A — self-hosted macOS agent. The HUMΛN agent process runs on a Mac (personal server, macOS VM). ctx.call.invoke('applescript', { action: 'bridge.invoke', ... }) succeeds because osascript is available. The muscle gets back the JXA result, logs it to provenance, returns a MuscleResult.
Path B — Companion desktop integration. The HUMΛN agent server runs on Linux. bridge.invoke throws BRIDGE_PLATFORM_UNSUPPORTED. The muscle catches this, returns a MacAutomationIntent structured block. The Companion desktop receives it in the AgentAction inbox, renders a tier-coloured approval card (MacAutomationProposal.tsx), the user approves, and applescript_run_jxa Tauri command runs locally. The outcome is reported back via POST /v1/events/emit.
The muscle doesn't decide which path executes — the platform does. If the connector can run, it runs. If it can't, the intent is dispatched.
Why companion_integration: true
The SDK ConnectorManifest now has a companion_integration?: boolean field. Setting it signals two things:
- To developers: this connector's full capability requires the HUMΛN Companion desktop app. The cloud-only path degrades gracefully to structured intents, but JXA won't actually execute without a Mac.
- To the marketplace: the listing shows "Requires HUMΛN Companion for full capability." The validator enforces that
deployment.supportedModesincludes'self-hosted'— because the connector cannot be cloud-only.
This is how the ecosystem stays honest about what it can do without the desktop.
What this pattern enables
The connector/muscle split for local automation generalises. Any integration that requires native execution on a user's device — filesystem access, local database reads, camera or microphone capture, Bluetooth communication — follows the same pattern:
- Connector: transport layer, platform-specific native execution
- Muscle: HumanOS orchestration, policy enforcement, canonical provenance
companion_integration: true: honest signal that full capability needs the Companion
The Mac automation reference is intentionally minimal. It's designed to be cloned, not just studied.
Mac Automation Reference — Part 1 of 3