👣 Find the tool calls your agents get wrong, and turn repeats into fixes.
Desire Path (dp) is a CLI and a set of agent hooks for developers who want
fewer repeated tool-call failures. It stores calls locally, ranks recurring
failures, and records mappings from mistaken tool names to real ones.
The name comes from the trails people wear through grass: evidence of where a path is needed.
- Find recurring friction: rank failed tool calls rather than guessing what to fix.
- Record the intended tool: keep explicit mappings from mistaken names to real tools.
- Inspect calls locally: collect and query failures without a Quipu server.
The Desire Path book explains ingestion, analysis and agent integration.
curl -fsSL https://raw.githubusercontent.com/scbrown/desire-path/main/install.sh | shPython 3.9+, curl, and a Linux or macOS shell. Downloads the latest published archive, verifies SHA-256 and the executable
version before publishing command links in ~/.local/bin. Add it to PATH.
The complete versioned bundle stays in ~/.local/lib/desire-path/TAG for rollback.
Published targets: Linux and macOS, x86_64 and arm64.
Set STACK_INSTALL_ROOT on the receiving shell for another prefix.
Pinned releases, alternatives, configuration and removal are in the
installation and usage reference.
A synthetic failure is collected in a local database; the operator writes the correction. Read the transcript or reproduce the recording.
Use a temporary database and one synthetic failed call; Python 3 formats the result:
DP_DEMO=$(mktemp -d)
printf '%s\n' '{"tool_name":"read_file","error":"unknown tool","session_id":"demo"}' | dp --db "$DP_DEMO/desires.db" ingest --source claude-code --json > "$DP_DEMO/record.json"
dp --db "$DP_DEMO/desires.db" paths --json | python3 -c 'import json,sys; p=json.load(sys.stdin)[0]; print(p["pattern"], p["count"])'Expected stdout:
read_file 1
The failure became a queryable pattern without configuring an agent or touching your usual database. An optional-metrics diagnostic may also appear on stderr; see troubleshooting.
After your agent has recorded calls:
| question | command |
|---|---|
| Which failures repeat? | dp paths --top 5 |
| What happened for this tool? | dp inspect read_file |
| What tool might have been intended? | dp similar read_file |
| How do I record the intended mapping? | dp alias read_file Read |
| How do I export the failures? | dp export --format json |
An alias records a mapping. Active interception is a separate pave setup. See the CLI reference for flags and all commands.
Repeated failures can be measured with dp failure-families --since <RFC3339> --until <RFC3339> --window 1h --max-records 10000 --json. It groups by tool, parsed shell command-program shape and a bounded error class; compound commands are grouped as programs, without claiming which subcommand failed. Argument values, paths and error messages are absent from output. Unsupported wrappers and dynamic command identities are counted separately as UNKNOWN. Synthetic turn-pattern observations are excluded. peak_window measures the historical rolling maximum; current_window measures the window ending at --until. These are observations, not an alerting policy or a claim of complete capture.
--max-records defaults to 10000 and accepts 1 through 100000. The store query
loads at most the cap plus one sentinel; overflow returns an error without partial
counts. Future records after --until conservatively consume this candidate cap
because the existing store selector bounds only --since. JSON also identifies
the exact since/until, max_records, input_records and complete: true.
Complete means the candidate inventory fit the cap, not that normalization or
failure capture was complete: consumers must still inspect unknown and
excluded. Nonzero counts also include fixed-key unknown_by_reason
(invalid_tool_name, unsupported_command_shape) and excluded_by_reason
(turn_pattern) maps. These are coarse parser branches, not individual commands
or a reason to treat unsupported records as normalized. Older reports omit them;
their unsupported kinds cannot be recovered from aggregate totals alone.
A record cap bounds materialized rows, not total input bytes or query
latency. Prefer one current window for scheduled threshold evaluation; a historical
report requires its own bounded read-cost admission.
Local failure-families reads require an existing database at the current schema
version. The command opens it read-only: missing databases and schema mismatches
return an error without creating a store or migrating it. Configured remote
stores continue to use their existing read API.
For Claude Code, with dp on the agent's PATH:
dp init --source claude-code
dp sourcesThe installer merges hooks into ~/.claude/settings.json. It installs ingestion
for successes and failures, plus signposting and correction hooks. Review that
file after installation. Using agents
explains the installed hooks and the Codex, Cursor, and Kiro source plugins.
Start agent orientation with dp prime (--brief, --json, or --static).
It reads existing state without initializing a database or installing hooks.
See the agent primer
and Desire Path skill.
The shell installer needs Python 3.9+, curl and Linux or macOS. The example needs a Bash-compatible shell and Python 3; source builds need Go 1.24+. Calls are stored locally by default. Review hook settings and captured data before enabling an agent integration. A recorded alias and active interception are separate capabilities.
- The Desire Path book: concepts and commands.
- Docs map: find the detailed guides.
- Getting started: configure your first source.
- Tambo: guided stack installation and verification.
- Camayoc: governed memory and vocabulary.
- Detailed examples and agent setup.
Load this repository’s graph: public repository-pendant assets have not yet been verified. When a release supplies the archive, checksum and provenance, follow the verified import workflow: extract the share directory and use quipu import SHARE_DIR --db repository.db. Import stages knowledge; ROOT stays unchanged.
The Quipu stack is built around a governed, bitemporal knowledge store: shared facts, decisions and work history your agents can query. Quipu can check writes against your rules, records where each fact came from, and answers what was true when.
| tool | what it gives your agents |
|---|---|
| tambo | 🧰 Agent Platform Toolkit - installs and configures the quipu stack |
| quipu | stores shared facts with provenance and history; can check writes against your rules |
| camayoc | prepares knowledge and vocabulary for Quipu, with checks before it is admitted |
| quechua | shared vocabulary and shapes for interoperable knowledge |
| chaski | reacts to graph changes and delivers governed notifications |
| bobbin | indexes your codebase and injects context from that index and Quipu knowledge |
| yupana | shows code impact and can read policies from Quipu to govern agent actions |
| desire-path | turns agent mistakes into feature requests; works on its own without Quipu |
| seeds | a work item tracker backed by the Quipu knowledge base |
| shantytown | runs crews of AI agents on work items, triggered by hand, on a schedule or by events; can share work and memory through Quipu |
| rikuy | live brief: status, graphs, watches and signed decisions over Quipu |
| shuttle | runs signed agent workflows and keeps their records in Quipu |
From a checkout, with just, Go, Python 3, pre-commit, and mdBook installed:
just build
just test
just checkSee the development guide.
