Polpo persists tasks, runs, missions, sessions, memory, logs, notifications, and approval state using a pluggable store layer. All stores implement a common interface and can be swapped via configuration.
TaskStore Interface
The core TaskStore interface defines the abstract contract that all task persistence backends must implement:
interface TaskStore {
// State access
getState(): PolpoState;
setState(partial: Partial<PolpoState>): void;
// Task CRUD
addTask(task: Omit<Task, "id" | "status" | "retries" | "createdAt" | "updatedAt">): Task;
getTask(taskId: string): Task | undefined;
getAllTasks(): Task[];
updateTask(taskId: string, updates: Partial<Omit<Task, "id" | "status">>): Task;
removeTask(taskId: string): boolean;
removeTasks(filter: (task: Task) => boolean): number;
// State machine
transition(taskId: string, newStatus: TaskStatus): Task;
// Bypass state machine (recovery only)
unsafeSetStatus(taskId: string, newStatus: TaskStatus, reason: string): Task;
// Lifecycle
close?(): void;
// Mission persistence (optional)
saveMission?(mission: Omit<Mission, "id" | "createdAt" | "updatedAt">): Mission;
getMission?(missionId: string): Mission | undefined;
getMissionByName?(name: string): Mission | undefined;
getAllMissions?(): Mission[];
updateMission?(missionId: string, updates: Partial<Omit<Mission, "id">>): Mission;
deleteMission?(missionId: string): boolean;
nextMissionName?(): string;
}
unsafeSetStatus bypasses the state machine and should only be used for recovery, race-condition fallbacks, and fix/Q&A re-runs. A mandatory reason string is logged.
Configuration Stores
| Store | Purpose | Location |
|---|
JsonConfigStore | Project configuration | .polpo/polpo.json |
The JsonConfigStore (aliased as PolpoConfigStore) manages the polpo.json configuration file. It is always used regardless of the storage backend setting.
Choosing a Backend
| Scenario | Recommended Backend |
|---|
| Getting started / single user | File (default) |
| Multiple concurrent orchestrators | SQLite |
| CI/CD pipelines | SQLite |
| Large task sets (100+ tasks) | SQLite or PostgreSQL |
| Production / multi-server | PostgreSQL |
| Debugging / inspecting state | File |
Set the storage backend in .polpo/polpo.json:
{
"settings": {
"storage": "sqlite"
}
}
Supported values: "file" (default), "sqlite", and "postgres".
SQLite and PostgreSQL both use Drizzle ORM via the @polpo-ai/drizzle package, sharing the same store interface. Switching between them is a one-line config change.
All stores share the same .polpo/ directory by convention. The directory is created automatically by polpo init.