Documentation Index
Fetch the complete documentation index at: https://docs.automagik.dev/llms.txt
Use this file to discover all available pages before exploring further.
PostgreSQL (pgserve)
Genie embeds pgserve as a persistent database. One PostgreSQL instance runs per machine on port 19642, auto-started on demand. The connection is a lazy singleton — pgserve only starts when something actually needs the database.
Genie requires pgserve >=1.1.10 (bumped 2026-04-20).
How pgserve Works
CLI command needs DB → getConnection() → is port 19642 listening?
│
┌─────────┴──────────┐
│ Yes │ No
│ Return cached │ Start pgserve
│ connection │ Run migrations
│ │ Return connection
└─────────────────────┘
Connection Details
| Setting | Value |
|---|
| Default port | 19642 |
| Host | 127.0.0.1 |
| Database name | genie |
| Data directory | ~/.genie/data/pgserve/ |
| Port lockfile | ~/.genie/pgserve.port |
| Migration marker | ~/.genie/pgserve.migrated |
Crash Recovery
On startup, killOrphanedPostgres() reads postmaster.pid from the data directory, verifies the PID is actually a postgres process (not a reused PID), then sends SIGTERM with a 5-second grace period before escalating to SIGKILL.
Schema Overview
The database schema is organized across 10 migration files covering core scheduling, task lifecycle, projects, state management, observability, boards, and an app registry.
Migration 001: Core Schema
Seven tables for the scheduler and observability (see Scheduler Architecture for how these tables drive the daemon loop):
| Table | Purpose |
|---|
schedules | Cron-like schedule definitions with status (active/paused/deleted) |
triggers | Individual fire instances with lease-based claiming |
runs | Execution attempts with trace IDs and exit codes |
heartbeats | Worker liveness tracking (alive/idle/busy/dead) |
audit_events | Immutable log of all state transitions |
agent_checkpoints | Session resume state (wish, group, phase, context) |
machine_snapshots | Machine state snapshots (agents, teams, CPU, memory) |
Migration 002: Task Lifecycle
Eleven tables for the full task management system:
| Table | Purpose |
|---|
task_types | Dynamic pipeline definitions (e.g., “Software Development” with 7 stages) |
tasks | Unified work entity — human and agent tasks with priority, timeline, blocking |
task_actors | Polymorphic assignment (local, genie_os_user, omni_agent) |
task_dependencies | Edges between tasks (depends_on, blocks, relates_to) |
task_stage_log | Audit trail for stage transitions with run traceability |
conversations | Chat containers (DM or group) linked to entities |
conversation_members | Membership-based permissions |
messages | All messages across all conversations |
tags | Classification labels with colors |
task_tags | Join table for task-tag relationships |
notification_preferences | Per-actor channel config (WhatsApp, Slack, email, etc.) |
Migration 003: Projects
Project-level scoping for multi-repo task management. Adds the projects table with tasks.project_id foreign key.
Migration 004: Cleanup
Removes test pollution from production tables — deletes tasks with /tmp/* repo paths and messages with test* sender IDs. Cleans up orphaned test schemas.
Migration 005: PG State (replaces JSON files)
Five tables that replace the legacy JSON file-based state:
| Table | Replaces | Purpose |
|---|
agents | ~/.genie/workers.json | Agent registry with lifecycle state, tmux pane info, provider metadata |
agent_templates | — | Reusable agent definitions with role, launcher, prompt |
teams | ~/.genie/teams/*.json | Team configs with repo, branch, members, status |
mailbox | .genie/mailbox/*.json | Durable message queue with delivery tracking |
team_chat | .genie/chat/*.jsonl | Team group chat messages |
Migration 006: Schema Reconciliation
Fixes schema drift between seed-created tables and migration-created tables for the agents and agent_templates tables.
Migration 007: Observability
Two tables for full session observability:
| Table | Purpose |
|---|
sessions | Session metadata — ID, agent, start/end time, project |
session_content | Complementary content — assistant text, tool I/O |
OTel structured events (cost, tokens, tool success/fail) flow into the existing audit_events table.
Migration 007b: Mailbox/Team Chat Reconciliation
Fixes production schema drift where 005_pg_state was recorded as applied but partially failed. Ensures mailbox and team_chat tables exist with correct schemas.
Migration 008: Boards
Two tables replacing task_types as the primary pipeline mechanism:
| Table | Purpose |
|---|
boards | Project-scoped boards with flexible columns, gates, and actions |
board_templates | Reusable board blueprints (builtin + custom) |
Boards are more flexible than task types — each column can have its own gate type (human, agent, human+agent) and an associated action skill.
Migration 009: App Store
Unified item registry for the Genie ecosystem:
| Table | Purpose |
|---|
app_store | Central registry — agents, skills, apps, boards, workflows, stacks, templates, hooks |
installed_apps | Per-machine installation records |
app_versions | Version history for each registry item |
Built-in Task Pipeline
The software task type defines a 7-stage pipeline that maps to Genie skills:
draft → brainstorm → wish → build → review → qa → ship
/brainstorm /wish /work /review /qa
Each stage has a gate type (human, agent, or human+agent) that determines whether the stage can auto-advance:
| Stage | Gate | Auto-advance | Skill |
|---|
| Draft | human | No | — |
| Brainstorm | human+agent | No | /brainstorm |
| Wish | human | No | /wish |
| Build | agent | Yes | /work |
| Review | human | No | /review |
| QA | agent | Yes | /qa |
| Ship | human | No | — |
LISTEN/NOTIFY
PostgreSQL’s LISTEN/NOTIFY mechanism provides real-time event streaming without polling:
| Channel | Fires When | Payload |
|---|
genie_trigger_due | New pending trigger inserted | Trigger ID |
genie_audit_event | Any audit event logged | entity_type:event_type:entity_id |
genie_task_stage | Task stage changes | task_id:old_stage:new_stage |
genie_message | New message posted | conversation_id:message_id:sender_id |
genie_task_dep | Dependency added/removed | task_id:added/removed:dep_id:dep_type |
The scheduler daemon subscribes to genie_trigger_due for real-time trigger notification, with a 30-second poll fallback as a safety net.
Task Service API
The task service (task-service.ts) provides CRUD operations scoped by repo_path:
// Create a task
const task = await createTask(sql, repoPath, {
title: "Implement auth middleware",
priority: "high",
wishFile: ".genie/wishes/auth-fix/WISH.md",
groupName: "1",
});
// Assign an actor
await addActor(sql, task.id, {
actorType: "local",
actorId: "engineer-1",
}, "assignee");
// Add dependencies
await addDependency(sql, task.id, otherTask.id, "depends_on");
Execution Locking
Tasks support atomic checkout via checkout_run_id and execution_locked_at fields. This prevents two agents from claiming the same task simultaneously:
UPDATE tasks
SET checkout_run_id = $1, execution_locked_at = now()
WHERE id = $2 AND checkout_run_id IS NULL
RETURNING *;
The lock expires after checkout_timeout_ms (default: 600,000ms / 10 minutes).
Migration Runner
Migrations are loaded from src/db/migrations/ in lexicographic order. The _genie_migrations table tracks which migrations have been applied:
CREATE TABLE _genie_migrations (
id INTEGER GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
name TEXT UNIQUE NOT NULL,
applied_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
Each migration runs in its own transaction. If a migration fails, subsequent migrations are skipped and the error is thrown.