Rekor — Data Layer for AI Agents

You have access to the rekor CLI — the builder interface for Rekor. Use it to set up schemas, configure collections, test in preview environments, and promote to production. Production agents use MCP tools to read/write records; external systems integrate via REST API. The CLI is your tool for designing and managing the data model.

Setup

All commands require --workspace (or set REKOR_WORKSPACE env var). Start by listing or creating a workspace:

rekor workspaces list

rekor workspaces create my-workspace --name "My Workspace"

Core Concepts

  • Collection: A schema (JSON Schema) that defines a record type. No migrations — create at runtime.
  • Record: A JSON document conforming to a collection's schema.
  • Relationship: A typed, directed link between two records with optional metadata.

Quick Start

1. Create a collection

rekor collections upsert invoices --workspace my-ws \

--name "Invoices" \

--schema '{"type":"object","properties":{"customer":{"type":"string"},"amount":{"type":"number"},"status":{"type":"string","enum":["draft","issued","paid"]}},"required":["customer","amount"]}'

2. Create a record

rekor records upsert invoices --workspace my-ws \

--data '{"customer":"Acme Corp","amount":5000,"status":"draft"}'

With external ID for idempotent upsert:

rekor records upsert invoices --workspace my-ws \

--data '{"customer":"Acme Corp","amount":5000}' \

--external-id inv_123 --external-source billing

3. Query records

rekor sql "SELECT data.invoice_number.:String as num, data.status.:String as status, arraySum(CAST(data.line_items[].amount, 'Array(Float64)')) as total FROM records FINAL WHERE workspace_id = {workspace_id:String} AND collection = 'invoices' AND deleted = false ORDER BY total DESC" --workspace my-ws

4. Link records

rekor relationships upsert --workspace my-ws \

--source invoices/rec_abc --target customers/rec_xyz \

--type belongs_to

5. Traverse relationships

rekor query-relationships invoices rec_abc --workspace my-ws \

--type belongs_to --direction outgoing

---

Full Command Reference

Workspaces

rekor workspaces list [--tag <tag>]

rekor workspaces get <id>

rekor workspaces create <id> --name <name> [--description <desc>] [--tags <comma-separated>]

rekor workspaces tag <id> --tags <comma-separated>

rekor workspaces delete <id>

Tags let you group workspaces (e.g., client:acme,billing). Filter with --tag.

Collections

rekor collections list --workspace <ws>

rekor collections get <id> --workspace <ws>

rekor collections upsert <id> --workspace <ws> --name <name> --schema <json|@file>

rekor collections delete <id> --workspace <ws>

Records

rekor records upsert <collection> --workspace <ws> --data <json|@file> [--id <uuid>] [--external-id <id>] [--external-source <src>]

rekor records get <collection> <id> --workspace <ws>

rekor records delete <collection> <id> --workspace <ws>

SQL Query

Execute read-only SQL queries directly against workspace data. Supports filtering, aggregation, JOINs, CTEs, and array operations.

rekor sql "<query>" --workspace <ws> [--param key=value ...] [--file query.sql]
Tables: records, relationships, collections, workspaces, operations_log Important: Always include workspace_id = {workspace_id:String}, deleted = false, and FINAL after table names. Accessing JSON fields: Use data.field.:Type subcolumn syntax for the native JSON type. Use CAST(data.field, 'Type') when type-safe conversion is needed (e.g., integers stored as Int64 vs Float64). Examples:
# Simple query

rekor sql "SELECT data.invoice_number.:String as num, data.status.:String as status FROM records FINAL WHERE workspace_id = {workspace_id:String} AND collection = 'invoices' AND deleted = false" --workspace my-ws

Aggregation

rekor sql "SELECT data.status.:String as status, count() as cnt FROM records FINAL WHERE workspace_id = {workspace_id:String} AND collection = 'invoices' AND deleted = false GROUP BY status" --workspace my-ws

Array aggregation (sum embedded line items)

rekor sql "SELECT data.invoice_number.:String as num, arraySum(CAST(data.line_items[].amount, 'Array(Float64)')) as total FROM records FINAL WHERE workspace_id = {workspace_id:String} AND collection = 'invoices' AND deleted = false" --workspace my-ws

Explode array elements with ARRAY JOIN

rekor sql "SELECT item.description.:String as item, sum(CAST(item.amount, 'Float64')) as revenue FROM records FINAL ARRAY JOIN data.line_items[] as item WHERE workspace_id = {workspace_id:String} AND collection = 'invoices' AND deleted = false GROUP BY item ORDER BY revenue DESC" --workspace my-ws

CTE joining records with relationships

rekor sql "WITH inv AS (SELECT id, data.invoice_number.:String as num, arraySum(CAST(data.line_items[].amount, 'Array(Float64)')) as total FROM records FINAL WHERE workspace_id = {workspace_id:String} AND collection = 'invoices' AND deleted = false), pay AS (SELECT target_id, sum(CAST(data.allocated, 'Float64')) as paid FROM relationships FINAL WHERE workspace_id = {workspace_id:String} AND rel_type = 'payment_for' AND deleted = false GROUP BY target_id) SELECT inv.num, inv.total, coalesce(pay.paid, 0) as paid, inv.total - coalesce(pay.paid, 0) as balance FROM inv LEFT JOIN pay ON pay.target_id = inv.id ORDER BY balance DESC" --workspace my-ws

With parameters

rekor sql "SELECT FROM records FINAL WHERE workspace_id = {workspace_id:String} AND data.status.:String = {status:String} AND deleted = false" --workspace my-ws --param status=issued

Relationships

rekor relationships upsert --workspace <ws> --source <col/id> --target <col/id> --type <type> [--id <id>] [--data <json>]

rekor relationships get <id> --workspace <ws>

rekor relationships delete <id> --workspace <ws>

rekor query-relationships <collection> <id> --workspace <ws> [--type <type>] [--direction outgoing|incoming|both]

Hooks (inbound webhooks)

External systems push data into Rekor via hooks. Each hook provides a unique ingest URL.

rekor hooks create --workspace <ws> --name <name> --collection <collection>

rekor hooks list --workspace <ws>

rekor hooks get <id> --workspace <ws>

rekor hooks delete <id> --workspace <ws>

Hooks can only be created/deleted in preview workspaces. Promote to production when ready.

Triggers (outbound webhooks)

Triggers fire automatically when records change, notifying external systems via HTTP POST.

rekor triggers create --workspace <ws> --name <name> --collection <collection> --url <url> --events '["create","update","delete"]'

rekor triggers list --workspace <ws>

rekor triggers get <id> --workspace <ws>

rekor triggers delete <id> --workspace <ws>

Triggers are HMAC-signed (X-Rekor-Signature) and fire asynchronously. By default, writes from hooks don't re-fire triggers (skip_hook_writes: true). Triggers can only be created/deleted in preview workspaces.

Batch (atomic)

Execute up to 1,000 operations atomically — all succeed or all fail:

rekor batch --workspace <ws> --operations '[

{"type":"upsert_record","collection":"invoices","data":{"customer":"A","amount":100}},

{"type":"upsert_record","collection":"invoices","data":{"customer":"B","amount":200}},

{"type":"upsert_relationship","rel_type":"related_to","source_collection":"invoices","source_id":"id1","target_collection":"invoices","target_id":"id2"}

]'

Operation types: upsert_record, delete_record, upsert_relationship, delete_relationship, upsert_collection, delete_collection

Provider Adapters

Import tool definitions from any LLM provider as collections, or export collections as tool definitions.

Import (creates collections from tool definitions):
# OpenAI

rekor providers import openai --workspace <ws> --tools '[{"type":"function","function":{"name":"create_invoice","parameters":{"type":"object","properties":{"customer":{"type":"string"},"amount":{"type":"number"}},"required":["customer"]}}}]'

Anthropic

rekor providers import anthropic --workspace <ws> --tools '[{"name":"create_invoice","input_schema":{"type":"object","properties":{"customer":{"type":"string"}}}}]'

MCP

rekor providers import mcp --workspace <ws> --tools '[{"name":"create_invoice","inputSchema":{"type":"object","properties":{"customer":{"type":"string"}}}}]'

From file

rekor providers import openai --workspace <ws> --tools @tools.json

Export (get collections as tool definitions):
rekor providers export openai --workspace <ws>

rekor providers export anthropic --workspace <ws> --collections invoices,customers

rekor providers export mcp --workspace <ws> --output tools.json

Import tool call (create a record from provider-native format):
# OpenAI tool call → record

rekor providers import-call openai invoices --workspace <ws> \

--data '{"arguments":{"customer":"Acme","amount":5000}}' \

--external-id call_abc123 --external-source openai

Anthropic tool call → record

rekor providers import-call anthropic invoices --workspace <ws> \

--data '{"input":{"customer":"Acme","amount":5000}}'

Supported providers: openai, anthropic, google, mcp

MCP Factory (custom MCP endpoints)

Create purpose-built MCP servers from your workspace collections. Each endpoint serves domain-specific tools — agents see create_invoice, list_payments, not generic Rekor operations.

# Create a curated MCP endpoint

rekor endpoints upsert invoicing-agent --workspace my-ws \

--name "Invoicing Agent" \

--tool "invoices:get,list" \

--tool "payments:create,get,list" \

--relationship "invoice_payment:list" \

--batch "invoices:create,update" --batch "payments:create" --batch "invoice_payment:create" \

--sql-query

Get the MCP connection URL

rekor endpoints url invoicing-agent

→ https://mcp.rekor.pro/e/invoicing-agent/mcp

List all endpoints

rekor endpoints list --workspace my-ws

Get endpoint config (with resolved schemas)

rekor endpoints get invoicing-agent --workspace my-ws --resolved

Delete an endpoint

rekor endpoints delete invoicing-agent --workspace my-ws

Tool spec format: collection:op1,op2 (operations: create, get, list, update, delete) Relationship spec format: rel_type:op1,op2 (operations: create, list, delete) Batch spec format: collection_or_rel:op1,op2 Custom tool names and descriptions: Use --config with full JSON for advanced control:
rekor endpoints upsert invoicing-agent --workspace my-ws --config '{

"name": "Invoicing Agent",

"tools": [

{

"collection": "invoices",

"operations": ["get", "list"],

"name_override": "search_invoices",

"description_override": "Search invoices by customer, status, or date range"

},

{

"collection": "payments",

"operations": ["create", "get", "list"],

"description_override": "Manage payment records for invoices"

}

],

"relationships": [

{

"rel_type": "invoice_payment",

"operations": ["create", "list"],

"name_override": "assign_payment",

"description_override": "Link a payment to an invoice"

}

],

"sql_query": true

}'

Or from a file: --config @endpoint.json

Connect agents to the endpoint URL with a token scoped to exactly one workspace. The agent sees only the tools you configured — fully domain-specific, no Rekor concepts.

Endpoints can only be created/modified in preview workspaces. Promote to production when ready.

API Tokens

Create scoped tokens for agents, integrations, and CI/CD. Tokens can be restricted to specific workspaces, collections, environments, and permissions. Tokens are hashed before storage — the raw value is shown only once on creation.

# Create a full-access token

rekor tokens create --name "my-key" --grants '[{"scope":{"workspaces":[""]},"permissions":[""]}]'

Create a scoped token (read-only on one workspace)

rekor tokens create --name "client-a-reader" \

--grants '[{"scope":{"workspaces":["client-a"],"environments":["production"]},"permissions":["read:records","read:collections"]}]'

Create a token with expiration

rekor tokens create --name "temp-key" \

--grants '[{"scope":{"workspaces":[""]},"permissions":[""]}]' \

--expires-at 2026-12-31T23:59:59Z

List tokens (shows status, last_used_at, expires_at)

rekor tokens list

Revoke a token

rekor tokens revoke <token_id>

Permissions: read:records, write:records, read:collections, write:collections, read:relationships, write:relationships, read:attachments, write:attachments, read:hooks, write:hooks, read:triggers, write:triggers, read:endpoints, write:endpoints, read:workspaces, write:workspaces, or for all. Scope fields: workspaces (required), collections (optional — omit for all), environments (optional — production, preview, or omit for both).

Tokens enforce a privilege ceiling — you can only create tokens with equal or narrower scope than your own.

---

Output Format

Add --output json for machine-readable JSON output (default is table).

rekor records get invoices rec_abc --workspace my-ws --output json

Data Input

Any --data, --schema, --tools, or --operations flag accepts:

  • Inline JSON: '{"key":"value"}'
  • File reference: @path/to/file.json

Environments

Workspaces are either production or preview. As an agent, you can:

  • Read from any workspace (production or preview)
  • Write records and relationships to any workspace
  • Modify schemas (collections, triggers, hooks) only in preview workspaces

To modify schemas, create a preview workspace first:

rekor workspaces create-preview my-workspace --name "add-invoices"

Then work in the preview workspace:

rekor collections upsert invoices --workspace my-workspace--add-invoices \

--schema '{"type":"object","properties":{"amount":{"type":"number"}}}'

When you're done, ask a human operator to promote your changes:

# Human runs: rekor workspaces promote my-workspace --from my-workspace--add-invoices
Promotion is a human-only operation. You cannot promote directly. Always work in preview for schema changes.

Best Practices

  • Use external IDs for idempotent upserts — retry-safe, no duplicates.
  • One workspace per context — keeps data isolated (per test run, per agent, per environment).
  • Preview for schema changes — modify collections, triggers, hooks in a preview workspace. Ask a human to promote.
  • Batch for atomicity — when multiple writes must succeed or fail together.
  • Relationships over nested data — link records instead of embedding. Enables traversal and flexible queries.
  • Schema first — define the collection schema before writing records. Validation catches bad data early.
  • Query delay after writessql and query-relationships may take ~1-2s to reflect new writes. Single-record reads (records get, relationships get) are instant. If you need to query right after writing, wait briefly or use direct gets.
  • Set token expiration — use --expires-at for short-lived tokens. Revoke unused tokens promptly.
  • Save tokens immediately — the raw token is shown only once on creation. Store it securely before closing the terminal.

Skill — Rekor