Skip to main content

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.

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.

What Supabase Provides

CapabilityHow Axis Uses It
Postgres with RLSPer-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 + trigramHybrid search index for search_codebase
Realtime publicationsLive team board at useaxis.dev/team/board, pushed over Postgres Realtime
AuthUser identity and session management for the dashboard and OAuth flow

Migration Chain

The numbered migration chain in supabase/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.
Most migration files are gitignored by default. Before committing a new migration, run git check-ignore -q supabase/migrations/<file>.sql and add it to the .gitignore allowlist if needed. A gitignored migration will never reach production.Check all migration files before trusting the pipeline:
cd axis
for f in supabase/migrations/*.sql; do
  printf '%s: ' "$(basename "$f")"; git check-ignore -q "$f" && echo IGNORED || echo visible
done
Anything that prints IGNORED will not be deployed by CI. Add it to the .gitignore allowlist explicitly.

Applying Migrations

Local / Development

supabase db reset
Docker is required. This command rebuilds the local database from scratch by replaying every numbered migration in order. Use it when setting up a fresh local environment or testing a new migration before committing.

Production (CI)

Migrations are applied to production automatically. .github/workflows/migrate.yml runs on any push to main that touches supabase/migrations/**:
supabase db push --db-url "$SUPABASE_DB_URL" --include-all
Two Actions secrets are required:
SecretPurpose
SUPABASE_ACCESS_TOKENAuthenticates the Supabase CLI against the project
SUPABASE_DB_URLDirect database connection string for the production project
The job runs under a 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:
1

Idempotent SQL only

Use CREATE TABLE IF NOT EXISTS, DROP ... IF EXISTS, and equivalent guarded forms. Every migration must be safe to run twice.
2

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.
3

Test on a branch or local database first

Apply the migration to a local stack or branch database before merging to main. The CI migration is not a test environment — a bad migration reaches production immediately on merge.

Key Tables

These tables are created and managed by the numbered migration chain:
TablePurpose
projectsOne row per project; scoped to an org
jobsThe job board: title, status, priority, dependencies, owner
locksActive file locks: path, agent, intent, content hash, expiry
lock_eventsAudit log of every lock grant, release, and force-unlock
sessionsPer-agent MCP sessions and their transcript archives
api_keysBearer tokens for authenticated API and MCP access
profilesUser accounts linked to Supabase Auth
orgsOrg records: name, billing status, seat count
org_membersMembership join table: org ↔ profile ↔ role

Atomic RPCs

Atomicity for the two operations that are unsafe under concurrent access lives entirely server-side:
RPCWhat it does
try_acquire_lockGrants a file lock or returns the current holder; uses SELECT ... FOR UPDATE to prevent two agents from both receiving GRANTED
claim_next_jobAtomically claims the next available unblocked job using SELECT ... FOR UPDATE SKIP LOCKED, ensuring two agents racing the queue cannot both win
claim_specific_jobAtomically claims a job by ID with the same locking semantics
These RPCs are called both from the hosted /api/v1 layer and directly in direct Supabase mode (dev). The search infrastructure is built across several migrations:
MigrationWhat it adds
0004pgvector extension; full-text and trigram indexes on content columns
0005Hybrid search RPC: fuses vector similarity, full-text rank, and trigram similarity into a single ranked result set
0007Co-change neighbors: tracks which files historically change together, powering the related files feature in search_codebase

Realtime

Migration 0013 adds a Realtime publication for the tables that back the live team board:
-- the migration enables realtime for jobs, locks, and sessions
ALTER PUBLICATION supabase_realtime ADD TABLE jobs, locks, sessions;
The team board at useaxis.dev/team/board subscribes to these changes and updates in real time as agents claim jobs and take locks.

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:
NEXT_PUBLIC_SUPABASE_URL=https://your-project.supabase.co
SUPABASE_SERVICE_ROLE_KEY=your-service-role-key
When both variables are set and 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.

Build docs developers (and LLMs) love