---
title: internal/plandag
description: Go API reference for the plandag package.
---
# plandag
```go
import "github.com/jbcom/radioactive-ralph/internal/plandag"
```
Package plandag owns the SQLite schema, DAG operations, and sync protocol for user\-facing plans.
The schema is embedded under schema/\*.sql and applied in lexical order by Migrate. The schema\_version is tracked in a dedicated table so future versions can detect skew and refuse to open a DB newer than the running binary supports.
## Index
- [Variables](<#variables>)
- [func Migrate\(db \*sql.DB\) error](<#Migrate>)
- [type CreatePlanOpts](<#CreatePlanOpts>)
- [type CreateTaskOpts](<#CreateTaskOpts>)
- [type Options](<#Options>)
- [type Plan](<#Plan>)
- [type PlanStatus](<#PlanStatus>)
- [type SessionMode](<#SessionMode>)
- [type SessionOpts](<#SessionOpts>)
- [type SessionTransport](<#SessionTransport>)
- [type SessionVariantOpts](<#SessionVariantOpts>)
- [type Store](<#Store>)
- [func Open\(ctx context.Context, opts Options\) \(\*Store, error\)](<#Open>)
- [func \(s \*Store\) AddDep\(ctx context.Context, planID, taskID, dependsOn string\) error](<#Store.AddDep>)
- [func \(s \*Store\) AttachPlan\(ctx context.Context, sessionID, planID string\) error](<#Store.AttachPlan>)
- [func \(s \*Store\) ClaimNextReady\(ctx context.Context, planID, variant, sessionID, sessionVariantID string\) \(\*Task, error\)](<#Store.ClaimNextReady>)
- [func \(s \*Store\) Close\(\) error](<#Store.Close>)
- [func \(s \*Store\) CloseSession\(ctx context.Context, sessionID string\) error](<#Store.CloseSession>)
- [func \(s \*Store\) CreatePlan\(ctx context.Context, o CreatePlanOpts\) \(string, error\)](<#Store.CreatePlan>)
- [func \(s \*Store\) CreateSession\(ctx context.Context, o SessionOpts\) \(string, error\)](<#Store.CreateSession>)
- [func \(s \*Store\) CreateSessionVariant\(ctx context.Context, o SessionVariantOpts\) \(string, error\)](<#Store.CreateSessionVariant>)
- [func \(s \*Store\) CreateTask\(ctx context.Context, o CreateTaskOpts\) error](<#Store.CreateTask>)
- [func \(s \*Store\) DB\(\) \*sql.DB](<#Store.DB>)
- [func \(s \*Store\) GetPlan\(ctx context.Context, id string\) \(\*Plan, error\)](<#Store.GetPlan>)
- [func \(s \*Store\) GetTask\(ctx context.Context, planID, id string\) \(\*Task, error\)](<#Store.GetTask>)
- [func \(s \*Store\) HeartbeatSession\(ctx context.Context, sessionID string\) error](<#Store.HeartbeatSession>)
- [func \(s \*Store\) ListPlans\(ctx context.Context, statuses \[\]PlanStatus\) \(\[\]Plan, error\)](<#Store.ListPlans>)
- [func \(s \*Store\) MarkDone\(ctx context.Context, planID, taskID, sessionID string, evidenceJSON string\) \(\[\]Task, error\)](<#Store.MarkDone>)
- [func \(s \*Store\) MarkFailed\(ctx context.Context, planID, taskID, sessionID, reason string, maxRetries int\) \(retried bool, err error\)](<#Store.MarkFailed>)
- [func \(s \*Store\) Ready\(ctx context.Context, planID string\) \(\[\]Task, error\)](<#Store.Ready>)
- [func \(s \*Store\) SetPlanStatus\(ctx context.Context, id string, status PlanStatus\) error](<#Store.SetPlanStatus>)
- [type Task](<#Task>)
- [type TaskStatus](<#TaskStatus>)
## Variables
ErrDuplicateSlug is returned when a plan with \(repo\_path, slug\) already exists. Callers either pick a new slug or update.
```go
var ErrDuplicateSlug = errors.New("plandag: plan with slug already exists in this repo")
```
ErrNoReadyTask indicates ClaimNextReady found nothing claimable.
```go
var ErrNoReadyTask = errors.New("plandag: no ready task")
```
## func [Migrate]()
```go
func Migrate(db *sql.DB) error
```
Migrate brings db up to currentSchemaVersion by applying any pending \*.up.sql migrations in lexical order.
Migrations are idempotent per\-version via SQLite's user\_version PRAGMA. Each migration runs inside a transaction.
## type [CreatePlanOpts]()
CreatePlanOpts configures plan creation. The caller supplies slug \+ title; ID is generated via Store.uuid\(\).
```go
type CreatePlanOpts struct {
Slug string
Title string
RepoPath string
RepoRemote string
PrimaryVariant string
Confidence int
TagsJSON string
}
```
## type [CreateTaskOpts]()
CreateTaskOpts configures task creation.
```go
type CreateTaskOpts struct {
PlanID string
ID string // stable slug (operator-chosen or fixit-emitted)
Description string
Complexity string
Effort string
VariantHint string
ContextBoundary bool
AcceptanceJSON string
ParentTaskID string
}
```
## type [Options]()
Options configures Open.
```go
type Options struct {
// DSN is a modernc.org/sqlite DSN, e.g.
// "file:/path/to/plans.db?_pragma=foreign_keys(1)&_pragma=journal_mode(WAL)"
DSN string
// Clock is swappable for tests. Nil defaults to clockwork.NewRealClock().
Clock clockwork.Clock
// UUID is swappable for tests. Nil defaults to uuid.NewV7().
UUID func() string
}
```
## type [Plan]()
Plan is the durable row.
```go
type Plan struct {
ID string
Slug string
Title string
RepoPath string
RepoRemote string
Status PlanStatus
PrimaryVariant string
Confidence int
CreatedAt time.Time
UpdatedAt time.Time
LastSessionAt sql.NullTime
TagsJSON string // JSON array
}
```
## type [PlanStatus]()
PlanStatus enumerates the lifecycle states a plan can be in.
```go
type PlanStatus string
```
Plan lifecycle states.
```go
const (
PlanStatusDraft PlanStatus = "draft"
PlanStatusActive PlanStatus = "active"
PlanStatusPaused PlanStatus = "paused"
PlanStatusDone PlanStatus = "done"
PlanStatusFailedPartial PlanStatus = "failed_partial"
PlanStatusArchived PlanStatus = "archived"
PlanStatusAbandoned PlanStatus = "abandoned"
)
```
## type [SessionMode]()
SessionMode identifies portable\-stdio vs durable\-HTTP modes.
```go
type SessionMode string
```
Session execution modes.
```go
const (
SessionModePortable SessionMode = "portable"
SessionModeDurable SessionMode = "durable"
)
```
## type [SessionOpts]()
SessionOpts configures CreateSession.
```go
type SessionOpts struct {
ID string // optional; caller may pass an existing UUID. Empty → auto.
Mode SessionMode
Transport SessionTransport
PID int
PIDStartTime string
Host string
}
```
## type [SessionTransport]()
SessionTransport identifies stdio / http / sse transports.
```go
type SessionTransport string
```
Session transport types.
```go
const (
SessionTransportStdio SessionTransport = "stdio"
SessionTransportHTTP SessionTransport = "http"
SessionTransportSSE SessionTransport = "sse"
)
```
## type [SessionVariantOpts]()
SessionVariantOpts configures CreateSessionVariant.
```go
type SessionVariantOpts struct {
SessionID string
VariantName string
SubprocessPID int
SubprocessStartTime string
}
```
## type [Store]()
Store is the plandag handle. It wraps a \*sql.DB plus deterministic clock \+ UUID provider \(test\-swappable\).
```go
type Store struct {
// contains filtered or unexported fields
}
```
### func [Open]()
```go
func Open(ctx context.Context, opts Options) (*Store, error)
```
Open returns a migrated, ready\-to\-use Store.
### func \(\*Store\) [AddDep]()
```go
func (s *Store) AddDep(ctx context.Context, planID, taskID, dependsOn string) error
```
AddDep wires task → depends\_on for the same plan. Rejects cycles.
### func \(\*Store\) [AttachPlan]()
```go
func (s *Store) AttachPlan(ctx context.Context, sessionID, planID string) error
```
AttachPlan records which session is watching which plan. Used by \`ralph status\` to enumerate active supervision.
### func \(\*Store\) [ClaimNextReady]()
```go
func (s *Store) ClaimNextReady(ctx context.Context, planID, variant, sessionID, sessionVariantID string) (*Task, error)
```
ClaimNextReady is the atomic "claim the next ready task for this variant" operation. Returns the claimed task id, or ErrNoReadyTask if none. Uses BEGIN IMMEDIATE \+ UPDATE ... RETURNING so two parallel ralphs never claim the same task.
### func \(\*Store\) [Close]()
```go
func (s *Store) Close() error
```
Close releases DB resources.
### func \(\*Store\) [CloseSession]()
```go
func (s *Store) CloseSession(ctx context.Context, sessionID string) error
```
CloseSession removes a session row. FK cascades clear its variants and attach rows.
### func \(\*Store\) [CreatePlan]()
```go
func (s *Store) CreatePlan(ctx context.Context, o CreatePlanOpts) (string, error)
```
CreatePlan inserts a fresh plan in draft status and returns the newly generated UUID v7 id.
### func \(\*Store\) [CreateSession]()
```go
func (s *Store) CreateSession(ctx context.Context, o SessionOpts) (string, error)
```
CreateSession inserts a session row. Returns the session id. Called by the MCP server on startup; the session's lifetime is the lifetime of one server process.
### func \(\*Store\) [CreateSessionVariant]()
```go
func (s *Store) CreateSessionVariant(ctx context.Context, o SessionVariantOpts) (string, error)
```
CreateSessionVariant registers a newly\-spawned ralph subprocess against a session. Returns the variant row id.
### func \(\*Store\) [CreateTask]()
```go
func (s *Store) CreateTask(ctx context.Context, o CreateTaskOpts) error
```
CreateTask inserts a pending task. Callers wire dependencies via AddDep.
### func \(\*Store\) [DB]()
```go
func (s *Store) DB() *sql.DB
```
DB returns the underlying \*sql.DB for callers that need raw access. Business\-logic callers should use Store's typed methods instead.
### func \(\*Store\) [GetPlan]()
```go
func (s *Store) GetPlan(ctx context.Context, id string) (*Plan, error)
```
GetPlan loads a plan by id.
### func \(\*Store\) [GetTask]()
```go
func (s *Store) GetTask(ctx context.Context, planID, id string) (*Task, error)
```
GetTask loads one task by \(plan\_id, id\).
### func \(\*Store\) [HeartbeatSession]()
```go
func (s *Store) HeartbeatSession(ctx context.Context, sessionID string) error
```
HeartbeatSession refreshes last\_heartbeat for a session. Called periodically by the server. Reaper uses staleness to detect dead sessions.
### func \(\*Store\) [ListPlans]()
```go
func (s *Store) ListPlans(ctx context.Context, statuses []PlanStatus) ([]Plan, error)
```
ListPlans returns plans matching filter. Empty filter → active \+ paused.
### func \(\*Store\) [MarkDone]()
```go
func (s *Store) MarkDone(ctx context.Context, planID, taskID, sessionID string, evidenceJSON string) ([]Task, error)
```
MarkDone transitions a running task to done, logs the event, and returns the set of newly\-ready downstream tasks.
### func \(\*Store\) [MarkFailed]()
```go
func (s *Store) MarkFailed(ctx context.Context, planID, taskID, sessionID, reason string, maxRetries int) (retried bool, err error)
```
MarkFailed transitions a running task to failed or retries.
### func \(\*Store\) [Ready]()
```go
func (s *Store) Ready(ctx context.Context, planID string) ([]Task, error)
```
Ready returns tasks that are ready to run — every dependency is \`done\` \(or \`skipped\`\). Result is ordered by created\_at for stable test output.
### func \(\*Store\) [SetPlanStatus]()
```go
func (s *Store) SetPlanStatus(ctx context.Context, id string, status PlanStatus) error
```
SetPlanStatus updates the plan's status column.
## type [Task]()
Task is a DAG node.
```go
type Task struct {
ID string
PlanID string
Description string
Complexity string
Effort string
VariantHint string
ContextBoundary bool
AcceptanceJSON string
Status TaskStatus
AssignedVariant string
ClaimedBySession string
ClaimedByVariantID string
RetryCount int
ReclaimCount int
ParentTaskID string
CreatedAt time.Time
UpdatedAt time.Time
}
```
## type [TaskStatus]()
TaskStatus enumerates valid task lifecycle states.
```go
type TaskStatus string
```
Task lifecycle states.
```go
const (
TaskStatusPending TaskStatus = "pending"
TaskStatusReady TaskStatus = "ready"
TaskStatusReadyPendingApproval TaskStatus = "ready_pending_approval"
TaskStatusRunning TaskStatus = "running"
TaskStatusDone TaskStatus = "done"
TaskStatusFailed TaskStatus = "failed"
TaskStatusSkipped TaskStatus = "skipped"
TaskStatusDecomposed TaskStatus = "decomposed"
)
```
Generated by [gomarkdoc]()