# Company OS Connectors, Sessions, and Triggers

This document describes the first managed integration-platform layer added on top of the existing Company OS connector control plane.

## Why this exists

Before this slice, Company OS already had:

- connector templates,
- credential storage,
- connector records,
- OpenAPI/MCP tool-source ingestion,
- partial OAuth state handling,
- connector operation run records.

What it did **not** have was the product layer that ties those pieces together for real agent operations:

- linked accounts,
- connector sessions,
- trigger subscriptions,
- account-aware connector discovery.

## New surfaces

### Connector catalog

`GET /api/company/companies/:company_id/connectors/catalog`

Returns:

- built-in connector templates,
- configured connector counts by provider,
- linked-account counts by provider,
- tool-catalog counts by provider,
- active session and trigger counts.

Use this as the Company OS “integration marketplace” summary surface.

### Linked connector accounts

`GET /api/company/companies/:company_id/connector-accounts`

`PUT /api/company/companies/:company_id/connector-accounts`

Stores a company-scoped connected account record with:

- provider,
- account reference,
- optional connector key,
- optional user ref,
- optional credential provider key,
- scopes,
- auth state metadata,
- health/error fields.

This is the bridge between a configured connector and a real account the agent can act through.

### Connector sessions

`GET /api/company/companies/:company_id/connector-sessions`

`PUT /api/company/companies/:company_id/connector-sessions/:session_key`

Stores the operational session context for agent runs:

- linked accounts,
- preferred connectors,
- allowed toolkits,
- thread id,
- user ref,
- arbitrary context metadata,
- session status.

This is the per-run/per-user context surface missing from the earlier connector model.

### Trigger subscriptions

`GET /api/company/companies/:company_id/trigger-subscriptions`

`POST /api/company/companies/:company_id/trigger-subscriptions`

Stores trigger definitions with:

- connector/provider,
- account reference,
- event type,
- trigger kind (`webhook`, `poll`, `schedule`, `manual`),
- filters,
- action type/payload,
- optional target session key.

This is the durable routing layer needed for “when X happens, create or wake agent work”.

#### Trigger delivery (automation worker + HTTP)

Delivery is **fully wired** — not storage-only.

| Kind | How it fires |
|------|----------------|
| **`poll` / `schedule`** | Automation tick (~15s) in `hsm_console`; respects `filter_spec.interval_sec` (default 300, min 30). |
| **`webhook`** | `POST /api/company/webhooks/triggers/:subscription_id` with header `X-Company-OS-Trigger-Secret` matching `filter_spec.webhook_secret`. Optional JSON body is appended to the spawned task spec. **No Company OS API auth** — secret per subscription. |
| **`manual`** | `POST /api/company/companies/:company_id/trigger-subscriptions/:subscription_id/deliver` (authenticated). Optional `{ "event": { ... } }` in body. |

Supported **`action_type`**: `create_task` (`action_payload.title`, optional `specification`, `owner_persona`, `priority`).

Outcomes are logged to **`company_trigger_delivery_log`** and **`governance_events`** (`trigger_delivered` / `trigger_delivery_failed`).

Console: **Workspace → Connectors** panel lists subscriptions, delivery log, webhook URLs, and **Deliver now**.

### Account-aware connector discovery

`POST /api/company/companies/:company_id/connectors/discover`

Input can include:

- `query`,
- `session_key`,
- `user_ref`,
- `category`,
- `limit`.

The response ranks connector templates using:

- configured connectors,
- linked accounts,
- optional session allowlist,
- query/category relevance.

This is the first step from “tool schemas exist” toward “the platform can recommend the right integration for this task and session”.

### BaseLayer browser hosting

BaseLayer is now a first-class connector template:

- `key`: `baselayer_browser`
- `provider_key`: `baselayer`
- category: `browser`
- native runtime: `provider_api`

The template maps to [BaseLayer](https://github.com/Lasdw6/BaseLayer)'s provider `/v1` contract:

- `GET /v1/health`, `/v1/hosts`, `/v1/stats`, `/v1/sessions`
- `POST /v1/sessions`
- `GET /v1/sessions/:sessionId`
- `POST /v1/sessions/:sessionId/activity`
- `DELETE /v1/sessions/:sessionId`

Agent workers can call the native tool:

```json
{
  "tool": "baselayer_browser_session",
  "params": {
    "action": "create",
    "api_base": "http://127.0.0.1:3000/v1",
    "runtime_profile": "baselayer-firecracker-headless-shell",
    "region": "us-east-2",
    "idempotency_key": "company-run-123",
    "provider": {
      "upstreamProvider": "hsm-company-os",
      "workflowId": "agent-chat-smoke"
    }
  }
}
```

Use environment variables instead of prompt-visible secrets when possible:

- `HSM_BASELAYER_API_URL` or `BASELAYER_API_URL`
- `HSM_BASELAYER_API_KEY` or `BASELAYER_API_KEY`

If you expose BaseLayer beyond a trusted network, follow its public API safety gates:

- enable `/v1`-only public mode,
- enable provider API-key auth,
- keep provider API-key config out of Git,
- place the listener behind a firewall or reverse proxy.

Connector account responses intentionally redact token-shaped `auth_state` values. Store only safe routing metadata in `auth_state` when possible; prefer env/vault-backed API keys for worker execution.

## Schema additions

Migration: [`migrations/20260428143000__connector_sessions_and_triggers.sql`](../../migrations/20260428143000__connector_sessions_and_triggers.sql)

It adds:

- richer fields to `connector_accounts`,
- `company_connector_sessions`,
- `company_trigger_subscriptions`.

## Current limitations

- This is a control-plane/product-layer slice, not a full hosted SaaS integration marketplace.
- OAuth token exchange for Company OS connectors is still only partially wired; the repo already had appliance-style PKCE state machinery, but this slice does not finish provider-specific OAuth flows.
- Discovery is heuristic and template-based, not yet learned or telemetry-ranked.
- BaseLayer integration uses the provider API directly; it does not vendor BaseLayer's Docker/Firecracker host runtime into this repo.

## Related surfaces (same integration plane)

- **Executor bridge (Google MCP):** `GET /api/company/connectors/executor/status`, `connect-url`, `POST .../connectors/executor/sync` — maps Executor MCP tools → `connector_accounts` + tool catalog. See `src/company_os/executor_bridge.rs`.
- **Email operator queue:** `GET/POST .../email/operator-queue`, propose-reply, decision — human-in-the-loop outbound email. See `workspace_catalog.rs`.

## Next recommended steps

1. Connect Company OS connector accounts to the existing MCP PKCE/OAuth appliance flow.
2. Make connector discovery aware of actual tool schemas from `company_tool_catalog`.
3. Add `dispatch_worker` / agent-chat wakeup as additional trigger `action_type`s beyond `create_task`.
4. Promote `baselayer_browser_session` into `company_tool_catalog` seed data when tool-catalog seeding becomes the default for native tools.
