Are you an LLM? Read llms.txt for a summary of the docs, or llms-full.txt for the full context.
Skip to content

Connections

Each connection is a directory in connections/ containing a spec, access rules, and optional documentation. Pre-built plugins come with everything maintained — you just provide credentials.

amodal connect slack          # install a plugin
amodal sync --from <url>      # sync from OpenAPI/GraphQL

Directory Structure

connections/my-api/
├── spec.json       ← API source, auth, entities, sync config
├── access.json     ← field restrictions, action tiers, row scoping
├── surface.md      ← (optional) endpoint documentation
├── entities.md     ← (optional) entity definitions
└── rules.md        ← (optional) business rules

spec.json

{
  "source": "My API",
  "baseUrl": "https://api.example.com",
  "format": "openapi",
  "auth": {
    "type": "bearer",
    "token": "env:MY_API_TOKEN",
    "header": "Authorization",
    "prefix": "Bearer "
  },
  "sync": {
    "auto": true,
    "frequency": "on_push",
    "notify_drift": true
  },
  "filter": {
    "tags": ["public"],
    "include_paths": ["/api/v2/**"],
    "exclude_paths": ["/api/v2/internal/**"]
  }
}
FieldDescription
sourceAPI name/label
baseUrlAPI base URL
format"openapi", "graphql", or "grpc"
auth.type"bearer", "api_key", "oauth2", "basic", "header"
syncAuto-sync settings and drift notification
filterInclude/exclude endpoints by tag or path glob

access.json

Controls what the agent can see and do:

{
  "endpoints": {
    "GET /api/deals/{id}": {
      "returns": ["Deal"],
      "confirm": false
    },
    "POST /api/deals": {
      "returns": ["Deal"],
      "confirm": true,
      "reason": "Creates a new deal",
      "thresholds": [
        { "field": "body.amount", "above": 10000, "escalate": "review" }
      ]
    },
    "DELETE /api/deals/{id}": {
      "returns": ["Deal"],
      "confirm": "never",
      "reason": "Deletion not allowed via agent"
    }
  },
  "fieldRestrictions": [
    {
      "entity": "Contact",
      "field": "ssn",
      "policy": "never_retrieve",
      "sensitivity": "pii_identifier",
      "reason": "PII — never exposed"
    },
    {
      "entity": "Contact",
      "field": "email",
      "policy": "retrieve_but_redact",
      "sensitivity": "pii_name"
    },
    {
      "entity": "Deal",
      "field": "internal_notes",
      "policy": "role_gated",
      "sensitivity": "internal",
      "allowedRoles": ["supervisor"]
    }
  ],
  "rowScoping": {
    "Deal": {
      "owner_id": {
        "type": "field_match",
        "userContextField": "userId",
        "label": "your deals"
      }
    }
  },
  "delegations": {
    "enabled": true,
    "maxDurationDays": 7,
    "escalateConfirm": true
  },
  "alternativeLookups": [
    {
      "restrictedField": "Contact.ssn",
      "alternativeEndpoint": "GET /api/contacts/{id}/verification-status",
      "description": "Use verification status instead of raw SSN"
    }
  ]
}

Action Tiers

TierBehavior
false / omittedAllow without confirmation
true / "confirm"Ask user for approval before executing
"review"Show the full plan before executing
"never"Block the operation entirely

Field Restriction Policies

PolicyEffect
never_retrieveField completely removed from API responses
retrieve_but_redactKept in data, replaced with [REDACTED] in output
role_gatedRemoved if user lacks allowedRoles, else redactable

Threshold Escalation

Endpoints can escalate their confirmation tier based on request parameters:

{ "field": "body.amount", "above": 10000, "escalate": "review" }

If body.amount > 10000, the tier escalates from confirm to review.

Drift Detection

amodal sync --check    # report drift without updating (CI-friendly)
amodal sync            # update local specs from remote

Available Plugins

See Plugins for 20+ pre-built connections.