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 gives the runtime enough structure to make API calls and gives the model enough context to choose the right calls. Define local connections in amodal/connections/, then commit and deploy the repo.

Directory Structure

amodal/connections/my-api/
├── spec.json       ← protocol, base URL, auth, health check
├── policy.json     ← endpoint permissions, confirmations, field restrictions
├── surface.md      ← endpoint capabilities and model-facing usage notes
├── entities.md     ← (optional) entity definitions
└── rules.md        ← (optional) business rules

For a local REST connection, spec.json and surface.md are the important files:

  • spec.json is the machine contract. The runtime uses it to build ctx.request() and the request tool.
  • surface.md is the model contract. It tells the LLM which endpoints exist and when to use them.
  • policy.json is optional for simple APIs. When present, it tightens permissions, confirmation behavior, and field restrictions.
  • entities.md and rules.md are optional context for complex APIs.

Installed packages can provide all of these files. A local amodal/connections/<name>/surface.md, policy.json, entities.md, or rules.md can customize a packaged connection while continuing to use the package's spec.json.

Installed Packages

Runtime content packages are declared in amodal.json#packages:

{
  "packages": ["@amodalai/connection-typefully", "@amodalai/connection-devto"]
}

The packages array is the source of truth for package content. Do not use dependencies in amodal.json to load agent packages.

spec.json

Connections support two protocols: REST (the default) for HTTP APIs, and MCP for Model Context Protocol tool servers.

REST Connection

{
  "baseUrl": "https://api.example.com",
  "specUrl": "https://api.example.com/openapi.json",
  "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/**"]
  }
}

For a public, no-auth API, omit the auth block entirely — there is no "none" auth type. The minimal REST connection is just a baseUrl:

{
  "baseUrl": "https://api.adviceslip.com",
  "format": "rest"
}

MCP Connection

{
  "protocol": "mcp",
  "transport": "stdio",
  "command": "uvx",
  "args": ["mcp-server-github"],
  "env": { "GITHUB_TOKEN": "env:GITHUB_TOKEN" }
}

MCP connections do not require policy.json, baseUrl, or format. See MCP Servers for full details on transports and configuration.

Fields

FieldDescription
protocol"rest" (default) or "mcp"
baseUrlAPI base URL (required for REST)
specUrlURL to the API spec document (optional)
testPathRelative path appended to baseUrl for validate health checks (optional, e.g. "/me")
format"openapi", "graphql", "grpc", "rest", or "aws-api" (REST only)
auth.type"bearer", "api_key", "oauth2", "basic", "header" (REST only)
syncAuto-sync settings and drift notification (REST only)
filterInclude/exclude endpoints by tag or path glob (REST only)
transport"stdio", "sse", or "http" (MCP only)
commandCommand to spawn (MCP stdio only)
argsCommand arguments (MCP stdio only)
envEnvironment variables (MCP stdio only)
urlServer URL (MCP sse/http only)
headersHTTP headers, e.g. for auth (MCP sse/http only)
trustTrust unsigned responses (MCP http only)
contextInjectionInject scope context values into API requests (see below)

Context Injection

When embedding an agent in a multi-tenant app, you need API calls to include tenant-specific identifiers (user ID, org ID, workspace ID, etc.) so the downstream API returns only that tenant's data. contextInjection automates this — the runtime reads values from the scope context (passed with the chat request) and injects them into every API call to this connection.

{
  "baseUrl": "https://api.example.com",
  "auth": {
    "type": "bearer",
    "token": "env:API_TOKEN"
  },
  "contextInjection": {
    "tenant_id": {
      "in": "header",
      "field": "X-Tenant-Id",
      "required": true
    },
    "org_id": {
      "in": "query",
      "field": "org_id"
    }
  }
}

Each key in contextInjection maps to a key in the scope context object. When the agent makes a request to this connection, the runtime looks up that key in the context and injects the value.

FieldDescription
inWhere to inject: "header", "query", "path", or "body"
fieldThe header name, query param name, path placeholder, or body field name
requiredIf true, requests fail with an error when the key is missing from scope context. Defaults to false (silently skipped).
Injection targets:
  • header — adds field: value to request headers (e.g., X-Tenant-Id: abc123)
  • query — appends field=value to the URL query string
  • path — replaces {field} in the endpoint URL (e.g., /tenants/{tenant_id}/data)
  • body — adds field: value to the JSON request body (POST/PUT/PATCH only)

How context is passed: The embedding app includes a context object in the chat request body alongside scope_id:

{
  "message": "What are my recent orders?",
  "scope_id": "user-123",
  "context": {
    "tenant_id": "tenant-abc",
    "org_id": "org-456"
  }
}

See Scope for full details on multi-tenant configuration.

policy.json

Controls what the agent can see and do:

{
  "endpoints": {
    "GET /tickets/{id}": {
      "returns": ["Ticket"]
    },
    "POST /tickets/{id}/comments": {
      "returns": ["Ticket"],
      "confirm": true,
      "reason": "Adds a visible support-ticket comment"
    },
    "DELETE /tickets/{id}": {
      "returns": ["Ticket"],
      "confirm": "never",
      "reason": "Ticket deletion is not allowed through the agent"
    }
  },
  "fieldRestrictions": [
    {
      "entity": "Customer",
      "field": "payment_token",
      "policy": "never_retrieve",
      "sensitivity": "secret",
      "reason": "Payment tokens are never exposed to the agent"
    },
    {
      "entity": "Customer",
      "field": "email",
      "policy": "retrieve_but_redact",
      "sensitivity": "pii_name"
    },
    {
      "entity": "Ticket",
      "field": "internal_notes",
      "policy": "role_gated",
      "sensitivity": "internal",
      "allowedRoles": ["supervisor"]
    }
  ],
  "rowScoping": {
    "Ticket": {
      "tenant_id": {
        "type": "field_match",
        "userContextField": "tenantId",
        "label": "your tenant's tickets"
      }
    }
  },
  "delegations": {
    "enabled": true,
    "maxDurationDays": 7,
    "escalateConfirm": true
  },
  "alternativeLookups": [
    {
      "restrictedField": "Customer.payment_token",
      "alternativeEndpoint": "GET /customers/{id}/billing-status",
      "description": "Use billing status instead of raw payment credentials"
    }
  ]
}

Omit confirm for read endpoints. For connection policies, confirm accepts only true, "review", or "never"; false is not valid.

Action Tiers

TierBehavior
omittedAllow without confirmation
trueAsk user for approval before executing
"review"Show the full plan before executing
"never"Block the operation entirely

These tiers are one surface of the platform-wide confirmation model; Confirmation Model maps them to custom-tool exposure kinds and the request tool's intent handshake.

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

Use your source-control and CI workflow to review connection spec changes before deploying them.

Packaged Connections

Connection packages can provide reusable specs, policies, and model-facing docs. Declare packaged content in amodal.json#packages, then override specific docs locally when your agent needs project-specific guidance.