3.8 KiB
3.8 KiB
CLAUDE TASKS FEATURE KNOWLEDGE BASE
OVERVIEW
Claude Code compatible task schema and storage. Provides core task management utilities used by task-related tools and features.
STRUCTURE
claude-tasks/
├── types.ts # Task schema (Zod)
├── types.test.ts # Schema validation tests (8 tests)
├── storage.ts # File operations
├── storage.test.ts # Storage tests (14 tests)
└── index.ts # Barrel exports
TASK SCHEMA
type TaskStatus = "pending" | "in_progress" | "completed" | "deleted"
interface Task {
id: string
subject: string // Imperative: "Run tests" (was: title)
description: string
status: TaskStatus
activeForm?: string // Present continuous: "Running tests"
blocks: string[] // Task IDs this task blocks
blockedBy: string[] // Task IDs blocking this task (was: dependsOn)
owner?: string // Agent name
metadata?: Record<string, unknown>
repoURL?: string // oh-my-opencode specific
parentID?: string // oh-my-opencode specific
threadID: string // oh-my-opencode specific
}
Key Differences from Legacy:
subject(wastitle)blockedBy(wasdependsOn)blocks(new field)activeForm(new field)
TODO SYNC
The task system includes a sync layer (todo-sync.ts) that automatically mirrors task state to the project's Todo system.
- Creation: Creating a task via
task_createadds a corresponding item to the Todo list. - Updates: Updating a task's
statusorsubjectviatask_updatereflects in the Todo list. - Completion: Marking a task as
completedautomatically marks the Todo item as done.
STORAGE UTILITIES
getTaskDir(config)
Returns the task storage directory path.
Default behavior (no config override):
Returns ~/.config/opencode/tasks/<task-list-id>/ where:
- Task list ID is resolved via
resolveTaskListId()
With storage_path config:
- Absolute paths (starting with
/) are returned as-is - Relative paths are joined with
process.cwd()
resolveTaskListId(config)
Resolves the task list ID for directory scoping.
Priority order:
ULTRAWORK_TASK_LIST_IDenvironment variableconfig.sisyphus?.tasks?.task_list_idconfig option- Sanitized
basename(process.cwd())as fallback
Sanitization: Replaces non-alphanumeric characters (except - and _) with -
readJsonSafe(filePath, schema)
- Returns parsed & validated data or
null - Safe for missing files, invalid JSON, schema violations
writeJsonAtomic(filePath, data)
- Atomic write via temp file + rename
- Creates parent directories automatically
- Cleans up temp file on error
acquireLock(dirPath)
- File-based lock:
.lockfile with timestamp - 30-second stale threshold
- Returns
{ acquired: boolean, release: () => void }
TESTING
types.test.ts (8 tests):
- Valid status enum values
- Required vs optional fields
- Array validation (blocks, blockedBy)
- Schema rejection for invalid data
storage.test.ts (14 tests):
- Path construction
- Safe JSON reading (missing files, invalid JSON, schema failures)
- Atomic writes (directory creation, overwrites)
- Lock acquisition (fresh locks, stale locks, release)
USAGE
import { TaskSchema, getTaskDir, readJsonSafe, writeJsonAtomic, acquireLock } from "./features/claude-tasks"
const taskDir = getTaskDir(config)
const lock = acquireLock(taskDir)
try {
const task = readJsonSafe(join(taskDir, "1.json"), TaskSchema)
if (task) {
task.status = "completed"
writeJsonAtomic(join(taskDir, "1.json"), task)
}
} finally {
lock.release()
}
ANTI-PATTERNS
- Direct fs operations (use storage utilities)
- Skipping lock acquisition for writes
- Ignoring null returns from readJsonSafe
- Using old schema field names (title, dependsOn)