TaskProvider boundary (ADR-001)

Mainark routes task-graph I/O through TaskProvider so backends can be swapped without rewriting CLI/pipeline callers.

Status

ItemStatus
Active default backendLinear (TASK_BACKEND=linear)
Local backend (opt-in)SQLite (TASK_BACKEND=sqlite) — Phase 2
BeadsStub only — design review: SQLite prior stands (spike)
Local task storeissues + work_status / plan_md / issue_events / id_sequences

Entry points

CallerFactoryNotes
Orchestrator / pipelinegetTaskProvider()Uses config().taskBackend
CLIcreateCliTaskProviderFromEnv(dotenv)Backend-aware; sqlite needs no Linear key
# Opt into local task store (Phase 2/3 soak)
TASK_BACKEND=sqlite
SQLITE_PATH=./data/orchestrator.db
# LINEAR_API_KEY not required for issue CRUD / implement queue when sqlite
import { getTaskProvider, createCliTaskProviderFromEnv } from "@/tasks";

await getTaskProvider().onPickedUp(uuid);
const tasks = createCliTaskProviderFromEnv(dotenv);
await tasks.createIssue({ title: "…" });

Intentionally outside / deferred

ItemWhy
Default still LinearPhase 4 flips default after human soak
Linear client internalsStill used by LinearTaskProvider
Fulreach CI → Linear commentsPhase 5
Beads SoTRejected in design review

Phase 3 checklist (automated vs human)

Automated in tests/unit/sqliteTaskProvider.test.ts: create/edit, deps, epic plan, queue, claim, events, offline factory, pause/resume reconcile.

Human soak before Phase 4: implement, publish, review, worktree lifecycle, full offline epic E2E.