Crates
Toolpath is a Rust workspace of focused, composable crates. The core crate has zero dependencies beyond serde; satellite crates add derivation sources and rendering.
toolpath-cli (binary: path)
+-- toolpath (core types)
+-- toolpath-convo (conversation abstraction)
+-- toolpath-git -> toolpath
+-- toolpath-github -> toolpath
+-- toolpath-claude -> toolpath, toolpath-convo
+-- toolpath-dot -> toolpath
+-- toolpath-md -> toolpath
No cross-dependencies between satellite crates except toolpath-claude -> toolpath-convo.
toolpath
Core types, builders, and query API
The gravity well. All other crates depend on this; it depends on nothing except serde. Defines Step, Path, Graph, and the query functions to traverse them.
toolpath-convo
Provider-agnostic conversation types and traits
Defines Turn, Role, ConversationView, and the ConversationProvider/ConversationWatcher traits. Provider crates (like toolpath-claude) implement the traits; consumer apps code against them.
toolpath-git
Derive from git repository history
Reads git history via libgit2 and maps commits to Steps, branches to Paths. Single branch produces a Path; multiple branches produce a Graph.
toolpath-github
Derive from GitHub pull requests
Reads GitHub PRs via the REST API and maps commits, reviews, comments, and CI checks to Steps. Everything is a Step in the DAG — code changes, review threads, approvals, and CI results.
toolpath-claude
Derive from Claude conversation logs
Reads Claude Code conversation data from ~/.claude/projects/ and maps messages, tool calls, and abandoned approaches to Toolpath documents.
toolpath-dot
Graphviz DOT visualization
Renders any Toolpath Document as a Graphviz diagram. Steps are color-coded by actor type, dead ends get red dashed borders, and the DAG structure is preserved visually.
toolpath-md
Markdown rendering for LLM consumption
Renders any Toolpath Document as readable Markdown — a narrative an LLM can reason about. Dead ends are called out explicitly, diffs are included at configurable detail levels, and the output preserves enough anchoring info for an LLM to reference back into the original document.
toolpath-cli
Unified CLI (binary: path)
One binary called `path` that ties everything together: derive, query, render, merge, track, validate.
Using the libraries
Core types
use toolpath::v1::{Step, Path, Base, Document};
let step = Step::new("step-001", "human:alex", "2026-01-29T10:00:00Z")
.with_parent("step-000")
.with_raw_change("src/main.rs", "@@ -1,1 +1,1 @@\n-hello\n+world")
.with_intent("Fix greeting");
let path = Path::new(
"path-pr-42",
Some(Base::vcs("github:org/repo", "abc123")),
"step-001",
);
Query operations
use toolpath::v1::query;
let ancestors = query::ancestors(&path.steps, &path.path.head);
let dead_ends = query::dead_ends(&path.steps, &path.path.head);
let by_actor = query::filter_by_actor(&path.steps, "agent:");
let artifacts = query::all_artifacts(&path.steps);
Git derivation
use toolpath_git::{derive, DeriveConfig};
let repo = git2::Repository::open(".")?;
let config = DeriveConfig {
remote: "origin".into(),
title: None,
base: None,
};
let doc = derive(&repo, &["main".into()], &config)?;
DOT rendering
use toolpath::v1::Document;
use toolpath_dot::{render, RenderOptions};
let dot_string = render(&doc, &RenderOptions::default());
// Pipe through `dot -Tpng` for an image
Markdown rendering
use toolpath::v1::Document;
use toolpath_md::{render, RenderOptions};
let md_string = render(&doc, &RenderOptions::default());
// Feed to an LLM for contextual assistance