Skip to main content
HUMΛN
Architecture
Architecture

companion_integration: true — what it means and when the Companion runs instead of the cloud

HUMΛN Team··7 min·Engineers

The @human/connector-applescript manifest now includes:

companion_integration: true,

This field was added to ConnectorManifest specifically because we needed vocabulary for a class of connectors that the existing model didn't handle well. Here's what the problem was, and what the field actually means — and what it doesn't.

The problem with "installable connector"

The standard HUMΛN connector model assumes cloud deployment: you install a connector, HUMΛN provisions credentials, the agent runtime calls connector.invoke() from whatever server is running the agent. The connector is a network gateway.

@human/connector-applescript doesn't fit this. It's not a network gateway. It's a process executor. child_process.execFile('/usr/bin/osascript') — that call works on macOS and nowhere else. If you install this connector on a Linux-hosted org, the transport layer will always return BRIDGE_PLATFORM_UNSUPPORTED. The connector isn't broken; the operating system just doesn't have the runtime.

Before companion_integration, a developer browsing the marketplace had no signal that this connector behaves differently from Slack or GitHub. They'd install it, wire it to a muscle, and get a confusing error on their first call.

What companion_integration: true signals

To developers: this connector has a first-class HUMΛN Companion desktop integration. The Companion app provides a native execution path — in the case of AppleScript, that's the applescript_run_jxa Tauri command, which runs osascript locally on the user's Mac. You get the full tier-gated governance experience, the structured approval card in the inbox, and outcome reporting via POST /v1/events/emit. But you need the Companion app running on a Mac for any of that to work.

To the validator: companion_integration: true requires deployment.supportedModes to include 'self-hosted'. A cloud-only connector cannot meaningfully set this flag — if there's no native execution path, there's no companion integration.

To the marketplace listing: the card shows "Requires HUMΛN Companion for full capability." This is accurate without being alarming — the connector still works in cloud-to-Mac scenarios, it just needs the Companion as the executor.

To the muscle: nothing, directly. The muscle doesn't read the connector manifest. It calls ctx.call.invoke('applescript', ...), handles BRIDGE_PLATFORM_UNSUPPORTED by returning a structured intent, and leaves routing to the platform. The muscle works the same way regardless of whether the connector is companion_integration or not.

The execution decision tree

When mac.invoke is called on the muscle:

Is ctx.call.invoke('applescript', 'bridge.invoke') available?
  │
  ├── YES (Path A: macOS agent)
  │     → connector.invoke() → jxa-runner.ts → osascript
  │     → MuscleResult { success: true, data: output }
  │
  └── NO (throws BRIDGE_PLATFORM_UNSUPPORTED)
        → muscle catches
        → returns MacAutomationIntent { type: 'mac_automation', requires_companion: true, ... }
        → Companion desktop picks it up from AgentAction.structured_data
        → MacAutomationProposal.tsx renders
        → User approves
        → applescript_run_jxa Tauri command executes JXA
        → onApprove(execution_id, 'approved') → POST /v1/events/emit

The muscle doesn't decide the path. It tries cloud-first and degrades gracefully to Companion. This means a single muscle deployment works in both environments without configuration.

What requires_companion: true means in the intent block

When the muscle returns a MacAutomationIntent, the requires_companion: true field is a signal to the Companion renderer — specifically to NotificationInbox.tsx. When action_type === 'mac_automation', the inbox renders MacAutomationProposal instead of the generic ApprovalPrompt. The proposal renderer knows how to:

  • Check device-local grants (permission_check Tauri command) before running
  • Build the JXA source from the catalog (buildJxaForCatalogCommand from @human/connector-applescript/frontend)
  • Execute it (applescript_run_jxa)
  • Handle TCC errors (the "not authorized to send Apple Events" macOS security error) with a deep-link to System Settings
  • Report the outcome back to HumanOS

A non-Companion client (a web browser, a CLI, another agent) that receives this intent can display it as a pending action but cannot execute it. That's correct — execution requires a macOS Tauri runtime.

There is a device-local SQLite table (mac_capability_grants) managed by permission_store.rs in apps/human-app. It answers one question: "Has the user on this device previously granted or denied this capability ID?"

This is not provenance. The canonical provenance for every Mac automation execution lives in HumanOS — logged by the muscle via ctx.provenance.log. The PermissionStore supplements the server-side HITL gate by preventing unnecessary re-prompts for commands the user has already "always allowed." It does not replace it.

The distinction matters: if the PermissionStore says "always granted" but the HumanOS policy for tier 2 operations requires fresh approval, the server-side gate wins. The PermissionStore is advisory UX, not authoritative policy.

How to build your own companion_integration: true connector

The Mac automation reference is designed to be cloned. Any connector that requires native execution on the user's device follows the same pattern:

  1. Connector manifest: set companion_integration: true, add 'self-hosted' to deployment.supportedModes
  2. Transport: implement BaseConnector.invoke for the native execution path. Return BRIDGE_PLATFORM_UNSUPPORTED (or similar) on non-supported platforms
  3. Muscle: catch the unsupported error, return a structured intent with type: 'your_connector_type'
  4. Companion renderer: add a new StructuredRenderer in apps/human-app/src/components/StructuredRenderers/, wire it into NotificationInbox.tsx on action_type === 'your_connector_type'
  5. Tauri commands: add the native execution commands to src-tauri/src/, register in lib.rs
  6. Local consent (optional): follow the PermissionStore sqlx pattern if your connector needs device-local grant tracking

The MacAutomationProposal.tsx renderer, permission_store.rs, and applescript.rs are not one-offs. They're templates. The four field names — command_id, tier, app_display_name, description — are the vocabulary every similar connector should reuse so the Companion inbox renders consistently.

What this unlocks

Before this pattern existed, any agent that needed to interact with native macOS apps had two choices: ship a separate Mac-specific binary, or require the user to run a local API server. Neither integrates with HumanOS governance.

With the connector/muscle split and the companion_integration model, a market of community catalog entries can grow on top of a single, governed execution path. A developer publishes a Things 3 entry. Another publishes BBEdit. A third publishes Logic Pro session management. None of them need to write governance code — the muscle, the HITL gate, and the provenance trail are already there. They just write JXA.

That's what a reference implementation is for.