Repository navigation
Releases: trendvidia/caliper
Release list
Caliper v1.7.0
A load in which no package type-checks can now return an engine instead of an error, through the new EngineOptions.KeepWhenAllFail. Off by default, so existing callers are unchanged.
Added
EngineOptions.KeepWhenAllFail: a load in which no package
type-checks returns an engine instead of the errorpackage errors: ….Packages()is empty andFailed()holds every package with its
errors. It is for callers that load a few packages of a module and
want a broken one described as a whole module's load would describe
it: alidade reloading a worktree's changed packages
(belluikit/alidade#41). A load none of whose packages has a Go file
is still an error. Off by default.
Changed
- Every source file carries its license header:
SPDX-License-Identifier: MITand the copyright line. The generated
protobuf Go gets it from its.proto. Test fixtures undertestdata
are left as they were. - The copyright holder in
LICENSEis spelled "TrendVidia, LLC.", as in
the organization's other repositories.
Caliper v1.6.2
Caliper is now public and MIT-licensed. This release adds the LICENSE file, so a module pinned to this tag carries it, and every release has its binaries attached again. The analysis itself is unchanged since v1.6.1.
Changed
- Caliper is MIT-licensed, with a
LICENSEfile at the root. The
contributor agreement already said so; the repository did not. - Install docs no longer assume a private repository: no
GOPRIVATE,
no authenticated release downloads, andbrew install trendvidia/tap/caliperwithoutHOMEBREW_GITHUB_API_TOKEN(the tap
is public too). - CI runs on GitHub-hosted Ubuntu and macOS runners with stock Go
1.27.2, replacing the self-hosted runner and its go-plus check. Stock
Go and go-plus give the same result locally: 379 tests run, 379 pass,
none skipped.
Build
- Every release gets its binaries again. v1.4.0 through v1.6.1
shipped none, though the install docs promised them. A release
workflow now runsscripts/build-release.shwhen a release is
published, for macOS / Linux / Windows × amd64 / arm64, with a
checksums.txt. Binaries are built with Go 1.27.2, the newest Go
caliper supports, because a binary refuses a newergocommand than
the one it was built with (#35). v1.6.1's binaries were added after
the fact with the same script.
Caliper v1.6.1
Go 1.27 compatibility fix: caliper now requires x/tools v0.51.0. On v1.6.0, a program reaching a method with type parameters panicked the call graph, and the export-data load ended the process on go-plus 1.27.2.
Fixed
-
The call graph no longer panics on a method with type parameters
(#40). Go 1.27 allows methods with type parameters of their own, and
the standard library has one,math/rand/v2's(*Rand).N. Any
program that reached such a method madeBuildInterProceduralContext
panic with the type parameter's name (panic: Int) inside x/tools'
Program.RuntimeTypes. caliper now requires x/tools v0.51.0, which
skips those methods there; calls to them are edges in the graph. -
The export-data load works on go-plus 1.27.2. With x/tools
v0.44.0,DepsFromExportDataon a module importing the standard
library ended the process withinternal error: package "fmt" without types was imported from .... The x/tools v0.51.0 bump above fixes it. -
A panic during call graph construction is returned as an error.
BuildInterProceduralContextused to let it end the process; the
next input x/tools cannot handle now fails the build of the context
instead.
Caliper v1.6.0
Analysis-engine release: a caller can now see which packages the load dropped and which loaded packages the call graph leaves out, and why.
Added
-
Engine.Failed()returns the packages the load dropped (#38).
Packages()leaves out every package with errors, and until now
nothing recorded that they existed, so a caller describing the whole
module could not tell a package that failed from one that does not
exist.Failed()returns them with theirErrorsand whatever
go/packages kept: the syntax that parsed, and for a partly
type-checked package, theTypesscope andTypesInfoof the
declarations that resolved. A directory whose files a build
constraint all excludes is still absent, because./...does not
match it. -
InterProceduralContext.Skippedlists the loaded packages left out of
the SSA program, each with theCause: the package whose error outside
a function body put it out of reach. Such a package is inPackages()
and type-checked cleanly, but imports, possibly transitively, a package
with a declaration or syntax error, so it has no functions and no
call-graph edges. Before, that was silent.
Caliper v1.5.0
Analysis-engine release: a load mode that takes dependency types from export data, three correctness fixes in how packages and findings are classified, and a refusal to run under a toolchain newer than the binary.
Fixed
-
A load refuses a newer toolchain instead of answering wrongly (#35). go/packages asks for complete types for
every direct import of a package it type-checks from source, and fills
them from export data; when that read fails it callslog.Fatalffrom
inside its importer, which no caller can recover — an MCP server dies
with it. A go command from a newer release than the Go this program was
built with is exactly such a failure. The load now stops before
starting, with an error naming both versions and what to do about it.
Measured on steward with a caliper built by go1.26.7 against go1.27.1's
go list: before, the process exited 1 withinternal error: package "math/rand/v2" without types was imported from "google.golang.org/grpc/internal/transport"; now it returns the
refusal. The default load is refused too, for a different reason: it
completes under skew, but the older type checker cannot process the
newer toolchain's sources, so the same run left 15 of steward's 117
packages in the SSA program and reported no error — a call graph
missing 87% of the module. Unskewed behaviour is unchanged, 117 of 117
packages before and after, in both modes. Export data unreadable for
another reason, a truncated build cache say, can still reach the same
fatal; only the predictable cause is guarded. -
context_misuseno longer flags a detached context in a deferred
cleanup (#10). A deferredRollback,CloseorUnlockruns when
the function returns, including becausectxwas cancelled or timed
out, so passingctxthere skips the cleanup exactly when it is needed
most — pgx'sRollbackreturns at once on a done context and leaves
the connection in a transaction.context.Background()inside a
defer, whether deferred directly, inside a deferred closure, or as
the parent of aWithTimeoutthere, is the recommended idiom and is
not reported.context.TODO()in adeferstill is. Measured on the
repositories the issue was filed from: gameflow goes from 19 findings
to 1, and all 9 removed sites are deferred cleanups (four
tx.Rollbackin the trader store, a migrationRollback, a
conn.Close, an advisory-unlockExec, two deferred metric
decrements); govm's 5 and voya's 0 are unchanged. -
A deferred call is reported once, not twice. The CFG lists a defer
statement in the block that registers it and again in aBlockDefer
block where it runs, which is how a path query sees a deferred
UnlockorCloseon every exit; rules that scan nodes to report on
them saw both copies. On govm,unchecked_errorwithinclude_defers
gave 162 findings of which 8 were exact duplicates; on gameflow,
context_misusegave 19 of which 9 were. Both are now 0, with the
same unique findings (154 and 1 respectively). Affects
context_misuse,unchecked_error,goroutine_leakand
sql_injection;lock_violationis unchanged, since its loop feeds
path queries that need both copies. -
A dependency with a type error inside a function body no longer
drops its importers from the SSA program (#30). The program was
built withssautil.AllPackages, which skips every package go/packages
marksIllTyped— andIllTypedpropagates, so one dependency with
any error removed every loaded package importing it, transitively,
from the call graph, silently: the loaded package's own type-check was
clean and it stayed inEngine.Packages(). On steward, grpc's
internal/transportfails on go-plus 1.27.1 withundefined: http2.TrailerPrefixinside a function body, and 36 of 117 packages
had no SSA package and no call-graph nodes. Now a package is skipped
only for an error outside a function body — a parse error, a type
error in a declaration, export data that could not be read — or for
importing such a package; one whose errors are all inside function
bodies is created from its types alone, so its declarations are there
for its importers and its unfinished bodies never reach the SSA
builder. steward: 117 of 117 packages in the SSA program under the
default load, with the same 13,119 within-module edges as under
DepsFromExportData, edge for edge. Pinned on the fixture by a
dependency with a body-only error (importer analysed, calls its clean
function; the dependency's functions have no bodies) and one with a
declaration error (importer dropped, as before), under both loads.
An error is placed by its source position, so//linedirectives in
generated code cannot move a declaration error into a body; and the
notice go/packages adds when caliper was built with an older Go than
thegocommand it runs does not count as an error.
Default-load timing on steward is unchanged (load 1.6–1.7 s, call
graph 3.8–4.0 s over the now-complete 117 packages; one run of three
hit 11.4 s on a busy machine).
Added
-
EngineOptions.DepsFromExportDatatype-checks the loaded packages
from source and takes every dependency's types from the compiler's
export data (go list -export) instead of parsing and type-checking
its source. It dropspackages.NeedDepsfrom the load; under it the
SSA program is built with the loaded packages from syntax and every
dependency from types alone (#28, for trendvidia/alidade). Default
false, everything unchanged.Measured on steward (117 packages, 1,293 reached with dependencies,
warm build cache, three interleaved runs each, median and range):Load SSA + CHA call graph default 1.93 s (1.4–2.5) 3.46 s (2.5–5.1) DepsFromExportData0.99 s (0.98–1.3) 0.36 s (0.29–0.50) The first split load on a tree whose dependencies are not yet in the
build cache pays their compilation once (3.4 s on steward, where they
were).Limitation: no interprocedural analysis through dependency code. A
dependency's SSA functions have no bodies, so no call-graph edge leaves
one (steward: 8,150,734 such edges by default, 0 under the option) and
no taint flows through one. Calls from a loaded package into a
dependency are still edges to that function; dynamic calls resolve
among fewer candidates, since a package reached only through a
dependency carries just the declarations its importers reference
(steward: 176,011 edges into dependencies by default, 22,519 under the
option). A dependency that does not compile on the host's toolchain has
no export data and is type-checked from source with its bodies skipped;
it is still bodiless in the SSA program, and the loaded packages that
import it are analysed. Pinned byTestDepsFromExportData_*on a
fixture with a third-party dependency (github.com/google/uuid) and a
local one that type-checks but does not compile: the call-graph edges
among the loaded packages are identical under both modes, edge for
edge.On steward the within-module graph is not identical but a strict
superset: 13,119 edges over all 117 packages against 6,366 over 81,
because grpc'sinternal/transporthas a type error inside a function
body on this toolchain (undefined: http2.TrailerPrefix), the default
load sees it and drops the 36 packages importing it from the SSA
program, and the split load never type-checks that body. The 6,366 are
all present under the option and every extra edge touches one of the
36. The default load's drop is #30.
Caliper v1.4.0
Caliper v1.4.0
One addition, for library consumers that need a graph of a repository to not depend on the machine that built it.
Added
EngineOptions.EnvappendsKEY=VALUEentries to the load's environment, after the process environment and the engine's own settings, and survives theGOWORK=offretry. Its purpose is a build configuration the host is not:GOOS=linux,GOARCH=amd64load the files behind//go:buildconstraints a tag cannot satisfy, since GOOS and GOARCH are not tags. Empty by default;DefaultOptionsdoes not touch it. (#25, for belluikit/alidade#43)
CI
- golangci-lint pinned to v2.13.2, built for the runner's Go 1.27; v2.10.1 panicked reading its export data. (#27)
Caliper v1.3.0
Caliper v1.3.0
The interprocedural surface could not run against real code. This release fixes that, and adds what a library consumer needs to build on it.
Fixed — call-graph tools work on real code
-
They no longer crash the server. Every interprocedural tool —
find_call_sites,find_taint_flow, anything reachingEngine.InterProcedural()— panicked on any real workspace, exiting the MCP server with code 2 rather than returning an error. Thepackages.Configload mode setNeedDepsbut notNeedImports;NeedDepsonly propagates the mode into packages already inImports, andImportsitself is populated byNeedImports. Without it everypkg.Importswas empty, sossautil.AllPackagesnever created the dependency packages andprog.Build()panicked on the first unsatisfied import — which is any package importing so much ascontext. Measured before the fix: 100% of loaded packages had empty.Importsacross four repositories. (#11) -
A program with uncreated dependencies is refused, not built.
prog.Build()spawns a goroutine per package, so its panics cannot be recovered by the caller and take the process down. The precondition is now checked up front and reported as an error naming the missing import. (#11) -
find_call_sitesreturns results. It reportedtotal: 0for every input on every repository.FindCallSitesByPatternmatched the pattern against function declarations while the pattern compiler only accepts expressions, so the match loop was unreachable for every valid input. It now matches call expressions across the corpus — as the tool's own documented$x.Close()example always implied — then enriches the result with call sites the call graph knows about for each resolved callee. Measured after the fix: 138 hits for$x.Close()on protolsp, 229 for$x.String()on protocompile, 384 for$x.Close()on govm, all previously 0. (#18)
Both defects were invisible to the test suite because every interprocedural fixture was import-free (package testpkg with a bare caller/callee pair). Fixtures now import stdlib packages, so this class of regression fails the suite.
Added — for library consumers
-
EngineOptions.Testsincludes each package's test files in the load (defaultfalse). Test files are roughly half the Go source in some repositories and are where intent is documented, so a consumer building a picture of a codebase usually wants them while a linter reporting on shipped code does not. Including tests takes protolsp from 1,560 to 4,057 workspace functions in the call graph, and protoregistry from 743 to 1,269. -
Engine.GeneratedFiles,Engine.IsGeneratedFile,InterProceduralContext.IsGeneratedFuncidentify generated code.EngineOptions.SkipGeneratedfilters AST traversal only — the SSA program and call graph are built from every loaded package and are unaffected by it. That asymmetry was undocumented and is a trap for anything walking the call graph: generated functions are 35% of protolsp's workspace functions and 45% of protoregistry's withSkipGeneratedat itstruedefault. Behaviour is unchanged, now documented and pinned by a test, and filterable by consumers that do not want it.
Build
golangci-lintexcludesSA5011in test files. The guard isif x == nil { t.Fatal(...) }, and the CI runner's staticcheck does not derive thattesting.T.Fatalterminates, so it reported the guarded deref as a nil dereference across 40 sites in 8 files. Scoped to_test.goand that one check.
Install
gh release download v1.3.0 --repo trendvidia/caliper --pattern 'caliper-darwin-arm64'
chmod +x caliper-darwin-arm64Verify with checksums.txt. caliper-* is the MCP server; caliper-analyze-* is the single-shot CLI.
Caliper v1.2.0
Caliper v1.2.0
Cross-method lifecycle rules (issue #8), plus the go install version-reporting fix that landed after v1.1.1. Caliper now exposes 26 MCP tools across seven categories.
Added — cross-method lifecycle rules
The bellui pre-v1 audits showed the properties worth checking in a GUI toolkit are cross-method, while all analyses were function-local. Three new capabilities close that gap:
check_paired_calls— type-scoped pairing rule: a match offirst_patternin any method of a type requires a match ofsecond_patternsomewhere in the type's method set, or in a companion type its methods construct (the widget→renderer link). Pairs by field identity when both patterns share a metavariable bound to a receiver field, lenient otherwise —$x.Start()on one field is not excused by$x.Stop()on a different one, but an unresolvable binding never produces a false positive.find_stale_capture— capture-at-create vs re-read-at-refresh: exported fields copied in a capture method (CreateRenderer) and never re-read in the re-read method (Refresh) of the type or its constructed companions.find_patterngainsinside/not_insideenclosing-context filters:"go","defer","callback_of:<pattern>","call:<pattern>". Expresses goroutine-context call discipline like "widget mutation insidego/time.AfterFunccontexts must be wrapped inui.Do(...)" in one call. Context is lexical: code in a named function called from agostatement elsewhere does not count as "inside go".
Both new tools are whole-program analyses and honor //caliper:ignore suppressions and .caliper.pxf severity overrides like every other check.
Fixed
go install-ed binaries report their version instead ofdev.go install pkg@versionbuilds from the module cache and records novcs.*settings, soresolveVersionnow falls back toMain.Version. Local builds keep reportingdev-<rev>[-dirty].- Download instructions that actually work:
docs/getting-started.mdnow documentsgh release download(with a raw-curlasset-endpoint equivalent and achecksums.txtverification step) instead of the browser-download URL, which 404s for private repos.
Install
Binaries for macOS / Linux / Windows × amd64 / arm64, built CGO_ENABLED=0 with -trimpath, stamped with -X main.Version=v1.2.0. caliper is the MCP server; caliper-analyze is the single-shot SARIF/JSON CLI.
gh release download v1.2.0 --repo trendvidia/caliper -p caliper-darwin-arm64
chmod +x caliper-darwin-arm64 && sudo mv caliper-darwin-arm64 /usr/local/bin/caliperOr:
brew install trendvidia/tap/caliper # macOS
go install github.com/trendvidia/caliper/cmd/caliper-mcp@v1.2.0Full details in CHANGELOG.md.
v1.1.1
Caliper v1.1.1
A fix release for v1.1.0, plus the prebuilt binaries the docs have always promised.
Fixed — go install works again
v1.1.0 was tagged at a commit whose go.mod still carried two replace directives, and Go refuses to install any module whose go.mod contains them:
The go.mod file for the module providing named packages contains one or
more replace directives.
So the command documented in the README failed outright, for both @latest and @v1.1.0. Homebrew was never affected — it builds from the release tarball, where the replaces resolved against the in-tree vendor/. v1.0.21 had no replaces and installed fine, so this regressed between there and v1.1.0.
If you are on v1.1.0, there is nothing to reinstall unless you use go install — the binaries Homebrew produced from v1.1.0 are correct.
Added — real release binaries
docs/getting-started.md has always documented downloadable binaries for six platforms, but no release ever carried a single asset and the documented curl URL returned 404. That's fixed: this release ships them.
caliper is the MCP server. caliper-analyze is the single-shot SARIF/JSON CLI added in v1.1.0. Both are built CGO_ENABLED=0 with -trimpath, stamped with -X main.Version=v1.1.1, for macOS / Linux / Windows × amd64 / arm64. checksums.txt accompanies them.
trendvidia/caliper is a private repo, so assets need an authenticated download — a plain curl against a github.com/.../releases/download/... URL returns 404 even with a token, because those URLs authenticate by session cookie rather than by header. Use gh:
gh release download v1.1.1 --repo trendvidia/caliper -p caliper-darwin-arm64
chmod +x caliper-darwin-arm64 && sudo mv caliper-darwin-arm64 /usr/local/bin/caliperDownloaded binaries report v1.1.1. Binaries obtained via go install still report dev — a separate bug in resolveVersion, fixed on main after this release was cut.
Also
caliper-analyzeis documented in the README and getting-started install sections. It shipped in v1.1.0, but onlycaliper-mcpwas mentioned.vendor/is gone from the repo (505 files, 6.2 MB). It existed only because protowire-go was a private module and Homebrew's sandbox couldn't fetch it; that repo is public now. Release tarballs from v1.1.1 onward are no longer self-contained and resolve dependencies from the module proxy.go.modhas zeroreplacedirectives. protowire-go is pinned to v1.3.2 andgoogle.golang.org/protobufto stock upstream v1.36.11.- The README's
GOPRIVATEnote blamed the privateprotowiredependency. protowire-go is public now;GOPRIVATEis still needed, but only becausetrendvidia/caliperitself is private.
Install
brew install trendvidia/tap/caliperOr from source:
GOPRIVATE=github.com/trendvidia/* go install github.com/trendvidia/caliper/cmd/caliper-mcp@v1.1.1
GOPRIVATE=github.com/trendvidia/* go install github.com/trendvidia/caliper/cmd/caliper-analyze@v1.1.1Full changelog: v1.1.0...v1.1.1
v1.1.0
Caliper v1.1.0
Three months and 60 commits since v1.0.21. Headline: a new single-shot CLI for CI use, a large noise-reduction pass on find_unchecked_error, cross-reconnect result caching, and a return to stock upstream mcp-go.
New — caliper-analyze, a single-shot CLI
The MCP server is built for LLM-driven interactive use; its session model is pure overhead when a consumer just wants one analysis and a report. caliper-analyze spawns, analyzes, writes SARIF to stdout, and exits — which is what CI gates, reviewdog, and GitHub Code Scanning uploads all actually want.
caliper-analyze -workspace . -format sarif > results.sarifFlags: -workspace, -rules (comma-separated rule kinds; defaults to the PR-default set), -format (sarif or json), -version.
Analyzer signal
find_unchecked_error— noise against the Go standard library dropped 1201 → ~800 hits (33%), via a built-in stdlib infallibility allowlist, a project-localinfallible {}config block, a CFG-based cleanup-path detector, and afmt.Staterecognizer that stops flagging writes insideFormat(s fmt.State, c rune)methods (~50+ stdlib call sites).find_race_condition— now recognizesx++/x--as writes. Goroutines capturing and incrementing a counter were silently producing no finding at all. Also honors Go 1.22+ per-iteration loop scoping, so loop-variable captures in a Go ≥ 1.22 module are no longer flagged unless the closure itself writes the variable.find_slice_append_race— recognizes mutex-protected appends.find_lock_violation— no longer flags a missing Unlock when the method value is returned, passed, or assigned; the obligation moved to the caller.find_error_swallow— re-implemented on top offind_unchecked_error's engine, inheriting its allowlist, cleanup-path detection and writer-arg transitivity while keeping its own value-use severity escalation. Tool name and input schema are unchanged, but it is stricter than before: baref.Close()discards are now flagged by default where the old implementation required an explicit opt-in.
Configuration
- New
infallible {}block in.caliper.pxfacceptingmethods,functions,writersanddisable_*counterparts, with*glob support. - Config now resolves per analysis path — each tool call walks up from its target looking for
.caliper.pxf, instead of a single boot-time load.
Performance
- Persistent result cache at
$TMPDIR/caliper-cache/, keyed on (tool, path, args, source fingerprint), with a 100 MB mtime-LRU cap (CALIPER_CACHE_MAX_BYTES). Repeat calls on unchanged source skip the coldpackages.Load— this survives the MCP reconnects that Claude Code's transport causes after every tool batch. - Engine cache lock fix — a fan-out of N parallel calls on a cold path no longer triggers N concurrent
packages.Loadinvocations.
Transport
mcp-goback on stock upstreamv0.57.0, un-patched and un-forked. The interim fork's only patch — panic recovery in the stdio tool-call worker — landed upstream in mark3labs/mcp-go#882, and upstream's version repliesINTERNAL_ERRORrather than dropping the message. Thereplacealso leaked throughgo.workinto sibling repos, which were compiling ~v0.49 code under a v0.57.0 label.- stderr tee to
$TMPDIR/caliper-mcp-YYYY-MM-DD.logwith timestamps, for diagnosing MCP disconnects.
Build
- CI runs gofmt + vet + build +
test -race+ golangci-lint on a self-hosted runner pinned to the go-plus toolchain. -ldflags "-X main.Version=..."support in both binaries, falling back todev-<vcs.revision>[-dirty]fromruntime/debug.BuildInfo.- Migrated from
trendvidia/protowiretoprotowire-go.
Install
brew install trendvidia/tap/caliperOr from source:
go install github.com/trendvidia/caliper/cmd/caliper-mcp@v1.1.0
go install github.com/trendvidia/caliper/cmd/caliper-analyze@v1.1.0Full changelog: v1.0.21...v1.1.0