A Git-native requirements management tool with a scope-avalanche grounding layer: permanent UIDs, one file per item, typed links, suspect detection, and a CI-gating check.
Project description
throughline
A Git-native requirements management tool with a built-in scope-avalanche
grounding layer. Requirements live as one small YAML file per item under
version control; a check command validates the whole graph and gates CI.
Two ideas, one system:
- throughline core — permanent, position-independent UIDs (never renumbered,
never reused; deletion is a tombstone), one file per item, typed directed
links, SHA-256 normative fingerprints that turn a real content change into a
suspect link, and a
checkCLI with stable exit codes. - grounding layer — every non-root item must justify itself by reaching a
root ("why"); AI-generated items enter
proposedand must be ratified by a human; assumptions are first-class and invalidating one cascades suspect across its blast radius. Unbounded generation yields a bounded, ranked review queue instead of silent sprawl.
The build contract is the throughline spec in
docs/referenced-resource/ (docs 04 system
requirements, 06 data format, 07 architecture).
New here?
HOW_TO_USE.mdis a fifteen-minute hands-on quick start: scaffold a project, add three linked requirements, watch the validator reject an ungrounded graph, fix it, and trace a requirement back to its reason for existing. Curious how the workflow relates to test-first practice?HOW_IDD_DIFFERS_FROM_BDD.mdexplains Intent-Driven Development and why it is the why axis to BDD's what.
How it differs
Doorstop, StrictDoc, and OpenFastTrace already do Git-native, plain-text
requirements with permanent IDs and link-based traceability — and so does
throughline's core. The difference is the grounding layer. Those tools trace
links once the items exist; none of them gate on whether an item has any
reason to exist, or on whether a machine-generated item has been signed off by
a person. throughline makes both a build failure: an item that reaches no root
is an orphan, a delivery root nobody serves is unserved-root, and an
AI-proposed item stays unratified until a human ratifies it. That is the axis
this tool adds — not "are the links well-formed?" but "should this scope exist
at all, and who took responsibility for it?" It is why throughline is built for
an age where a machine can generate a hundred plausible requirements an hour:
generation is bounded by a ranked review queue instead of silent sprawl.
Install
throughline is pure Python (one dependency, pyyaml) and needs Python >= 3.11
(for the stdlib tomllib). The same steps work on Linux, macOS, and Windows —
only how you obtain Python and put scripts on PATH differs.
Recommended — pipx (installs the CLI in its own
isolated environment):
pipx install throughline
Prefer the bleeding edge? Install straight from Git instead:
pipx install "git+https://github.com/rhodium-org/throughline.git"
Per-OS notes:
- Linux — system Python is often "externally managed" (PEP 668); don't
pip installinto it. Usepipx(sudo apt install pipx/pacman -S python-pipx) or a virtual environment. - macOS —
brew install python pipx && pipx ensurepath, then install as above. - Windows — install Python 3.12 from python.org or
winget install Python.Python.3.12(tick Add to PATH), thenpython -m pip install --user pipx && pipx ensurepath. Bothtl.exeandthroughline.exeare generated.
Either way you get tl (and the long form throughline) on your PATH. For a
local checkout you can develop against, see CONTRIBUTING.md.
Or run it containerised, no local Python at all:
docker build -t throughline .
docker run --rm -v "$PWD/my-project:/work" throughline -C /work check --strict
The format
A project is a directory: throughline.toml (config) + per-register folders, each
with a .register.yml manifest and one <UID>.yml per item.
uid: FR-0022 # permanent, immutable, never reused
type: requirement
status: approved
title: Guided setup wizard
text: The system shall walk new users through a 3-step setup.
normative: true
links:
- target: BN-0003 # this requirement derives from a business need
type: derives_from
- target: ASM-0002 # …and depends on an assumption's validity
type: assumes
stamp: sha256:… # target fingerprint when last confirmed (suspect tracking)
Roots (intent, business_need, risk, constraint, assumption,
non_goal) may exist ungrounded — they are the roots of "why". Everything else
must reach a root through a grounding link (derives_from, mitigates,
implements, verifies), which together form a DAG — circular justification is
rejected. A non_goal records deliberately-excluded scope: it is a root but
not a delivery root, so nothing has to derive from it and it is never flagged
unserved. Non-goals surface in tl context so excluded scope is visible to
reviewers and agents rather than living only in prose. throughline never tries to
detect items that "violate" a non-goal — that judgement stays with a human.
CLI
tl init [--name NAME] # scaffold a project
tl register new <PREFIX> <dir> [--parent P] # add a register
tl new <PREFIX> [--uid U] [--type T] [--ground UID] # allocate + create (grounded at birth)
tl link <SRC> <DST> --type <kind> [--stamp] # add a typed link
tl delete <UID> --reason "…" # tombstone (never erased)
tl review [<UID> | --all-clean] # mark reviewed at current content
tl check [--strict] [--format json] # validate the graph — the CI gate
tl trace <UID> [--direction in|out] [--depth N]
tl blast <UID> [--format json] # everything depending on an item
tl shape [--format json] # observed (from)-[link]->(to) triples
tl diagram [types|transitions|both] # Mermaid of the model / lifecycle
tl docs [FILE ...] [--at REF] # inject graph content into marked Markdown regions
tl docs [FILE ...] --check # CI gate: fail if any document is out of date
tl context # agent-facing brief (IDD + this project's model)
tl ratify <UID> --by <who> # a human takes accountability
tl invalidate <UID> --reason "…" # falsify; cascade suspect
tlandthroughlineare the same command —tlis the short alias, and every subcommand above works under either name.
Exit codes are a stable contract: 0 ok · 1 findings at error severity ·
2 usage/internal error. So tl check drops straight into a pre-commit hook
or CI gate — an ungrounded, unserved, or otherwise invalid graph fails the build.
What check enforces
Upward and downward coverage are independent and both matter:
| Rule | Meaning |
|---|---|
orphan |
a non-root item with no grounding chain to a root |
unserved-root |
a delivery root nobody derives from / mitigates |
grounding-cycle |
circular justification |
dangling-link / deleted-link-target |
link to a missing/tombstoned item |
uid-grammar / uid-collision |
malformed UID, or one UID in two places (merge) |
tombstone-deleted |
a retired UID's tombstone was erased (bad merge / stray git rm) |
schema |
missing required attr or out-of-enum value |
suspect-link |
target changed since the link was last confirmed |
unreviewed |
item content changed since last review |
unratified |
AI-origin item still proposed |
ambiguous |
flagged ambiguous — blocked from ratification |
coverage |
a declared [[rules.coverage]] link requirement is unmet |
unpublished |
a normative item is referenced by no published document (inert until [docs] paths are set) |
Every rule's severity is configurable per project under [rules]; --strict
promotes every warning to an error for CI.
Try it
The examples/grounding-demo/ project is a small, fully
grounded graph (intents, a business need, a risk, a constraint, an assumption,
requirements, an NFR, and verifying tests):
tl -C examples/grounding-demo check --strict # green, exit 0
tl -C examples/grounding-demo trace FR-0055 # walk its justification tree
tl -C examples/grounding-demo blast ASM-0002 # what a bad assumption would take down
Self-hosting — throughline's own requirements
throughline manages its own spec. The requirements/ project is
throughline's vision, goals, user requirements, system requirements, and NFRs seeded
as throughline items, with the full grounding chain wired up
(SR/NFR --implements--> UR --derives_from--> goal --derives_from--> vision):
tl -C requirements check --strict # green, exit 0 — the tool gates its own scope
tl -C requirements trace SR-0001 # walk a system requirement up to the vision
This is the discipline the tool exists to provide, applied to the tool itself: a new system requirement that doesn't justify itself against a user requirement — or a user requirement that doesn't derive from a goal — fails the build. Both the demo and the self-host graph are gated in CI and by the pre-commit hook.
Grounding operations
- ratify — a human takes accountability. Refused for ambiguous or ungrounded items: the two states that must never be signed off.
- invalidate — falsify an assumption (or any node): it is rejected and every
transitive dependent is marked
suspect(its blast radius).
Testing & gates
pytest -q # model, UID, fingerprint, validate, grounding
tl -C examples/grounding-demo check --strict # the demo graph gate (exit 1 = broken)
tl -C requirements check --strict # throughline's own requirements (self-host gate)
.pre-commit-config.yamlruns the gate on commits touching either project (demo and self-host). Enable withpre-commit install..github/workflows/ci.ymlruns the tests, both grounding gates, and a Docker build + image smoke-test on push/PR.
What this is
M0 — Core: UID model, one-file-per-item storage, typed links,
fingerprints/suspect, the validation pipeline, the grounding layer, and the
tl CLI. Not included: baselines/diff, HTML/PDF publish, and CSV/ReqIF
import-export. Assumption items carry provenance attributes (attrs.owner /
attrs.last_validated / attrs.confidence) alongside their content.
throughline is early software (alpha) and unfinished by design — see
ROADMAP.md for what's built, what's next, and where help is most
useful.
Contributing
Contributions are welcome. CONTRIBUTING.md gets you to a
checked development environment; ROADMAP.md lists good first work;
all participation is under the Code of Conduct. To report a
vulnerability, see SECURITY.md.
License
Copyright © 2026 Time Back Solutions Limited. Released under the
Apache License 2.0 — see LICENSE and NOTICE. Provenance
and prior-art are recorded in PROVENANCE.md.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file throughline-0.4.0.tar.gz.
File metadata
- Download URL: throughline-0.4.0.tar.gz
- Upload date:
- Size: 75.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a495347a83d9ab9b09bdd8ef2d058f21407700e41f773a6e91909ae58f7e6b90
|
|
| MD5 |
690a5f9bde2525aefc2303de399a084b
|
|
| BLAKE2b-256 |
7cced13f8c5ab6326b998bff6be8969ce58e9eb0d721822b0d9d35357cab4e41
|
Provenance
The following attestation bundles were made for throughline-0.4.0.tar.gz:
Publisher:
release.yml on rhodium-org/throughline
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
throughline-0.4.0.tar.gz -
Subject digest:
a495347a83d9ab9b09bdd8ef2d058f21407700e41f773a6e91909ae58f7e6b90 - Sigstore transparency entry: 2165163467
- Sigstore integration time:
-
Permalink:
rhodium-org/throughline@2039a239a3885b0b975a7ddd1a14632203eee450 -
Branch / Tag:
refs/tags/v0.4.0 - Owner: https://github.com/rhodium-org
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@2039a239a3885b0b975a7ddd1a14632203eee450 -
Trigger Event:
release
-
Statement type:
File details
Details for the file throughline-0.4.0-py3-none-any.whl.
File metadata
- Download URL: throughline-0.4.0-py3-none-any.whl
- Upload date:
- Size: 58.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2665e8c861b16ed350509b324977e2c85ac9a92bfd07f12b85d802a35c5b81aa
|
|
| MD5 |
b2f7256d2ff910968cf262aaef93448a
|
|
| BLAKE2b-256 |
01aea14796eac4564740fb7c53cef723816898daed9c192b40a5c267ea92320a
|
Provenance
The following attestation bundles were made for throughline-0.4.0-py3-none-any.whl:
Publisher:
release.yml on rhodium-org/throughline
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
throughline-0.4.0-py3-none-any.whl -
Subject digest:
2665e8c861b16ed350509b324977e2c85ac9a92bfd07f12b85d802a35c5b81aa - Sigstore transparency entry: 2165163502
- Sigstore integration time:
-
Permalink:
rhodium-org/throughline@2039a239a3885b0b975a7ddd1a14632203eee450 -
Branch / Tag:
refs/tags/v0.4.0 - Owner: https://github.com/rhodium-org
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@2039a239a3885b0b975a7ddd1a14632203eee450 -
Trigger Event:
release
-
Statement type: