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.

Agent Guidelines

  • Drive Rekor through the rekor CLI when you have shell access. If you also have mcp__rekor__ tools in your toolset, prefer the CLI for setup and configuration; reserve MCP tools for production read/write operations.
  • Only provide information from this skill, tool descriptions, or reference documentation. Do not invent URLs, paths, commands, or flags.
  • Schema work (collections, hooks, triggers, MCP Factory endpoints) only happens in preview workspaces. Always create or use a preview before changing schemas.
  • Promotion is human-only. When schema is ready, surface the exact rekor workspaces promote command and wait for the user to run it.
  • Tokens are shown only once on creation. Always tell the user to copy and store it before doing anything else.
  • Never auto-commit. Show the user git diff (when working with schema files) and wait for approval.

---

First-Time Setup Walkthrough

When the user is starting from scratch, walk them through these steps. Skip any that are already done — check with rekor workspaces list before assuming.

1. Install the CLI

npm install -g rekor-cli

Verify with rekor --version. The CLI is published to npm as rekor-cli; the binary is rekor.

2. Authenticate

If the user has a Rekor account:

rekor login

Opens a browser to complete OAuth. For headless or CI use, pass an existing API key:

rekor login --token rec_xxx

If the user does not have an account yet, direct them to [rekor.pro](https://rekor.pro) — free plan includes 2,000 operations per month, no credit card required.

3. Create a workspace

Workspaces are top-level data containers. One per app, domain, or tenant.

rekor workspaces create <id> --name "<Display Name>" [--tags <comma-separated>]

Set REKOR_WORKSPACE=<id> in the user's shell to avoid passing --workspace on every command.

4. Create a preview environment

Schema changes (collections, hooks, triggers, MCP Factory endpoints) are blocked in production workspaces. Create a preview to do schema work:

rekor workspaces create-preview <id> --name "<preview-slug>"

The resulting preview workspace ID is <id>--<preview-slug>. Use that as --workspace for all schema commands.

5. Define the first collection

A collection is a JSON Schema that defines a record type. Define it in the preview workspace:

rekor collections upsert <slug> --workspace <id>--<preview-slug> \

--name "<Display Name>" \

--schema '{"type":"object","properties":{...},"required":[...]}'

For schemas longer than a line, write them to a file and pass --schema @path/to/schema.json.

6. Test in preview, then ask the user to promote

Write some test records to the preview, query them, iterate until the schema is right:

rekor records upsert <slug> --workspace <id>--<preview-slug> --data '{...}'

rekor sql "SELECT FROM records FINAL WHERE workspace_id = {workspace_id:String} AND collection = '<slug>' AND deleted = false" --workspace <id>--<preview-slug>

When ready, surface the promotion command for the user to run (you cannot promote yourself):

rekor workspaces promote <id> --from <id>--<preview-slug>

Recommend --dry-run first to preview the diff.

7. Connect production agents

Two ways to give production agents access:

Scoped API token — for direct REST/CLI access:
rekor tokens create --name "<agent-name>" \

--grants '[{"scope":{"workspaces":["<id>"],"environments":["production"]},"permissions":["read:records","write:records"]}]'

The raw token (rec_...) is shown once. Copy it immediately.

MCP Factory endpoint — for purpose-built MCP tools per agent (recommended for LLM agents):

See the [MCP Factory](#mcp-factory-custom-mcp-endpoints) section below.

---

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 writes — single-record reads (records get, relationships get) reflect writes immediately; sql and query-relationships may take a moment to catch up. 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