Skip to main content

scud/
lib.rs

1//! # SCUD - Fast, DAG-driven Task Manager
2//!
3//! SCUD (Simple, Concurrent, Unified, Directed) is a task management system designed
4//! for AI-driven development workflows. It provides both a CLI tool and a library
5//! for managing tasks organized in directed acyclic graphs (DAGs).
6//!
7//! ## Features
8//!
9//! - **DAG-based execution**: Tasks have dependencies that form a directed acyclic graph,
10//!   ensuring work proceeds in the correct order
11//! - **Multi-phase support**: Organize tasks into phases (tags) for different project areas
12//! - **File locking**: Safe concurrent access with atomic read/write operations
13//! - **SCG format**: Token-efficient text format for task storage
14//! - **AI integration**: Parse PRDs and expand complex tasks using LLM providers
15//!
16//! ## Library Usage
17//!
18//! SCUD can be used as a library to programmatically manage tasks:
19//!
20//! ```no_run
21//! use scud::storage::Storage;
22//! use scud::models::{Phase, Task, TaskStatus};
23//!
24//! // Initialize storage (uses current directory by default)
25//! let storage = Storage::new(None);
26//!
27//! // Load all phases (task groups by tag)
28//! let phases = storage.load_tasks().expect("Failed to load tasks");
29//!
30//! // Load a specific phase by tag
31//! let auth_phase = storage.load_group("auth").expect("Phase not found");
32//!
33//! // Find the next available task (dependencies met, status pending)
34//! if let Some(next_task) = auth_phase.find_next_task() {
35//!     println!("Next task: {} - {}", next_task.id, next_task.title);
36//! }
37//!
38//! // Get phase statistics
39//! let stats = auth_phase.get_stats();
40//! println!("Progress: {}/{} done", stats.done, stats.total);
41//! ```
42//!
43//! ## Storage Format
44//!
45//! Tasks are stored in `.scud/tasks/tasks.scg` using the SCG (SCUD Graph) format.
46//! Multiple phases are separated by `---` delimiters:
47//!
48//! ```text
49//! @phase auth
50//!
51//! [1] Implement login endpoint
52//! status: pending
53//! complexity: 5
54//! deps: 2, 3
55//!
56//! ---
57//!
58//! @phase api
59//!
60//! [1] Create REST framework
61//! status: done
62//! ```
63//!
64//! ## CLI Usage
65//!
66//! The `scud` binary provides commands for task management:
67//!
68//! - `scud init` - Initialize a new SCUD project
69//! - `scud list` - List tasks in the active phase
70//! - `scud next` - Find and optionally claim the next available task
71//! - `scud show <id>` - Display task details
72//! - `scud set-status <id> <status>` - Update task status
73//! - `scud waves` - Show tasks organized by execution waves
74//! - `scud stats` - Display completion statistics
75//!
76//! ## Task Generation Pipeline
77//!
78//! SCUD provides a multi-phase pipeline for generating tasks from PRD documents.
79//! This can be invoked via the CLI (`scud generate`) or programmatically:
80//!
81//! ```no_run
82//! use scud::commands::generate::{generate, GenerateOptions};
83//! use std::path::PathBuf;
84//!
85//! #[tokio::main]
86//! async fn main() -> anyhow::Result<()> {
87//!     // Create options with required fields
88//!     let mut options = GenerateOptions::new(
89//!         PathBuf::from("docs/prd.md"),
90//!         "my-feature".to_string(),
91//!     );
92//!
93//!     // Customize the pipeline
94//!     options.num_tasks = 15;        // Generate up to 15 tasks
95//!     options.verbose = true;        // Show detailed output
96//!     options.no_expand = false;     // Run expansion phase
97//!     options.no_check_deps = false; // Run dependency validation
98//!
99//!     // Run the pipeline: parse → expand → check-deps
100//!     generate(options).await?;
101//!     Ok(())
102//! }
103//! ```
104//!
105//! The pipeline consists of three phases:
106//!
107//! 1. **Parse**: Convert a PRD document into initial tasks using AI
108//! 2. **Expand**: Break down complex tasks into subtasks
109//! 3. **Check Dependencies**: Validate and fix task dependencies
110//!
111//! Each phase can be skipped using `no_expand` and `no_check_deps` options.
112
113/// Agent definitions for model routing.
114///
115/// Allows tasks to specify which AI harness and model should run them.
116/// Agent definitions are loaded from `.scud/agents/<name>.toml` files.
117///
118/// # Example
119///
120/// ```toml
121/// # .scud/agents/reviewer.toml
122/// [agent]
123/// name = "reviewer"
124/// description = "Code review agent using smarter model"
125///
126/// [model]
127/// harness = "claude"
128/// model = "opus"
129/// ```
130pub mod agents;
131
132/// Failure attribution using git blame.
133///
134/// Maps validation errors to specific tasks by parsing error output for
135/// file:line references and using git blame to find which commits changed
136/// those lines. Task IDs are extracted from commit message prefixes like `[TASK-ID]`.
137///
138/// # Example
139///
140/// ```no_run
141/// use scud::attribution::{attribute_failure, AttributionConfidence};
142/// use std::path::Path;
143///
144/// let working_dir = Path::new(".");
145/// let wave_tasks = vec!["auth:1".to_string(), "auth:2".to_string()];
146///
147/// let attribution = attribute_failure(
148///     working_dir,
149///     "error: src/main.rs:42: undefined variable",
150///     "",
151///     &wave_tasks,
152///     None,
153/// ).unwrap();
154///
155/// match attribution.confidence {
156///     AttributionConfidence::High => println!("Clear responsible: {:?}", attribution.responsible_tasks),
157///     AttributionConfidence::Medium => println!("Multiple suspects: {:?}", attribution.responsible_tasks),
158///     AttributionConfidence::Low => println!("Cannot determine - all tasks suspect"),
159/// }
160/// ```
161pub mod attribution;
162
163/// Backpressure validation for maintaining code quality during automated execution.
164///
165/// Runs programmatic validation (build, test, lint) after task completion.
166/// See [`backpressure::run_validation`] for the main entry point.
167pub mod backpressure;
168
169/// SQLite database for event logging, transcript storage, and session history.
170///
171/// Provides queryable storage for swarm events, agent transcripts, and session
172/// metadata. Uses WAL mode for concurrent access during swarm execution.
173pub mod db;
174
175/// Background transcript watcher for real-time import of Claude Code JSONL files.
176pub mod transcript_watcher;
177
178/// CLI command implementations.
179///
180/// This module contains the implementation of all SCUD CLI commands including
181/// task listing, status updates, AI-powered parsing, and more. Each submodule
182/// corresponds to a CLI subcommand.
183///
184/// Key submodules:
185/// - `ai` - AI-powered commands (parse PRD, expand tasks, analyze complexity)
186/// - `generate` - Multi-phase task generation pipeline (parse → expand → check-deps)
187/// - `list` - List tasks with filtering
188/// - `next` - Find next available task
189/// - `set_status` - Update task status
190/// - `waves` - Display execution waves
191/// - `stats` - Show completion statistics
192/// - `spawn` - Parallel task execution
193/// - `swarm` - Wave-based parallel execution with backpressure
194///
195/// ## Generate Pipeline
196///
197/// The [`commands::generate`] module provides a complete pipeline for task generation:
198///
199/// ```no_run
200/// use scud::commands::generate::{generate, GenerateOptions};
201/// use std::path::PathBuf;
202///
203/// # async fn example() -> anyhow::Result<()> {
204/// let options = GenerateOptions::new(
205///     PathBuf::from("prd.md"),
206///     "feature".to_string(),
207/// );
208/// generate(options).await?;
209/// # Ok(())
210/// # }
211/// ```
212pub mod commands;
213
214/// Configuration management for SCUD projects.
215///
216/// Handles loading and saving of `.scud/config.toml` which stores:
217/// - LLM provider settings (provider, model, API endpoints)
218/// - Model tiers (smart/fast models for different task types)
219/// - Token limits and other provider-specific settings
220///
221/// # Example
222///
223/// ```no_run
224/// use scud::config::Config;
225/// use std::path::Path;
226///
227/// let config = Config::load(Path::new(".scud/config.toml"))
228///     .unwrap_or_default();
229/// println!("Using provider: {}", config.llm.provider);
230/// ```
231pub mod config;
232
233/// Dynamic extension loading and execution.
234///
235/// Provides infrastructure for loading and running extensions that can
236/// extend SCUD functionality with custom tools and commands.
237pub mod extensions;
238
239/// Task graph serialization formats.
240///
241/// Provides parsers and serializers for the SCG (SCUD Graph) format,
242/// a token-efficient text format designed for AI context windows.
243///
244/// # Format Overview
245///
246/// ```text
247/// @phase my-project
248///
249/// [1] First task
250/// status: pending
251/// complexity: 3
252///
253/// [2] Second task
254/// status: done
255/// deps: 1
256/// ```
257///
258/// Key exports:
259/// - [`formats::parse_scg`] - Parse SCG text into a Phase
260/// - [`formats::serialize_scg`] - Serialize a Phase to SCG text
261/// - [`formats::Format`] - Enum of supported formats (SCG, JSON)
262pub mod formats;
263
264/// LLM client and prompt management.
265///
266/// Provides integration with various LLM providers for AI-powered features:
267/// - PRD parsing to generate initial task lists
268/// - Task expansion into subtasks
269/// - Complexity analysis and dependency detection
270///
271/// Supported providers:
272/// - `claude-cli` - Anthropic Claude via CLI
273/// - `anthropic` - Direct Anthropic API
274/// - `xai` - xAI/Grok API
275/// - `openai` - OpenAI API
276/// - `openrouter` - OpenRouter API
277/// - `codex` - OpenAI Codex CLI
278pub mod llm;
279
280/// OpenCode Server integration for agent orchestration.
281///
282/// Provides HTTP client and SSE event streaming for OpenCode Server mode,
283/// enabling structured communication with agents instead of CLI subprocess spawning.
284///
285/// # Architecture
286///
287/// Instead of spawning one CLI process per agent, this module communicates with
288/// a single OpenCode server that manages multiple sessions:
289///
290/// ```text
291/// SCUD Swarm ──HTTP──► OpenCode Server
292///                 ◄─SSE── real-time events (tool calls, output, completion)
293/// ```
294///
295/// # Benefits
296///
297/// - Lower overhead (single server vs N processes)
298/// - Structured events (tool calls, text deltas, completion)
299/// - Graceful cancellation via HTTP API
300/// - Real-time visibility into agent activity
301///
302/// # Example
303///
304/// ```no_run
305/// use scud::opencode::{OpenCodeManager, global_manager};
306///
307/// #[tokio::main]
308/// async fn main() -> anyhow::Result<()> {
309///     let manager = global_manager();
310///     manager.ensure_running().await?;
311///
312///     let session = manager.client().create_session("Task 1").await?;
313///     manager.client().send_message(&session.id, "Do something", None).await?;
314///
315///     Ok(())
316/// }
317/// ```
318pub mod opencode;
319
320/// JSON RPC IPC server for subagent communication.
321///
322/// Provides a JSON RPC 2.0 protocol for inter-process communication between
323/// SCUD and external orchestrators. The server reads requests from stdin
324/// and emits events/responses to stdout.
325///
326/// ## Protocol
327///
328/// Requests (stdin):
329/// ```json
330/// {"jsonrpc": "2.0", "method": "spawn", "params": {"task_id": "1", "prompt": "..."}, "id": 1}
331/// {"jsonrpc": "2.0", "method": "ping", "id": 2}
332/// {"jsonrpc": "2.0", "method": "shutdown", "id": 3}
333/// ```
334///
335/// Responses/Events (stdout):
336/// ```json
337/// {"jsonrpc": "2.0", "result": {"status": "ok"}, "id": 1}
338/// {"jsonrpc": "2.0", "method": "agent.started", "params": {"task_id": "1"}}
339/// {"jsonrpc": "2.0", "method": "agent.completed", "params": {"task_id": "1", "success": true}}
340/// ```
341///
342/// ## Usage
343///
344/// ```no_run
345/// use scud::rpc::{RpcServer, RpcServerConfig};
346///
347/// #[tokio::main]
348/// async fn main() -> anyhow::Result<()> {
349///     let config = RpcServerConfig::default();
350///     let mut server = RpcServer::new(config);
351///     server.run().await
352/// }
353/// ```
354pub mod rpc;
355
356/// Core data models for tasks and phases.
357///
358/// This module defines the fundamental types used throughout SCUD:
359///
360/// - [`models::Task`] - Individual work items with status, complexity, dependencies
361/// - [`models::Phase`] - A collection of related tasks (identified by a tag)
362/// - [`models::TaskStatus`] - Task lifecycle states (Pending, InProgress, Done, etc.)
363/// - [`models::Priority`] - Task priority levels (Critical, High, Medium, Low)
364/// - [`models::IdFormat`] - ID generation strategy (Sequential or UUID)
365///
366/// # Example
367///
368/// ```
369/// use scud::models::{Task, TaskStatus, Phase};
370///
371/// let mut phase = Phase::new("my-feature".to_string());
372///
373/// let mut task = Task::new(
374///     "1".to_string(),
375///     "Implement feature".to_string(),
376///     "Add the new functionality".to_string(),
377/// );
378/// task.complexity = 5;
379/// task.dependencies = vec!["setup:1".to_string()]; // Cross-phase dependency
380///
381/// phase.add_task(task);
382///
383/// // Find tasks ready to work on
384/// if let Some(next) = phase.find_next_task() {
385///     println!("Ready: {}", next.title);
386/// }
387/// ```
388pub mod models;
389
390/// File-based task storage with locking.
391///
392/// Manages reading and writing of task data to the filesystem with:
393/// - File locking for safe concurrent access
394/// - Caching of active phase selection
395/// - Atomic read-modify-write operations
396///
397/// The storage layer handles:
398/// - `.scud/tasks/tasks.scg` - Main task storage
399/// - `.scud/active-tag` - Currently selected phase
400/// - `.scud/config.toml` - Project configuration
401/// - `.scud/guidance/*.md` - AI context files
402///
403/// # Example
404///
405/// ```no_run
406/// use scud::storage::Storage;
407/// use scud::models::TaskStatus;
408///
409/// let storage = Storage::new(None); // Use current directory
410///
411/// // Load and modify a phase atomically
412/// let mut phase = storage.load_group("my-phase").unwrap();
413/// if let Some(task) = phase.get_task_mut("1") {
414///     task.set_status(TaskStatus::Done);
415/// }
416/// storage.update_group("my-phase", &phase).unwrap();
417/// ```
418pub mod storage;
419
420/// Sync SCUD tasks to Claude Code's Tasks format.
421///
422/// Claude Code has a built-in Tasks feature that agents can access via
423/// `TaskList`, `TaskUpdate`, `TaskCreate` tools. By syncing SCUD tasks
424/// to `~/.claude/tasks/`, agents can see the full task list and dependencies.
425///
426/// # Example
427///
428/// ```no_run
429/// use scud::sync::claude_tasks;
430/// use scud::models::phase::Phase;
431///
432/// let phase = Phase::new("auth".to_string());
433/// // ... add tasks ...
434///
435/// // Sync to Claude Tasks format
436/// let task_file = claude_tasks::sync_phase(&phase, "auth").unwrap();
437///
438/// // Get the task list ID for environment variable
439/// let list_id = claude_tasks::task_list_id("auth");
440/// // Set CLAUDE_CODE_TASK_LIST_ID={list_id} when spawning agents
441/// ```
442pub mod sync;
443
444/// Swarm execution mode - how agents are spawned during swarm execution.
445///
446/// # Modes
447///
448/// - **Tmux**: Uses tmux for agent management. Requires tmux to be installed.
449///   Provides live visibility through tmux windows, useful for debugging.
450///
451/// - **Extensions**: Uses extension-based subprocesses with no tmux dependency.
452///   Agents run as direct child processes. Better for CI/CD environments or
453///   systems without tmux.
454///
455/// - **Server**: Uses OpenCode Server mode for agent orchestration. Provides
456///   structured events (tool calls, text deltas), graceful cancellation, and
457///   lower per-agent overhead. Recommended for production use.
458///
459/// # Example
460///
461/// ```
462/// use scud::SwarmMode;
463///
464/// let mode = SwarmMode::Server;
465/// assert_eq!(mode.to_string(), "server");
466/// ```
467#[derive(Clone, Debug, Default, clap::ValueEnum)]
468pub enum SwarmMode {
469    /// Use tmux for agent management (default, requires tmux installed)
470    #[default]
471    Tmux,
472    /// Use extension-based subprocesses (no tmux dependency)
473    Extensions,
474    /// Use OpenCode Server for agent orchestration (recommended)
475    Server,
476    /// Beads-style continuous execution (no wave batching)
477    /// Tasks execute immediately when dependencies are met
478    Beads,
479}
480
481impl std::fmt::Display for SwarmMode {
482    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
483        match self {
484            SwarmMode::Tmux => write!(f, "tmux"),
485            SwarmMode::Extensions => write!(f, "extensions"),
486            SwarmMode::Server => write!(f, "server"),
487            SwarmMode::Beads => write!(f, "beads"),
488        }
489    }
490}
491
492#[cfg(test)]
493mod swarm_mode_tests {
494    use super::*;
495
496    #[test]
497    fn test_swarm_mode_default() {
498        let mode: SwarmMode = Default::default();
499        assert!(matches!(mode, SwarmMode::Tmux));
500    }
501
502    #[test]
503    fn test_swarm_mode_display() {
504        assert_eq!(SwarmMode::Tmux.to_string(), "tmux");
505        assert_eq!(SwarmMode::Extensions.to_string(), "extensions");
506        assert_eq!(SwarmMode::Server.to_string(), "server");
507        assert_eq!(SwarmMode::Beads.to_string(), "beads");
508    }
509
510    #[test]
511    fn test_swarm_mode_clone() {
512        let mode = SwarmMode::Extensions;
513        let cloned = mode.clone();
514        assert!(matches!(cloned, SwarmMode::Extensions));
515    }
516}
517
518/// Returns a greeting message.
519///
520/// # Example
521///
522/// ```
523/// assert_eq!(scud::hello(), "Hello, World!");
524/// ```
525pub fn hello() -> &'static str {
526    "Hello, World!"
527}