A repository is not simply "a project". It builds something, and what it builds decides which practices are reasonable to expect from it. A published library is expected not to commit a dependency lockfile — the versions it pins would be ignored by everyone installing it. The application beside it in the catalogue is expected to commit one, because the versions it pins are exactly what gets deployed. Judging both by one rule misreads one of them.
Until metrics 2.3.0 a single proxy stood in for the question: does the repository publish a package to a registry. That reads every command-line tool on PyPI as a library, and every application that happens to ship one helper package as one too.
Every reading the evidence supports
The classification is multi-label. Software that is both a published library and a runnable tool is the ordinary case, not a contradiction to be resolved: ripgrep is a crate and a binary, esbuild is an npm package and an executable. A repository therefore keeps every reading its evidence supports.
Three questions are answered independently, and a repository can answer yes to more than one:
| Question | True for | What it makes reasonable to expect |
|---|---|---|
| Consumed as code | library, framework, SDK, API client, middleware, driver | A stable interface, a changelog, versioning other software can depend on |
| Run as a program | command-line tool, terminal interface, desktop and mobile application, web interface, network service, chat bot, MCP server | Pinned dependencies, deployment and configuration hygiene |
| Installed into a host | plugin, extension, theme, editor tooling | The host supplies the trust model and the release cadence |
Where both apply, both apply — a hybrid owes the obligations of every reading it carries, never the most lenient one.
The labels
| Consumed as code | Run as a program | Installed into a host |
|---|---|---|
| Library | Command-line tool | Plugin |
| Framework | Terminal interface | Extension |
| SDK | Desktop application | Theme |
| API client | Mobile application | Editor tooling |
| Middleware | Web interface | |
| Driver | Network service | |
| Chat bot | ||
| MCP server |
Notebook is a label of its own and belongs to none of the three: it is read and run by a person, imported by nothing, and installed into nothing.
How the answer is reached
Evidence is ranked by how far it can be trusted, and no single weak signal produces a label.
| Evidence | Examples | Weight |
|---|---|---|
| Declared in a build manifest | an npm bin entry, a console_scripts entry point, <OutputType>Exe</OutputType>, Composer's type, Maven's <packaging>, a Cargo [lib] target | Decisive |
| Declared by the registry | a Packagist type, a NuGet package type, a crates.io category | Strong |
| Declared dependencies | a web framework, a CLI argument parser, a chat-platform client | Moderate |
| File-tree structure | cmd/…/main.go, src-tauri/, a Helm chart, a browser-extension manifest | Supporting |
| Repository topics and registry keywords | cli, wordpress-plugin, self-hosted | Weak — self-assigned |
| The repository description | "a CLI for…", "a library for…" | Weak — self-assigned |
The first two are the strongest because they are not opinions: a maintainer who writes <OutputType>Exe</OutputType> is not describing the software, the build would not work otherwise. A topic is an opinion, and two of them agreeing is the minimum that carries anything at all.
Evidence also runs the other way. A Cargo package with publish = false, a Composer type of project, a .NET tool, a Maven war — each rules out being something other software can depend on, whatever else the repository looks like.
Where the answer is absent
Three situations produce no classification, and all three are ordinary:
- The report predates metrics 2.3.0. Every stored report was reclassified from the facts it already carried, but the manifest evidence is collected during a scan — so reports gathered earlier carry the weaker tiers only, and gain the full reading when the repository is next inspected.
- The evidence does not answer the question. Many repositories publish no manifest, carry no informative topics, and describe themselves in prose that states nothing structural.
- The answer would be a guess. Where signals are present but too weak to cross the threshold, nothing is claimed.
In all three the report simply shows no classification. Absence is never presented as a finding, nothing is scored on it, and a repository without one is not marked, ranked, or penalized in any way.
Repositories that build several things
A monorepo holding a deployable service beside three published libraries is not one artifact, and rolling it up to a single answer would lose the fact that both readings are true. Each manifest is therefore classified on its own declarations, and the repository carries the union.
One consequence is worth stating plainly: the single primary label shown for such a repository is the best-supported one, which in a large monorepo can be a published build tool rather than the product the project is known for. The primary label exists for display and for grouping comparable repositories — it is never the basis of a scoring decision.
What it affects today
Nothing. As of metrics 2.3.0 the classification is published as data — metrics.classification in every report, alongside the evidence that produced it — and no metric reads it. Connecting it to the metrics that depend on it, beginning with the dependency-lockfile expectation, is a separate change and will be recorded in the methodology versions when it lands.