Storage
Goblin uses SQLite for persistence and git worktrees for isolated development.
SQLite Database
The database is stored at .goblin/goblin.db.
Schema Overview
-- Projects: Maps repos to Linear teams
CREATE TABLE projects (
id TEXT PRIMARY KEY,
name TEXT NOT NULL,
repo_path TEXT NOT NULL,
linear_org TEXT NOT NULL,
linear_team_id TEXT NOT NULL,
linear_team_key TEXT NOT NULL,
created_at TEXT NOT NULL
);
-- Pipelines: Issue lifecycle tracking
CREATE TABLE pipelines (
id TEXT PRIMARY KEY,
project_id TEXT NOT NULL,
linear_issue_id TEXT NOT NULL,
stage TEXT NOT NULL DEFAULT 'scope',
branch_name TEXT,
worktree_path TEXT,
base_commit TEXT,
pr_url TEXT,
scoper_agent_id TEXT,
builder_agent_id TEXT,
reviewer_agent_id TEXT,
tester_agent_id TEXT,
scope_result TEXT,
review_result TEXT,
test_result TEXT,
test_report TEXT,
qa_steps TEXT,
assignee_user_id TEXT,
created_at TEXT NOT NULL,
updated_at TEXT NOT NULL
);
-- Agents: Worker instances
CREATE TABLE agents (
id TEXT PRIMARY KEY,
project_id TEXT NOT NULL,
status TEXT NOT NULL DEFAULT 'idle',
linear_issue_id TEXT,
session_file TEXT,
pid INTEGER,
created_at TEXT NOT NULL,
last_seen_at TEXT NOT NULL
);
-- Events: Audit log
CREATE TABLE events (
id INTEGER PRIMARY KEY AUTOINCREMENT,
event_type TEXT NOT NULL,
agent_id TEXT,
linear_issue_id TEXT,
data TEXT,
created_at TEXT NOT NULL
);
-- Project config: Per-project settings
CREATE TABLE project_config (
project_id TEXT NOT NULL,
key TEXT NOT NULL,
value TEXT NOT NULL,
updated_at TEXT NOT NULL,
PRIMARY KEY (project_id, key)
);
-- Pipeline stage history: Transition tracking
CREATE TABLE pipeline_stage_history (
id INTEGER PRIMARY KEY AUTOINCREMENT,
pipeline_id TEXT NOT NULL,
stage TEXT NOT NULL,
status TEXT NOT NULL,
agent_id TEXT,
summary TEXT,
result TEXT,
started_at TEXT NOT NULL,
completed_at TEXT
);
-- Preview environments: Running previews
CREATE TABLE preview_environments (
id TEXT PRIMARY KEY,
pipeline_id TEXT NOT NULL,
project_id TEXT NOT NULL,
linear_issue_id TEXT NOT NULL,
docker_project_name TEXT NOT NULL,
port_offset INTEGER NOT NULL DEFAULT 0,
service_urls TEXT,
status TEXT NOT NULL DEFAULT 'running',
provider TEXT,
instance_id TEXT,
public_ip TEXT,
public_url TEXT,
created_at TEXT NOT NULL,
stopped_at TEXT
);
-- Linear credentials
CREATE TABLE linear_orgs (
name TEXT PRIMARY KEY,
token TEXT NOT NULL,
created_at TEXT NOT NULL,
updated_at TEXT NOT NULL
);
Database Operations
from goblin.storage.db import Database
db = Database(".goblin/goblin.db")
db.initialize() # Creates tables from schema
# Execute queries
db.execute("INSERT INTO projects ...", params)
result = db.execute_one("SELECT * FROM pipelines WHERE id = ?", (id,))
results = db.execute_many("SELECT * FROM agents WHERE status = ?", ("working",))
Git Worktrees
Each pipeline gets an isolated git worktree:
worktrees/
├── ENG-123-add-auth/ # Worktree for ENG-123
│ ├── .git # Worktree git dir
│ ├── .goblin/ # Signal files
│ │ ├── build-complete
│ │ └── GOBLIN_NOTES.md
│ └── src/ # Project files
├── ENG-124-fix-bug/
└── ENG-125-new-feature/
Worktree Operations
from goblin.core.worktree import WorktreeManager
wm = WorktreeManager(repo_path, worktrees_dir)
# Create worktree
worktree = wm.create("ENG-123", branch_name="ENG-123-add-auth")
# Get worktree
worktree = wm.get("ENG-123")
# Delete worktree
wm.delete("ENG-123")
# Get diff
diff = wm.get_diff("ENG-123") # Against base commit
Benefits of Worktrees
- Isolation: Each issue has its own working directory
- Parallel Work: Multiple agents work simultaneously
- Clean Diffs: Compare against known base commit
- No Conflicts: Agents don't interfere with each other
Event Log
All significant events are logged:
-- Event types
'pipeline_created'
'pipeline_scope_started'
'pipeline_scope_completed'
'pipeline_build_started'
'pipeline_build_completed'
'pipeline_review_started'
'pipeline_review_completed'
'pipeline_test_started'
'pipeline_test_completed'
'pipeline_done'
'pipeline_failed'
'agent_spawned'
'agent_stalled'
'agent_recovered'
Querying Events
# View recent events
goblin events --limit 50
# Filter by issue
goblin events --issue ENG-123
# Filter by type
goblin events --type pipeline_failed
Backup & Recovery
Database Backup
# Backup database
cp .goblin/goblin.db .goblin/goblin.db.backup
# Restore
cp .goblin/goblin.db.backup .goblin/goblin.db
Worktree Recovery
# List all worktrees
git worktree list
# Prune stale worktrees
git worktree prune
Performance
- Indexes: Created on frequently queried columns
- In-memory mode: For testing with
:memory: - Connection pooling: Not needed (SQLite handles this)
Important Indexes
CREATE INDEX idx_pipelines_project ON pipelines(project_id);
CREATE INDEX idx_pipelines_stage ON pipelines(stage);
CREATE INDEX idx_pipelines_issue ON pipelines(linear_issue_id);
CREATE INDEX idx_agents_project ON agents(project_id);
CREATE INDEX idx_agents_status ON agents(status);
CREATE INDEX idx_events_type ON events(event_type);
Next Steps
- Database Schema Reference - Full schema
- Signal Files - Signal file reference
- CLI Reference - Database commands