Skip to main content

GoalT (Goal Tree)

A multi-parent, value-propagating goal graph. Concept-stage, open source, looking for people to poke holes in it.

Open in Colab

The idea

Most prioritization tools assume a clean hierarchy: one goal breaks into sub-goals, which break into sub-sub-goals, and so on. Real work rarely looks like that. A feature can depend on two other things at once; a bug fix can matter to three different initiatives for three different reasons. Trees don't capture that. A graph might.

GoalT is a small engine for exactly that:

  • One root goal. Everything traces back to it.
  • Any goal can have multiple children and multiple parents. It's a DAG, not a tree.
  • Every parent distributes exactly 1.0 of value across its children.
  • A goal with multiple parents accumulates value from each of them — so goals that genuinely matter to more things naturally float to the top.
  • Adding a goal only recomputes the part of the graph it affects, not the whole thing.
  • Cycles are rejected explicitly, not silently allowed to loop.

Value redistribution (how a parent splits its value among children) is pluggable. By default it's a simple equal split — deterministic, no API key needed, always converges. You can swap in an LLM to decide weights based on context instead (e.g. "speed matters more than polish this sprint"). The engine never trusts the LLM's numbers directly: whatever comes back gets validated and re-normalized so the graph stays mathematically consistent even if the model returns something odd.

Try it without installing anything

Click the "Open in Colab" badge above. It opens demo.ipynb in your browser, no setup required. Run the cells top to bottom.

Local install

Requirements: Python 3.10+ (the mcp package, needed for the Claude Code server, requires it). If you're on macOS and pip install fails with errors like "Requires-Python >=3.10" or "No matching distribution found for mcp", you likely have more than one Python installed and pip is pointing at the wrong one (common with the Python bundled in Xcode Command Line Tools). Check with python3 --version, and if it's 3.10+, use python3 -m pip install ... instead of a bare pip install ..., which guarantees packages land in the same Python that will actually run the server.

python3 -m pip install goaltree

The core engine only needs networkx. The heavier pieces are extras, so you install what you actually use:

python3 -m pip install "goaltree[viz]"   # + matplotlib, for visualize.draw
python3 -m pip install "goaltree[mcp]"   # + the Claude Code MCP server and dashboard
python3 -m pip install "goaltree[all]"   # everything

Or from source:

git clone https://github.com/GOAL-T/goaltree.git
cd goaltree
python3 -m pip install -e ".[all]"
from goaltree import GoalGraph

g = GoalGraph()
g.add_root("root", "Ship v2 of the product")
g.add_goal("a", "Improve onboarding", parents=["root"])
g.add_goal("b", "Improve performance", parents=["root"])
g.add_goal("c", "Fix export bug", parents=["a", "b"])  # depends on both

print(g)
GoalGraph(root='root')
  1.000  Ship v2 of the product (root)
  1.000  Fix export bug (c)
  0.500  Improve onboarding (a)
  0.500  Improve performance (b)

Note that c lands on 1.000 while the root is also 1.000, and that a, b and c sum to more than the root. That's intentional, not a bug: value is conserved per parent (each parent splits exactly 1.0 among its children), not globally across the graph. A goal serving two parents accumulates from both.

So the number isn't a share of a fixed budget, and comparing it to the root's 1.0 doesn't mean anything. It's a pull-weight: it answers "how much is riding on this," not "what fraction of the project is this." Here, the export bug is load-bearing for both sub-goals, so nothing else in the graph can be done without it mattering — which is exactly what a 1.000 is saying.

See demo.ipynb for the full walkthrough, including the LLM-backed redistribution example.

Use it inside Claude Code

GoalT ships as a Claude Code plugin: an MCP server (build and query a tree in conversation) plus a live dashboard that auto-starts with the server and highlights, in real time, which goal Claude is currently working on.

Install as a plugin (recommended)

/plugin marketplace add GOAL-T/goaltree
/plugin install goalt@goalt-marketplace

This wires up both the MCP tools and the activity hook automatically. Dependencies install themselves the first time the server starts (a bootstrap.sh finds a suitable Python and runs pip install if needed), so no manual clone or pip install step is required. The very first tool call may take a few extra seconds while that happens; after that it's instant.

Manual install (no activity hook, still works)

git clone https://github.com/GOAL-T/goaltree.git
cd goaltree
claude mcp add --transport stdio goalt -- bash "$(pwd)/bootstrap.sh"

This gets you the tools but not the automatic "Claude is currently..." activity pulse -- that part relies on the plugin's hook, which is only registered via the plugin install path above.

Using it

Onboarding an existing codebase: run the /goalt:start slash command in the project you want to plan. Claude explores the repo (README, package manifest, folder structure, database migrations if present), identifies real functional areas, and builds a tree with genuine descriptions -- linking the files and backend artifacts (database tables, edge functions, etc.) it's confident actually implement each goal, rather than fabricating structure.

Starting from scratch, in a Claude Code session:

"Create a goal tree for shipping v2 of our product, with onboarding and performance as sub-goals, and a shared bug fix that depends on both. Show me the priorities and open the dashboard."

Claude calls create_tree, add_goal, and list_priorities, then open_dashboard gives you a URL (http://127.0.0.1:8765) to open in your browser. From there:

  • Watch mode: leave the dashboard open while Claude works. The header shows a live "Claude is currently..." indicator on every tool call -- guaranteed, wired through a Claude Code hook.
  • File-edit highlighting (guaranteed): once a goal has related_files linked, editing one of those files automatically highlights that goal with a glowing green border -- no extra tool call needed, the hook matches the edited path against every goal's related files.
  • Self-reported highlighting (best-effort): for goals that don't map cleanly to specific files, Claude can call set_active_goal with a reason. Best-effort only -- it happens if Claude chooses to call it, not guaranteed.
  • Uncommitted-changes tracking: if project_root was set when the tree was created, a background thread polls git status every few seconds and marks goals with an amber border if any of their related files have uncommitted changes -- independent of whether anything is being actively edited right now.
  • Click any node to open a side panel with two tabs: Description (the goal's description plus its related files/backend artifacts) and Changes (files currently being edited and/or with uncommitted changes, for this specific goal). Clicking a node that's currently active or has uncommitted work opens straight to the Changes tab.
  • Open files in VS Code: every file listed in Related files or Changes is a clickable link (vscode://file/...) that opens it directly in VS Code -- works out of the box if VS Code is installed, no setup needed. Files with uncommitted changes also get a Diff button that opens a proper side-by-side diff (HEAD vs working copy). On macOS this launches VS Code directly (no PATH setup needed, works if VS Code is simply installed); elsewhere it uses the code CLI if it's on PATH. If neither is available, the button tells you exactly what to do instead of failing silently.
  • Drag nodes to rearrange them -- positions stick, they won't snap back on the next update. Click "Reset layout" to let the graph re-lay itself out.

Available tools: load_tree, create_tree, add_goal, link_artifacts, list_priorities, set_active_goal, clear_active_goal, open_dashboard, reset_tree.

Current limitations:

  • The tree auto-saves to <project_root>/.goalt/tree.json on every change and auto-loads on the next session (either a best-effort guess at startup, or reliably via load_tree once Claude knows the actual project root -- the system instructions point it there first). Add .goalt/ to your project's .gitignore if you don't want to commit it.
  • File-to-goal matching (goals_for_file) is a heuristic suffix match, not exact-path resolution -- it can mismatch on ambiguous relative paths in unusual project layouts.
  • Uncommitted-changes tracking assumes a single git repository at project_root and re-polls on a fixed interval (a few seconds), so there's a small lag between a change happening and it showing up.

What's actually in this repo

  • goaltree/goal_tree.py -- the core engine: graph construction, cycle detection, deterministic value propagation, and the pluggable LLM redistribution hook. The only module with no optional dependencies, and the only one re-exported from goaltree directly.
  • goaltree/visualize.py -- a thin matplotlib/networkx wrapper used by demo.ipynb to draw a static graph image. Needs the [viz] extra.
  • demo.ipynb -- an interactive, runnable walkthrough (works in Colab, no local setup).
  • goaltree/mcp_server.py -- the MCP server: tools for building/querying the tree, plus best-effort active-goal tracking. Starts the dashboard automatically on load. Needs the [mcp] extra.
  • goaltree/dashboard.py -- the live, interactive web dashboard (FastAPI + vis-network, single file, no build step), including the hook endpoint Claude Code's PreToolUse hook calls. Needs the [mcp] extra.
  • pyproject.toml -- packaging metadata; also defines the goalt-mcp console script, which is just python -m goaltree.mcp_server under a shorter name.
  • .claude-plugin/plugin.json, .claude-plugin/marketplace.json, .mcp.json, hooks/hooks.json -- plugin packaging so the whole thing installs with two commands (see above).
  • commands/start.md -- the /goalt:start slash command that onboards GoalT onto an existing codebase.
  • bootstrap.sh -- the plugin's actual entry point (see .mcp.json). Finds a Python 3.10+ interpreter and auto-installs dependencies on first run, so installing the plugin genuinely requires nothing beyond the two /plugin commands above -- no separate clone or pip install step, and no machine-specific path hardcoded anywhere.
  • tests/ -- 62 tests covering the core engine, the dashboard's API/hook logic, and the MCP tools end-to-end (via a real MCP client, the same way Claude Code talks to it). See "Running tests" below.

No CLI yet -- a natural next step if there's interest.

Running tests

python3 -m pip install -e ".[dev]"
pytest

62 tests across three files:

  • tests/test_goal_tree.py -- the core engine (multi-parent value propagation, cycle handling, artifact linking, file matching, save/load round-trips), no I/O.
  • tests/test_dashboard.py -- pure helper functions, real git fixtures for uncommitted-changes detection, the VS Code diff fallback chain (mocked, no GUI needed), and the FastAPI endpoints via TestClient.
  • tests/test_mcp_server.py -- integration tests: a real MCP client talking to a real goaltree.mcp_server subprocess over stdio, covering the actual tools (create_tree, add_goal, link_artifacts, set_active_goal, load_tree/persistence, reset_tree). Slower (~30s total) since each test spawns a real process, but it's what actually exercises the tool layer Claude Code calls into.

Known open questions

Being upfront about this instead of overselling it:

  • Convergence with LLM-driven weights. The deterministic fallback always converges by construction. Whether repeated LLM-driven re-weighting stays stable across many edits on a large graph hasn't been proven, only observed on small examples.
  • Global value isn't conserved. Because a node can have multiple parents, the sum of all node values in the graph is not 1.0 overall — only locally, per parent, do children's weights sum to 1.0. That's intentional (it's the mechanism that makes "more real dependencies = more pull" work), but worth understanding before reading too much into raw numbers.
  • Cost at scale. With a real LLM plugged in, every add_goal call can trigger one redistribution call per affected parent. On a large, deep graph that could mean a lot of API calls per edit. Caching / batching isn't implemented yet.
  • No benchmark yet. This hasn't been compared against classical prioritization methods (AHP, weighted scoring, plain OKR cascading) on a real backlog. That comparison is a natural next step, not a claim already made.
  • Cycle detection is currently a defensive backstop, not an active safeguard. Through the public add_goal API alone, a cycle is impossible by construction (a new node has no outgoing edges yet). The check matters for a planned future feature — linking two already-existing goals together — where cycles become genuinely reachable.
  • Startup auto-load is a guess, not a guarantee. At server startup, GoalT tries loading a saved tree using its own process's working directory as a guess for project_root -- this works when Claude Code happens to launch the MCP server rooted at the project, but isn't guaranteed. The reliable path is the explicit load_tree tool, which the system instructions tell Claude to call first with the actual project root before assuming no tree exists.
  • Relationship to existing work. The value-propagation mechanism is closely related to PageRank-style algorithms on DAGs. If you know prior art that solves this better, please open an issue — genuinely interested, not trying to reinvent something that already exists.

Contributing

Issues and PRs welcome — see CONTRIBUTING.md. Breaking it is as useful as extending it; if you find a case where the graph produces something wrong or unstable, that's exactly the kind of feedback this needs right now.

License

Apache 2.0 — see LICENSE. Use it, fork it, build on it, commercial or not.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

goaltree-0.6.0.tar.gz (43.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

goaltree-0.6.0-py3-none-any.whl (33.7 kB view details)

Uploaded Python 3

File details

Details for the file goaltree-0.6.0.tar.gz.

File metadata

  • Download URL: goaltree-0.6.0.tar.gz
  • Upload date:
  • Size: 43.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.11.14

File hashes

Hashes for goaltree-0.6.0.tar.gz
Algorithm Hash digest
SHA256 c7ebc511072ecb4fd016a8f7967fe1ec8ec06633fa5ea50527aaf6f27a94047a
MD5 d6322f3e514fbc804be03f6ac26a2400
BLAKE2b-256 c8299a63f6bbf29ab29f03336609b2ff29eb27c05b44f34a0f35dec5f498482c

See more details on using hashes here.

File details

Details for the file goaltree-0.6.0-py3-none-any.whl.

File metadata

  • Download URL: goaltree-0.6.0-py3-none-any.whl
  • Upload date:
  • Size: 33.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.11.14

File hashes

Hashes for goaltree-0.6.0-py3-none-any.whl
Algorithm Hash digest
SHA256 938a814f7fc0c8612e027ae3760e3ea07b95abbe9c8d6b8be16aaaebe3fdeb8b
MD5 39141b7ee30da8e8e8192575f2c03be8
BLAKE2b-256 e29dd029dc170ff9ddeed115748d4f31b09365b4575def2581dbc6b2ea5ef36d

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page