trusty-git-analytics · Acquisition due diligence
tga audit
One command walks the git history of the repositories your config already names, and renders a technical due-diligence report for someone deciding whether to buy the codebase. The report has eight sections, and the parts it cannot fill are named as gaps rather than scored.
- Command
- tga audit
- Stages
- 8
- Flags
- 6, all optional
- Output
- up to 18 files
- Prompts
- none
The gaps are printed, not filled in
A due-diligence report is read by someone deciding whether to buy the thing it describes. The failure that matters there is not a missing number. It is a number nobody measured, printed as though somebody had.
tga audit has no PERFORMANCE dimension and no COST dimension — nothing
in the pipeline measures either one. So the report declares both as gaps rather than scoring them
off a proxy.
Failure works the same way. Point the sweep at a config with no JIRA project key and the jira sync stage fails. That failure becomes a named line in Gaps & Caveats. The alternative
— a zero in a cell — is indistinguishable from a project that genuinely had no JIRA
activity, and the reader has no way to tell which one they are looking at.
Every report-quality bug fixed in the last milestone was that same shape: a partial signal rendered as an authoritative statement.
The failure you will actually hit
no JIRA project scope: pass --project <KEY> or set jira.project_key in config.yaml
This is the stage that most often fails on an unattended run. It does not stop the sweep, and it does not become a zero.
What you need installed
Two binaries, and one daemon you can skip. tga collects and
classifies; trusty-review renders the report at the end of the
sweep. They meet at a file — the manifest — rather than at a library edge, which is why the
renderer is a separate install rather than something tga carries.
shell
curl -sSf https://raw.githubusercontent.com/bobmatnyc/trusty-tools/main/install.sh | sh tctl install tga tctl install trusty-review
Homebrew and cargo install from a checkout both work too; the other install paths are on the home page. Whatever route you take, the sweep looks for trusty-review on your PATH — set TRUSTY_REVIEW_BIN to a full path if it lives somewhere PATH cannot
see it.
trusty-review
Without it the sweep still runs and still writes manifest.toml, then stops with an error naming that file.
Nothing collected is lost — see the recovery command below. A copy too old to
require inference is rejected before stage 1, with the upgrade command, rather
than delivering a report with no written analysis.
OPENROUTER_API_KEY
The renderer writes the report's analysis with a model, so an audit cannot finish
without a key. It is checked before stage 1, not at the end, so an unset one costs
you the error and not the sweep: export OPENROUTER_API_KEY=…
trusty-analyze
The renderer asks a running analyze daemon for the findings and the complexity distribution, and shrugs when it is absent: the report is produced either way, and the sections it feeds become declared gaps instead.
Point it at a repository set
tga audit audits local checkouts that a config file names. It
does not discover or clone anything, so this step is the one that decides what gets audited. tga install is an interactive wizard that writes the config for you;
a hand-written one can be as small as a list of repository paths, because every other section
has a default.
-c, --config <FILE> is global on tga, so it goes before the subcommand. A missing config logs a
warning and runs on defaults rather than failing — which is worth knowing, because an audit
of nothing is a report of nothing.
Running it
Six flags, all optional, nothing interactive. Once it starts it never prompts, confirms, or waits for input — start it and walk away.
shell — defaults
tga audit
Bare, it reads ./config.yaml and writes ./audit-output. That is the whole minimal invocation.
shell — named engagement
tga --config config.yaml audit \ --org acme --client "Acme Holdings" --analyst "J. Reviewer" \ --weeks 26 --output ./acme-dd
| Flag | Effect |
|---|---|
--org <ORG> | The organisation under audit. Metadata only — it titles the report and nothing else. |
--title <TITLE> | Defaults to <org> — Technical Due Diligence, or Technical Due Diligence with no --org. |
--analyst <NAME> | Renders as not stated if omitted. |
--client <NAME> | Same — absent is recorded as absent. |
-o, --output <DIR> | Where the audit writes. Defaults to ./audit-output. |
--weeks <N> | Limit collection to the last N ISO weeks. |
What --org is not
It does not discover repositories. The sweep audits whatever local checkouts the resolved
config already names, and --org only reaches the report's title
block.
Where the report comes out
Everything lands in the output directory — ./audit-output unless --output says otherwise. The run ends by printing the paths it
wrote under Report artifacts, so the last lines
on your terminal are the deliverable. The Markdown file is the report; open it first.
If the sweep stopped at the render — the renderer was not installed, or the model call failed — the manifest survived it, because it is written before the renderer is called. Fix the cause and run the last stage by hand; this is exactly what the sweep would have run:
shell — render an existing manifest
trusty-review report \ --manifest ./audit-output/manifest.toml \ --analyze --synthesize --out ./audit-output
Eight stages, in the order the data flows
The numbering is real: each stage writes what the next one reads, which is why they run in this order and not another. A stage that fails is recorded and named in Gaps & Caveats, and the run continues.
-
collect— walks the configured repositories intocommitsvia git2. -
classify— runs the four-tier classification cascade over those commits. -
jira sync— ingests JIRA transitions and comments. -
deployments collect— deploy events intofact_deployments. -
incidents collect— incidents intofact_incidents. -
dora— reduces those two fact tables to the four DORA keys. -
pr-metrics— per-engineer pull-request metrics; writespr-metrics.csv. -
report— renders tga's own CSV, JSON and Markdown.
No stage aborts the run
Every stage's result is recorded, never propagated. A stage that fails is marked failed, the sweep moves to the next one, and the failure surfaces as a named gap in the report instead of a halt. One thing stops a sweep: a pre-flight failure creating the output directory.
That is what makes an unattended run worth starting. A pipeline that stops on the first unreachable source produces nothing; this one produces a report whose missing pieces are labelled.
What lands in the output directory
Up to 18 files, from three producers.
| From | Files | What |
|---|---|---|
report stage | 14 | 9 CSV, 4 JSON, 1 Markdown. |
pr-metrics stage | 1 | pr-metrics.csv. |
| the seam | 1 | manifest.toml — what tga hands to trusty-review. |
| trusty-review | 2 | {slug}.md and {slug}.json — the due-diligence
report itself. |
The report, section by section
Eight sections, in this order. A model writes the executive summary, the top-risk rationale, and the RED/AMBER finding prose, working only from what the sweep collected — every figure it cites is checked against that data and the sentence is dropped if the figure is not there. Section 2 falls back to a roll-up composed from the report's own counts whenever that check rejects the written one.
| § | Section |
|---|---|
| 1 | Report Metadata |
| 2 | Executive Summary, with Top Risks |
| 3 | Scoring Model Normalization |
| 4 | Per-Application Scorecard |
| 5 | Findings by Severity
|
| 6 | Risk Registers
|
| 7 | Graph-Ready Data Appendix |
| 8 | Gaps & Caveats |
§1 in full, and §4's tech stack, lines of code, and frameworks.
§5, §6.1, and §7's complexity_distribution and loc_by_technology.
§4 Benchmark Position, §6.2, §6.3, §6.4, §6.5, §6.6 — no data source behind any of them, and the report says so rather than scoring them.
Red, amber, green — and what routes a finding there
The colours are the report's own convention, and the mapping is mechanical: the diagnostic's own severity decides, nothing else.
| Band | Diagnostic severity | How it renders |
|---|---|---|
| Red | error · critical | §5.1, full detail. |
| Amber | warning · high | §5.2, compact. |
| Green | everything else | §5.3, topic list only. |
The ceiling that matters
A refactor suggestion caps at Amber. It can never come out Red, no matter what the underlying tool called it — because "extract this method" is advice, and a buyer reading a RED line is entitled to assume something is broken.
What the last fix actually changed
Measured on one run, over the ripgrep repository, before and after the report stage was corrected.
| Measure | Before | After |
|---|---|---|
| RED findings | 20 | 0 |
| AMBER findings, each carrying real numbers | 0 | 20 |
| Non-code components scored | 2 | 0 |
| Complexity buckets sum to | 1,000 | 4,328 |
The 20 pre-fix RED entries were all "Extract method" refactor suggestions misrouted into
RED. The two non-code components were CHANGELOG.md and FAQ.md, scored as if they were applications. The complexity
buckets summed to a round 1,000 instead of the 4,328 units actually counted.
All three are the same defect wearing different clothes: output that looked like a measurement and was not one.
Scope of that evidence
These numbers are the ripgrep run only. The trusty-tools audit was not re-run after the fix, so nothing here says the same before-and-after holds on a second codebase.
What this does not do
The buyer's alternative is a tool that would have guessed at all six of these. Read this section as part of the pitch, not as a disclaimer at the bottom.
It does not find or clone repositories
Every entry in the sweep is a local checkout that the resolved config already names.
Discovery is open work (#5215); until it lands, naming a GitHub organisation or a
Bitbucket workspace in --org gets you a report title, not a repository
list.
There is no engineering-velocity section
DOC-67 §8 specifies one; it is not implemented (#5241, #5242). DORA is computed at stage 6 and never reaches the report. If you need deployment frequency or change failure rate in the deliverable, this does not produce it today.
§6.1 is linter output, not a security scan
It carries general-purpose linter findings — clippy, ruff, biome, rubocop, PMD. A linter
flagging an unwrap() is a different claim from a scanner flagging
SQL injection or a hardcoded credential, and this section is only ever making the first one.
Six registers have no data source
§4 Benchmark Position, and §6.2 through §6.6 — CVE exposure, license and IP risk, obsolescence, cloud readiness, remediation economics. Each is declared a gap. None is estimated.
agentic_pct counts markers, not AI
The undercount that made this figure unquotable is fixed (#5249, #5403): measured against tga's own history the catch rate went from 47.70% to 91.04%. What the number means did not change. Detection is marker-based only — the run's own disclosure line says so — so commits whose trailers or footers were stripped, squashed, or rewritten are indistinguishable from human commits, and a low share means "no markers emitted", not "no AI assistance". Twelve markers cover seven tool labels, and five of those (Devin, OpenHands, Aider, Copilot, Cursor) are exercised only by synthetic tests, because this repository's history contains none of their markers. Read it as a floor on marker-emitting work, not as a provenance figure.
No PERFORMANCE or COST dimension exists
Nothing in the pipeline measures runtime behaviour or spend, so neither is scored. Both appear in Gaps & Caveats, which is the whole design: the report would rather be visibly incomplete than quietly wrong.
Start to finish
Four steps to a report
- Install
tgaandtrusty-review. - Write
config.yaml, by hand or withtga install. - Run the sweep. It will not ask you anything.
- Open the Markdown file whose path it printed last, and read Gaps & Caveats before the scores.
shell
tga audit --org acme --output ./acme-dd