Zenbu

Documentation
Login

Documentation


title: Zenbu connectors status: canonical audience:

Zenbu connectors wiki

This is the single source of truth for the connector service. Humans use it for setup and operations. AI agents use it to understand tool semantics, retrieval order, context normalization, and mutation safety.

Mental model

The connector service does not directly "give Gmail to an AI." It provides authenticated tools for discovering accounts, searching lightweight resource references, hydrating selected resources, and performing controlled writes.

The core AI loop is:

discover account -> search/list -> select IDs -> hydrate -> normalize
-> rank and bound context -> invoke model -> cite source IDs

A Gmail list response containing only id and threadId is a candidate list, not useful prompt context. The orchestrator must fetch selected messages before asking the model to reason about them.

Quick start

cp connectors/.config.development connectors/.config
# Fill in local values. The real file is Mercurial-ignored.

bazel test //connectors:connector_tests
bazel run //connectors:connector_server

The service defaults to connectors/.config. Override it with an explicit first argument or CONNECTOR_CONFIG_PATH.

bazel run //connectors:connector_server -- /absolute/path/to/config
CONNECTOR_CONFIG_PATH=/absolute/path/to/config \
  bazel run //connectors:connector_server

With mrjunejune running on port 6969 and connectors on 6981:

  1. Log in at http://127.0.0.1:6969/login.
  2. Open http://127.0.0.1:6981/auth-test.html.
  3. Check the Zenbu session.
  4. Connect Google or select an existing account.
  5. Exercise Drive and Gmail reads/writes from the test console.

Configuration

Canonical keys:

Key Purpose
DATABASE Connector SQLite database
AUTH_DATABASE Existing Zenbu auth SQLite database
AUTH_COOKIE_SECRET Same hex secret used by mrjunejune
AUTH_SESSION_IDLE_TTL Session idle extension in seconds
SERVER_HOST Bind address; local default is 127.0.0.1
SERVER_PORT Connector port; local default is 6981
STATIC_DIR Optional Seobeo static directory
GOOGLE_CLIENT_ID Google OAuth web client ID
GOOGLE_CLIENT_SECRET Google OAuth client secret
GOOGLE_REDIRECT_URI Exact registered callback URI
MASTER_KEY_VERSION Credential-encryption key version
MASTER_KEY_BASE64URL Unpadded base64url encoding of 32 random bytes

Generate a connector master key:

openssl rand 32 | openssl base64 -A | tr '+/' '-_' | tr -d '='

Lowercase legacy aliases remain accepted, but new configuration should use the uppercase names above.

Authentication and OAuth

Local Google OAuth redirect:

http://127.0.0.1:6981/v1/oauth/google/callback

Google Cloud testing-mode apps must list the Google account under Google Auth Platform -> Audience -> Test users.

Tool discovery

GET /v1/ai/tools is the runtime machine-readable manifest. An orchestrator should fetch or version this contract rather than infer tool semantics from URL names.

GET /v1/accounts returns safe connection summaries:

{
  "accounts": [
    {
      "accountId": "google:116932985844341173188",
      "provider": "google",
      "email": "[email protected]",
      "expiresAt": 1787020000,
      "scopes": "..."
    }
  ]
}

The authenticated user is always derived from the Zenbu session. A model must not supply or override a Zenbu owner ID.

Gmail retrieval

Search or list candidates

GET /v1/accounts/{account_id}/gmail/messages
    ?q=from:[email protected] newer_than:30d
    &maxResults=10

Useful Gmail search examples:

from:[email protected] newer_than:30d
subject:(quarterly planning) has:attachment
in:sent to:[email protected]

The result:

{"messages":[{"id":"abc","threadId":"abc"}]}

means only that message abc is a candidate.

Hydrate selected messages

Metadata-only:

GET /v1/accounts/{account_id}/gmail/messages/abc?format=metadata

Full message:

GET /v1/accounts/{account_id}/gmail/messages/abc?format=full

The orchestrator should:

  1. Extract Subject, From, To, and Date.
  2. Decode Gmail base64url body data.
  3. Prefer text/plain; convert HTML to text only when needed.
  4. Remove irrelevant quoted history and signatures.
  5. Cap each message and the total retrieved context.
  6. Preserve message.id and threadId for citations and follow-up calls.

Attachments are explicit:

GET /v1/accounts/{account_id}/gmail/messages/{message_id}/attachments/{attachment_id}

Do not silently ingest every attachment.

Drive retrieval

Search candidates with Drive query syntax and narrow fields:

GET /v1/accounts/{account_id}/drive/files
    ?q=name contains 'roadmap' and trashed = false
    &pageSize=10
    &fields=files(id,name,mimeType,modifiedTime,description,webViewLink),nextPageToken

Fetch metadata for a selected file:

GET /v1/accounts/{account_id}/drive/files/{file_id}
    ?fields=id,name,mimeType,modifiedTime,description,webViewLink

Fetch bytes for a stored file:

GET /v1/accounts/{account_id}/drive/files/{file_id}/download

Native Google Docs require export rather than ordinary download. A dedicated Workspace export helper is still needed before an AI can reliably ingest every Google-native document type.

Normalized AI context

Provider payloads should be converted to a common record before model use:

{
  "source": "gmail",
  "accountId": "google:...",
  "resourceId": "abc",
  "title": "Quarterly planning",
  "author": "[email protected]",
  "timestamp": "2026-08-17T18:00:00Z",
  "text": "Cleaned and bounded source text",
  "url": null,
  "metadata": {
    "threadId": "abc",
    "mimeType": "text/plain"
  }
}

Context rules:

Writes and confirmation

Allowed writes:

Explicitly rejected:

All writes require:

Gmail send and Drive overwrite default to confirmation. The first request returns:

{
  "error": "confirmation_required",
  "request_digest": "..."
}

Create a one-time confirmation:

POST /v1/confirmations
{"request_digest":"..."}

Retry the identical mutation and idempotency key with X-Connector-Confirmation. Prefer draft creation over immediate send.

Per-user confirmation policy:

GET /v1/settings/confirmations/gmail.send
PUT /v1/settings/confirmations/gmail.send
{"policy":"always"}

Supported actions are gmail.send and drive.overwrite.

Route catalog

Concern Routes
Health and tools GET /health, GET /v1/ai/tools
Auth and accounts GET /v1/auth/session, GET /v1/accounts
OAuth POST /v1/oauth/google/start, GET /v1/oauth/google/callback
Disconnect DELETE /v1/accounts/:account_id
Confirmation POST /v1/confirmations, GET/PUT /v1/settings/confirmations/:action
Drive /v1/accounts/:account_id/drive/...
Gmail /v1/accounts/:account_id/gmail/...

Architecture

Bazel target Responsibility
//connectors:connector_core Crypto, PKCE, encoding, canonical digests
//connectors:connector_store Deita/SQLite persistence and policy
//connectors:google_provider Google HTTP transport and provider mapping
//connectors:connector_service_lib Seobeo routes and test console
//connectors:connector_auth_http Shared Zenbu session/CSRF adapter
//connectors:connector_tests Store, provider, auth, and route tests

Seobeo handles inbound and outbound HTTP. Deita owns SQLite access. Dowa arenas own request-scoped allocations.

Operational and security invariants

Documentation maintenance

This page is canonical. Update it whenever routes, configuration, security rules, or AI retrieval behavior change.

Only split a topic into another wiki/ page when this page becomes difficult to navigate. Any split page must be linked from this index, state its scope, and avoid duplicating normative rules.