# Open District — Agent Instructions

## Section Index

| # | Section | Anchor |
|---|---------|--------|
| 1 | [Product Summary](#product-summary) | `#product-summary` |
| 2 | [MCP Endpoint + Config](#mcp-endpoint--config) | `#mcp-endpoint--config` |
| 3 | [MCP Tools (10)](#mcp-tools) | `#mcp-tools` |
| 4 | [REST/API Endpoints](#restapi-endpoints) | `#restapi-endpoints` |
| 5 | [Connector Catalog](#connector-catalog) | `#connector-catalog` |
| 6 | [Event Store Facts](#event-store-facts) | `#event-store-facts` |
| 7 | [Audit/Governance Surface](#auditgovernance-surface) | `#auditgovernance-surface` |
| 8 | [Canonical Examples](#canonical-examples) | `#canonical-examples` |
| 9 | [Pricing + Signup](#pricing--signup) | `#pricing--signup` |

---

## Product Summary

Open District is data for AI that shows its work. It connects open source public data beside enterprise systems and personal context in one secure platform. Every fact has a source, every answer has citations, every action is audited. Includes: append-only event store (Postgres + ClickHouse mirror), 33 source connector templates (REST manifests, OAuth, webhooks, direct DB), federated SQL with read-only gate, semantic + lexical search (Qdrant, 1024-dim), entity graph with cited paths, pipeline engine (scheduled DAG jobs, sandboxed WASM UDFs), MCP server (10 tools), append-only audit log, SSO (OIDC), PASETO sessions, scoped API keys. Free forever. Sign up at https://opendistrict.org/#signup.

---

## MCP Endpoint + Config

- **URL:** `https://mcp.opendistrict.org/mcp`
- **Transport:** Streamable HTTP
- **Auth:** Bearer token via scoped API key issued in-app at `app.opendistrict.org`
- **Scopes:** `admin`, `api_keys`, `read`
- **Discovery:** well-known manifest at `https://opendistrict.org/.well-known/mcp-server`; hyperscaler integration guides under `/guides/` (AWS AgentCore Gateway target, Azure Foundry IQ knowledge source)

```json
{
  "mcpServers": {
    "opendistrict": {
      "url": "https://mcp.opendistrict.org/mcp",
      "headers": {
        "Authorization": "Bearer $OD_API_KEY"
      }
    }
  }
}
```

---

## MCP Tools

All tools require valid Bearer token. All reads are gated; all actions are audited.

### 1. `query`

Federated SQL query with read-only gate. Executes across connected sources without write side-effects.

```
query(sql: string, params?: Record<string, any>) -> { rows: any[], columns: string[], row_count: number, sources: string[], duration_ms: number }
```

| Param | Type | Required | Description |
|-------|------|----------|-------------|
| sql | string | yes | Read-only SQL statement |
| params | Record<string, any> | no | Parameterized query bindings |

### 2. `search`

Semantic + lexical search across indexed data. Hybrid retrieval with Qdrant (1024-dim embeddings) and lexical fallback.

```
search(q: string, filters?: { source?: string, entity_type?: string, date_from?: string, date_to?: string }, limit?: number) -> { results: SearchResult[], total: number }
```

| Param | Type | Required | Description |
|-------|------|----------|-------------|
| q | string | yes | Search query (natural language or keywords) |
| filters | object | no | Source, entity type, date range filters |
| limit | number | no | Max results (default 20) |

### 3. `schema`

Introspect available schemas, types, and table structures across connected sources.

```
schema(source?: string, table?: string) -> { schemas: SchemaDef[], tables?: TableDef[], columns?: ColumnDef[] }
```

| Param | Type | Required | Description |
|-------|------|----------|-------------|
| source | string | no | Scope to specific source |
| table | string | no | Scope to specific table |

### 4. `catalog`

Browse and search the connector catalog. Lists available source templates, their types, and sync status.

```
catalog(type?: string, category?: string, search?: string) -> { connectors: ConnectorTemplate[], count: number }
```

| Param | Type | Required | Description |
|-------|------|----------|-------------|
| type | string | no | Filter by connector type (rest, oauth, webhook, db) |
| category | string | no | Filter by category (public, enterprise, personal) |
| search | string | no | Search connector names and descriptions |

### 5. `topology`

Inspect the entity graph topology. Returns node/edge counts, entity types, and relationship summaries.

```
topology(entity_type?: string, depth?: number) -> { nodes: number, edges: number, types: EntityType[], relationships: RelationshipSummary[] }
```

| Param | Type | Required | Description |
|-------|------|----------|-------------|
| entity_type | string | no | Scope to specific entity type |
| depth | number | no | Traversal depth for relationship summary (default 1) |

### 6. `metrics`

Query platform usage and data freshness metrics. Tenant-scoped statistics on queries, syncs, and coverage.

```
metrics(scope?: "tenant"|"system", period?: string) -> { queries_total: number, syncs_total: number, sources_active: number, data_freshness: Record<string, string> }
```

| Param | Type | Required | Description |
|-------|------|----------|-------------|
| scope | enum | no | tenant (default) or system |
| period | string | no | Time period (e.g. "7d", "30d", default "7d") |

### 7. `entities`

Entity graph lookup with cited paths. Returns entities and their provenance chains.

```
entities(id?: string, type?: string, name?: string, depth?: number) -> { entities: Entity[], edges: Edge[], citations: Citation[] }
```

| Param | Type | Required | Description |
|-------|------|----------|-------------|
| id | string | no | Specific entity ID |
| type | string | no | Entity type filter |
| name | string | no | Fuzzy name match |
| depth | number | no | Graph traversal depth (default 1) |

### 8. `pipelines`

Manage scheduled DAG jobs. Inspect pipeline definitions, runs, and status.

```
pipelines(action: "list"|"get"|"trigger", id?: string) -> { pipelines?: Pipeline[], run?: PipelineRun, triggered?: boolean }
```

| Param | Type | Required | Description |
|-------|------|----------|-------------|
| action | enum | yes | list, get, or trigger |
| id | string | conditional | Pipeline ID (required for get/trigger) |

### 9. `events`

Query append-only event store. Temporal provenance on all facts.

```
events(filter?: { source?: string, entity_id?: string, event_type?: string, since?: string, until?: string }, cursor?: string, limit?: number) -> { events: Event[], next_cursor?: string }
```

| Param | Type | Required | Description |
|-------|------|----------|-------------|
| filter | object | no | Source, entity, type, time range |
| cursor | string | no | Pagination cursor |
| limit | number | no | Max events (default 50) |

### 10. `audit`

Query audit log entries. Every query and action is recorded.

```
audit(filter?: { actor?: string, action?: string, resource?: string, since?: string, until?: string }, cursor?: string, limit?: number) -> { entries: AuditEntry[], next_cursor?: string }
```

| Param | Type | Required | Description |
|-------|------|----------|-------------|
| filter | object | no | Actor, action, resource, time range |
| cursor | string | no | Pagination cursor |
| limit | number | no | Max entries (default 50) |

---

## REST/API Endpoints

| Method | URL | Auth | Description |
|--------|-----|------|-------------|
| GET | `https://app.opendistrict.org/api/health` | none | Service health (public) |
| POST | `https://mcp.opendistrict.org/mcp` | Bearer | MCP Streamable HTTP endpoint |
| GET | `https://app.opendistrict.org/login` | none | SSO/OIDC login redirect |
| POST | `https://app.opendistrict.org/api/keys` | Bearer (admin) | Issue scoped API key |
| DELETE | `https://app.opendistrict.org/api/keys/:id` | Bearer (admin) | Revoke API key |

---

## Connector Catalog

**Total:** 33 source connector templates

### By Type

| Type | Count | Description |
|------|-------|-------------|
| REST manifests | ~15 | Declarative JSON configs for REST APIs |
| OAuth | ~8 | OAuth 2.0 flows for SaaS platforms |
| Webhooks | ~5 | Inbound event receivers |
| Direct DB | ~5 | Postgres, Snowflake |

### By Category

| Category | Examples |
|----------|----------|
| PUBLIC | Government open data, regulatory filings, census, court records |
| ENTERPRISE | SaaS APIs, databases, internal tools, Jira, Snowflake |
| PERSONAL | Email, calendar, documents, notes |

### Public Datasets

Government portals, regulatory agencies, open data initiatives, geospatial datasets, legislative records, campaign finance, environmental monitoring, transportation, education statistics, health statistics, crime statistics, property records, business registries, patent databases, academic publications.

### Additional Connectors

U.S. Census, SEC EDGAR, court opinions, Jira, Snowflake, direct Postgres.

---

## Event Store Facts

- **Storage:** Append-only event store backed by Postgres
- **Analytics mirror:** ClickHouse for analytical queries over large event ranges
- **Immutability:** Events are never updated or deleted; corrections are new events referencing originals
- **Temporal provenance:** Every fact carries source timestamp, ingestion timestamp, and source reference
- **Audit integration:** Every query against the event store writes an audit log entry
- **Schema evolution:** Events carry schema version; readers handle backward-compatible evolution

---

## Audit/Governance Surface

| Control | Implementation |
|---------|---------------|
| Audit log | Append-only; every query, every action |
| Row-level security | Postgres RLS policies per tenant |
| Scoped API keys | Scopes: `admin`, `api_keys`, `read` |
| Read-only gate | Federated SQL rejects write statements |
| SSO | OIDC providers |
| Session tokens | PASETO (v4.public) |
| Human-approval workflow | Governed actions require explicit approval |
| Governed write-backs | Audited, approved writes to external systems |
| Standing subscriptions | Recurring data syncs with governance |

---

## Canonical Examples

Four canonical scenarios, mirrored 1:1 from the machine-readable manifest [examples.yaml](https://opendistrict.org/examples.yaml) (source of truth; also exposed as MCP `prompts/list` templates). Asks are verbatim.

### follow-the-money

- **Ask:** Which companies named in new federal rules donated to the committees overseeing them?
- **Chain:** `search(q="final rule" · Federal Register · last 90 days)` → `entities(name=…)` → `query(SELECT committee, amount FROM fec_contributions)`
- **Cited answer shape:** rule hits count + committee donation total, citing Federal Register FR citation and FEC itemized records.

### scan-the-courts

- **Ask:** Is anyone challenging the new broadband rule?
- **Chain:** `search(q="petition for review" · Court opinions · related <FR cite>)` → `query(SELECT docket, status, next_hearing)`
- **Cited answer shape:** case count, lead docket, hearing date — docket and order-list citations.

### meeting-brief

- **Ask:** What should I know before my 2pm?
- **Chain:** `calendar(event=next)` × `email(counterparty=… · last 30 days)` × `search(q=<counterparty> · all sources)`
- **Cited answer shape:** deal state from thread, regulatory risk from Federal Register hit, suggested ask.

### thesis-watch

- **Ask:** Flag anything that changes my thesis on Acme.
- **Chain:** standing watch (`pipelines`) → `events(filter.entity_id=… · since last review)`
- **Cited answer shape:** thesis factor at risk + primary-source notice citation.

---

## Pricing + Signup

- **Price:** Free forever
- **License:** AGPL-3.0-only (repo: lab/www, LICENSE file); public records keep their original source licenses
- **Sign up:** https://opendistrict.org/#signup
- **Email:** hello@opendistrict.org
- **Sign in:** https://app.opendistrict.org/login
- **API keys:** Issued per tenant in-app with explicit scopes
