Axis uses Supabase as its coordination persistence layer: a managed Postgres instance with row-level security, realtime subscriptions, and the server-side stored procedures that make job claiming and file locking safe under concurrent load. The hosted product at useaxis.dev runs on Supabase. If you are self-hosting the full Axis backend or contributing to the schema, this page covers the migration workflow, key tables, and operational rules.Documentation Index
Fetch the complete documentation index at: https://mintlify.com/virsanghavi/axis/llms.txt
Use this file to discover all available pages before exploring further.
What Supabase Provides
| Capability | How Axis Uses It |
|---|---|
| Postgres with RLS | Per-org isolation: every query is scoped to the calling user’s org without application-layer filtering |
| Atomic stored procedures (RPCs) | try_acquire_lock, claim_next_job, claim_specific_job — serialized at the database level so two agents racing cannot both win |
pgvector + full-text + trigram | Hybrid search index for search_codebase |
| Realtime publications | Live team board at useaxis.dev/team/board, pushed over Postgres Realtime |
| Auth | User identity and session management for the dashboard and OAuth flow |
Migration Chain
The numbered migration chain insupabase/migrations/ is the source of truth for the database schema. Migrations are named NNNN_description.sql and applied in filename order, starting from 0000.
Never apply supabase/schema.sql by hand. That file is a generated snapshot kept for reference only. It may be out of date relative to the latest migrations. The numbered chain is authoritative.
Applying Migrations
Local / Development
Production (CI)
Migrations are applied to production automatically..github/workflows/migrate.yml runs on any push to main that touches supabase/migrations/**:
| Secret | Purpose |
|---|---|
SUPABASE_ACCESS_TOKEN | Authenticates the Supabase CLI against the project |
SUPABASE_DB_URL | Direct database connection string for the production project |
db-migrate concurrency group with cancel-in-progress: false, so two migration runs can never overlap. supabase db push records applied migrations and skips ones it has already run, making re-runs and manual workflow_dispatch triggers safe.
The normal path is: write a migration → commit it → open a pull request → merge to main → CI applies it. Do not hand-apply a migration that is already in flight through this path.
Migration Rules
All migrations must follow these rules to be safe in production:Idempotent SQL only
Use
CREATE TABLE IF NOT EXISTS, DROP ... IF EXISTS, and equivalent guarded forms. Every migration must be safe to run twice.Guard cross-chain references
Some tables (
orgs, org_members, projects) were created outside the numbered chain. Migrations that reference them must wrap the reference in to_regclass checks so the migration applies cleanly to both a bare database built from 0001 upward and to production as it actually exists. See the header comment of 0011_inference_guardrails.sql for the pattern.Key Tables
These tables are created and managed by the numbered migration chain:| Table | Purpose |
|---|---|
projects | One row per project; scoped to an org |
jobs | The job board: title, status, priority, dependencies, owner |
locks | Active file locks: path, agent, intent, content hash, expiry |
lock_events | Audit log of every lock grant, release, and force-unlock |
sessions | Per-agent MCP sessions and their transcript archives |
api_keys | Bearer tokens for authenticated API and MCP access |
profiles | User accounts linked to Supabase Auth |
orgs | Org records: name, billing status, seat count |
org_members | Membership join table: org ↔ profile ↔ role |
Atomic RPCs
Atomicity for the two operations that are unsafe under concurrent access lives entirely server-side:| RPC | What it does |
|---|---|
try_acquire_lock | Grants a file lock or returns the current holder; uses SELECT ... FOR UPDATE to prevent two agents from both receiving GRANTED |
claim_next_job | Atomically claims the next available unblocked job using SELECT ... FOR UPDATE SKIP LOCKED, ensuring two agents racing the queue cannot both win |
claim_specific_job | Atomically claims a job by ID with the same locking semantics |
/api/v1 layer and directly in direct Supabase mode (dev).
Embeddings and Search
The search infrastructure is built across several migrations:| Migration | What it adds |
|---|---|
0004 | pgvector extension; full-text and trigram indexes on content columns |
0005 | Hybrid search RPC: fuses vector similarity, full-text rank, and trigram similarity into a single ranked result set |
0007 | Co-change neighbors: tracks which files historically change together, powering the related files feature in search_codebase |
Realtime
Migration0013 adds a Realtime publication for the tables that back the live team board:
Direct Supabase Mode (Development)
In development, you can skip the hosted API layer and have the local MCP server talk directly to Supabase using the same RPCs:AXIS_API_KEY is not set, the server uses direct Supabase mode. The same try_acquire_lock, claim_next_job, and claim_specific_job RPCs are called directly. This mode is for development and testing only — the hosted API layer handles auth, rate limiting, and org scoping in production.