Skip to main content

Crate cpm_planner

Crate cpm_planner 

Source
Expand description

cpm-planner: a Critical Path Method (CPM) planner for agent work, exposed as a standalone MCP server and usable as a plain Rust library.

The CPM kernel does the forward pass (earliest start/finish), backward pass (latest start/finish), slack computation, critical-path identification, parallel batch grouping, and bottleneck (ROI) analysis.

On top of that kernel, BasicCpmPlanner implements the lock-aware Planner trait: callers submit a PlanGraph, then acquire / heartbeat / release locks on disjoint cohorts of deliverables so that multiple workers can run in parallel without stepping on each other. The same planner keeps named plan lines and variants (plan-as-code files under .cpm-planner/plans/), frozen earned-value baselines and snapshots, and durable state in SQLite (SqlitePlanStore). PlanServer surfaces all of it as MCP tools (plan.submit, plan.acquire_cohort, plan.ev, …) over stdio, so any MCP-speaking client — Claude Code, Cursor, a custom orchestrator, or a praxec workflow connection — can drive it.

§Example

Schedule a graph, then lease and complete its first ready cohort:

use cpm_planner::plan::{AcquireRequest, CallerId, DeliverableStatus, PlanGraph};
use cpm_planner::ports::Planner;
use cpm_planner::{BasicCpmPlanner, MarkStatusRequest};

let graph: PlanGraph = serde_json::from_value(serde_json::json!({
    "deliverables": [
        {"id": "design", "owned_files": ["docs/design.md"], "prerequisites": [],
         "estimated_effort_hours": 4.0},
        {"id": "build", "owned_files": ["src/app.rs"], "prerequisites": ["design"],
         "estimated_effort_hours": 8.0},
        {"id": "docs", "owned_files": ["README.md"], "prerequisites": ["design"],
         "estimated_effort_hours": 2.0}
    ]
}))?;

// Pure CPM: `__start__` and `__finish__` are synthetic zero-length endpoints.
let cpm = cpm_planner::schedule::compute_cpm(&graph)?;
assert_eq!(cpm.critical_path, ["__start__", "design", "build", "__finish__"]);
assert_eq!(cpm.critical_path_duration, 12.0);

// Lock-aware execution on a private in-memory store.
let runtime = tokio::runtime::Runtime::new()?;
runtime.block_on(async {
    let planner = BasicCpmPlanner::new();
    let plan_id = planner.submit_plan(graph).await?;
    let caller = CallerId("worker-1".into());

    let cohort = planner
        .acquire_cohort(AcquireRequest::new(plan_id.clone(), caller.clone(), 4))
        .await?;
    let leased: Vec<&str> = cohort.rows.iter().map(|r| r.deliverable.id.as_str()).collect();
    assert_eq!(leased, ["design"]); // `build` and `docs` wait on it

    planner
        .mark_status(MarkStatusRequest::new(
            plan_id.clone(),
            "design",
            caller.clone(),
            DeliverableStatus::Complete,
        ))
        .await?;

    // Completing `design` releases its lock and readies both dependents.
    let next = planner
        .acquire_cohort(AcquireRequest::new(plan_id, caller, 4))
        .await?;
    let mut leased: Vec<&str> = next.rows.iter().map(|r| r.deliverable.id.as_str()).collect();
    leased.sort();
    assert_eq!(leased, ["build", "docs"]);
    Ok::<_, anyhow::Error>(())
})?;

§Layout

  • plan — the wire/domain model (deliverables, cohorts, locks, errors).
  • ports — the Planner trait.
  • algorithm / task — the pure CPM kernel and its internal model (the Task types carry ES/EF/LS/LF/slack/batching state the wire model doesn’t need to expose).
  • schedule — schedule::compute_cpm, the CPM run shared by submit, status and the analysis tools.
  • planner — BasicCpmPlanner, the lock-aware implementation (including the earned-value operations).
  • plan_store — durable SQLite persistence (plans, statuses, cohort locks, submit dedup, portfolio lines/variants/revisions, earned value) and the cross-process atomicity mechanism.
  • project — project-root discovery and confined plan-file I/O.
  • edits, revise — structured graph edits and progress-preserving revision.
  • lint, simulate, resource_schedule, monte_carlo, compare, metrics, drag, risk, network_health — the read-only analysis tools and the plan scorecard.
  • earned_value — the pure PV / EV / AC engine.
  • review, llm — the optional plan.review and its OpenRouter / Jev judge.
  • server — the MCP tool façade.
  • skills — the embedded agent skills and cpm-planner skills install.
  • audit — the lock-lifecycle audit surface.

See docs/architecture.md in the repository for the request flow, the store schema and the concurrency model.

This crate has no dependency on praxec; it is consumed purely over the MCP protocol.

Re-exports§

pub use algorithm::CpmAlgorithm;
pub use drag::DragResult;
pub use drag::diameter;
pub use drag::drag;
pub use estimator::EffortEstimator;
pub use estimator::EstimationConfig;
pub use plan::AcceptRequest;
pub use plan::AcquireRequest;
pub use plan::Estimate;
pub use plan::ForceReleaseRequest;
pub use plan::HeartbeatRequest;
pub use plan::MarkStatusRequest;
pub use plan_store::DB_PATH_ENV;
pub use plan_store::SqlitePlanStore;
pub use planner::BasicCpmPlanner;
pub use planner::ClockFn;
pub use planner::DEFAULT_EFFORT_HOURS;
pub use planner::DEFAULT_MAX_TTL;
pub use planner::DEFAULT_TTL;
pub use planner::MAX_ATTEMPTS;
pub use planner::MAX_LAPSES;
pub use server::PLAN_TOOL_NAMES;
pub use server::PlanServer;
pub use server::TOOL_ACCEPT;
pub use server::TOOL_ACQUIRE_COHORT;
pub use server::TOOL_FORCE_RELEASE;
pub use server::TOOL_HEARTBEAT;
pub use server::TOOL_MARK_STATUS;
pub use server::TOOL_REVIEW;
pub use server::TOOL_STATUS;
pub use server::TOOL_SUBMIT;
pub use server::plan_tool_definitions;
pub use task::Bottleneck;
pub use task::CriticalPathResult;
pub use task::Task;
pub use task::TaskBatch;
pub use task::TaskKind;
pub use task::TaskStatus;

Modules§

algorithm
CPM Algorithm Implementation
audit
Minimal audit surface for the planner’s lock-lifecycle events.
compare
Compare plan variants on the scorecard: Pareto front and weighted rank.
drag
Devaux DRAG and graph diameter for CPM schedules.
earned_value
Pure earned-value engine: PV / EV / AC and the derived SPI / CPI / EAC family, computed from a frozen baseline, the current graph, statuses and actuals. No I/O, no clocks: the caller supplies as_of.
edits
Pure structured edits over a PlanGraph.
estimator
Effort Estimation for CPM Tasks
lint
plan.lint: static checks over a PlanGraph that never submit it.
llm
OpenRouter / Jev configuration and the JudgmentModel seam (P6, #26).
metrics
Plan scorecard: one struct of headline numbers that wires the DRAG, risk and network-health metrics together with the schedule and lint results.
monte_carlo
Seeded Monte Carlo schedule risk over three-point estimates.
network_health
iDesign network-health metrics.
plan
SPEC §33 PA1 — Planner data model.
plan_store
SQLite persistence for crate::planner::BasicCpmPlanner.
planner
BasicCpmPlanner — open-source Planner implementation.
ports
The lock-aware Planner trait — the seam between an MCP/host caller and a scheduling implementation. crate::planner::BasicCpmPlanner is the textbook Critical Path Method implementation shipped by this crate.
project
Project-root discovery and confined plan-file paths.
resource_schedule
Resource-constrained scheduling: levels a plan against per-resource capacities with event-driven list scheduling, then reports the driving chain (what each link waited on) and project / feeding buffers.
review
plan.review: deterministic lint, one batched Jev judgment call, and mechanically verified proposals (P6, #26).
revise
Pure plan revision: derive the runtime state of a revised graph from the state of the plan it replaces, carrying progress over.
risk
iDesign risk engine for CPM Planner.
schedule
Shared CPM computation: turns a validated PlanGraph into a CriticalPathResult. Used when a plan is submitted, when the store recomputes results cached by an older kernel version, and by the read-only analysis tools.
server
MCP tool surface for the open-source CPM planner.
simulate
Read-only plan simulation: lint, CPM, optional resource leveling and Monte Carlo, and the scorecard, for a graph that is never persisted.
skills
cpm-planner skills install|uninstall|list: copies the agent skills under skills/ (embedded at compile time) into the directories each agent tool reads, per docs/agents/tool-matrix.md.
task
CPM Task data structures