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.How pgserve Works
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:| 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 (workers, 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 theprojects 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 theagents 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 |
audit_events table.
Migration 007b: Mailbox/Team Chat Reconciliation
Fixes production schema drift where005_pg_state was recorded as applied but partially failed. Ensures mailbox and team_chat tables exist with correct schemas.
Migration 008: Boards
Two tables replacingtask_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) |
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
Thesoftware task type defines a 7-stage pipeline that maps to Genie skills:
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’sLISTEN/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 |
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:
Execution Locking
Tasks support atomic checkout viacheckout_run_id and execution_locked_at fields. This prevents two agents from claiming the same task simultaneously:
checkout_timeout_ms (default: 600,000ms / 10 minutes).
Migration Runner
Migrations are loaded fromsrc/db/migrations/ in lexicographic order. The _genie_migrations table tracks which migrations have been applied: