beats

module
v0.1.9 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 15, 2026 License: MIT

README ΒΆ

CI Go Report Card GitHub release Sample Reports


beats

beats

Measure the structural fingerprint of a Go codebase.

beats clusters Go functions by the skeleton of how they are written β€” independent of names, comments, domain vocabulary or semantic meaning. The goal is to find meaningful patterns in code by looking at what it does structurally, not what it means semantically.

πŸ“– Read the full story on Medium β†’

For some quick easy context here are a couple of PRs that beats raised and merged:

Why beats

Every codebase has a rhythm β€” recurring structural patterns that developers fall into without naming them. Beats finds that pulse. When the rhythm is steady, you have convention. When it's irregular, you may want to pay attention.

Beats finds where the variance is and where it isn't.

Reports from sample OSS repositories
Project Repository Report
Argo CD argoproj/argo-cd View β†’
Mattermost mattermost/mattermost-server View β†’
Gitea go-gitea/gitea View β†’
cAdvisor google/cadvisor View β†’
CockroachDB cockroachdb/cockroach View β†’

πŸ” What is beats?

beats identifies recurring structural patterns across an entire Go codebase to answer one question: does the golang code across the repository coalesce to form a structural pattern and if so, how can we identify and evaluate the same?

Beats define Structural fingerprint as follows.

For each function, beats computes three features:

  1. Token sequence β€” an ordered list of AST mnemonics representing the structural skeleton of the function body. Each token is a normalised AST node, for example : CALL for a function call, ASSIGN for a variable assignment, RETURN for a return statement (with arity), IF, FOR, RANGE, and so on. No names, no literals β€” only structure.

  2. Direct imports β€” the set of packages actually used within the function (not just imported by the file). This captures the dependency shape at the function level, not the file level.

  3. Call targets (fan-out) β€” the set of external functions invoked within the function body.

No attempt is made to understand what a call target does or what an import statement provides. That would reintroduce vocabulary dependence and defeat the purpose.

These three features β€” along with some additional metadata β€” form a FunctionMetadata record.
Beats collects FunctionMetadata across the entire codebase and clusters structurally similar functions. Similarity between two functions is computed as the geometric mean of three signals, each normalized to [0, 1]: token-sequence similarity (1 βˆ’ normalized Levenshtein distance), Jaccard overlap of imports, and Jaccard overlap of called functions. Using the geometric mean (βˆ›(AΒ·BΒ·C)) rather than a weighted sum means a pair must score well across all three dimensions to be considered similar β€” a function with high token overlap but no shared imports or calls won't be treated as a match

Potential outliers

Functions that came structurally close to a cluster β€” but didn't meet the similarity threshold to join β€” are potential outliers. They look like they should follow a convention but deviate in a specific, measurable way.

For each outlier, beats surfaces the exact gap between the function and its closest cluster:

  • Token delta β€” token types present in the outlier but absent from the cluster's common subsequence, or vice versa. A +IF means the outlier has an extra branch peers don't; a βˆ’DEFER means it's missing a cleanup step they all share.
  • Import delta β€” packages the outlier uses that peers don't, or packages peers consistently use that this function omits.
  • Call delta β€” specific call targets (e.g. errors.Is, sync.Mutex.Lock) that peers share but the outlier skips, or that the outlier adds beyond the cluster norm.
  • Cyclomatic delta β€” how much more or less complex the outlier is relative to the cluster mean.

The HTML report groups outliers by their closest cluster and visualises the signal across three charts:

  • Package coverage β€” the top 20 packages by function count, split into clustered (settled convention) vs outliers (structural ad-hoc). Surfaces which areas of the codebase have converged on patterns and which haven't.
  • Delta direction β€” breaks all outliers into three buckets: missing something peers have (strongest signal), extending beyond peers, or both. A repo dominated by the "missing" bucket has more structural drift worth reviewing.
  • Token frequency β€” the top 10 token types most commonly absent from outliers compared to their peer clusters. A dominant type appearing across many outliers (e.g. DEFER, IF) signals a systemic gap rather than a one-off.

beats also writes <repo>/.beats/outlier.md after indexing β€” a pre-computed document with every outlier, its deltas, and the full bodies of its closest cluster's peer functions. This is what the Claude skill reads to triage outliers without issuing any further queries.

Remember, beats is a lens - not a prescription.


πŸ€– Analyze with Claude

beats ships a Claude plugin that wires the outlier triage into a conversational skill.

Install the plugin

Inside Claude Code or Cowork, add the marketplace and install:

/plugin marketplace add somak2kai/beats
/plugin install beats@beats

Index in your terminal, triage in Claude. This is the lowest-cost way to run beats.

beats init does pure computation β€” parsing, clustering, writing the database. It produces no output that needs LLM reasoning. Running it inside Claude wastes tokens on a step that doesn't benefit from them.

Step 1 β€” index in your terminal:

beats init --repo /path/to/your/go/repo

This writes <repo>/.beats/outlier.md and <repo>/.beats/report.html. No Claude involved.

Step 2 β€” triage in Claude:

mini fingerprint

Tell Claude the repo path when prompted. Claude reads outlier.md directly and outputs the full triage β€” no indexing, no repeated database queries, just analysis.

This keeps Claude's token budget focused entirely on the one step that actually needs it.

Full mode (all-in-one)

If you prefer to run everything through Claude in one command:

run beats on /path/to/your/go/repo

Claude will handle install verification, beats init, triage, and the HTML report. Convenient, but costs more tokens since indexing runs inside the Claude session.

What the LLM analysis does

For each outlier, Claude matches its closest cluster hash to the peer cluster in outlier.md and reads the actual function bodies of every cluster member. It then asks one question per structural signal:

Does the function body explain this deviation from its peers?

If yes β†’ Expected Variation. If no β†’ Needs Attention. The verdict is always tied to a specific delta β€” a token type, import, call target, or cyclo difference β€” not a general code quality opinion.


πŸ“¦ Installation
Prerequisites
  • Go 1.21 or later
  • Git
Install via Homebrew (macOS / Linux)
brew tap somak2kai/tap
brew install beats

Upgrade to the latest release at any time:

brew upgrade beats
Install from source

Clone the repository and build the CLI:

git clone https://github.com/somak2kai/beats.git
cd beats
go build -o beats ./cmd/

Move the binary somewhere on your $PATH:

mv beats /usr/local/bin/

Or run directly without installing:

go run ./cmd/ <command> [flags]
Verify
beats --version

πŸš€ Usage

beats has one main commands: init to index a repository , to create clusters and report on it.


beats init β€” index a repository

Walks a Go codebase and writes FunctionMetadata records into a local Badger store.

beats init --repo=<path-to-go-repository>

Example:

beats init --repo=/home/user/projects/myservice

What gets indexed:

  • All Go source files under the repository root (excluding vendor/ and test files by default, auto generated files such as pb.go)
  • For each exported and unexported function: token sequence, call targets, direct imports, file path, line number, package name
  • runs the clustering algorithm, and produces an HTML report at <repo>/.beats/report.html.

Open the report:

open /home/user/projects/myservice/.beats/report.html

The report shows all clusters sorted by combined coherence, with per-cluster member lists, top imports, Cyclo P95, package distribution, and a coherence quadrant breakdown.



❀️

Directories ΒΆ

Path Synopsis
pkg
ast
calibrate
Package calibrate provides threshold calibration for the beats clustering pipeline.
Package calibrate provides threshold calibration for the beats clustering pipeline.
db

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL