{
  "markdown": "# Sighttrue\n\n**[sighttrue.com](https://sighttrue.com)** · [your stack](https://sighttrue.com/stack) · [compare](https://sighttrue.com/compare) · [method](https://sighttrue.com/method) · [feed](https://sighttrue.com/feed.xml)\n\n## Check your dependencies in CI\n\n```yaml\npermissions:\n  pull-requests: write   # only needed for the comment\n\nsteps:\n  - uses: actions/checkout@v4\n  - uses: sighttrue/sighttrue@v1\n    with:\n      manifest: package.json\n      fail-on: withdrawn,archived,relicensed\n```\n\nFails the build when a dependency's own publisher has withdrawn it — npm calls\nit deprecated, PyPI and crates.io call it yanked, RubyGems yanked, Packagist\nabandoned, NuGet deprecated — or when its repository has been archived or moved\nto a source-available licence, and reports advisories either way. Reads\n`package.json`, `requirements.txt`, `pyproject.toml`, `Cargo.toml`,\n`composer.json` and `Gemfile`. No key, no\naccount, no service to sign up to — it reads published measurements and talks\nto OSV. A network problem is never a finding: if the readings cannot be fetched\nthe step says so and passes, because a build that breaks when somebody else's\nsite is down is a build that gets deleted.\n\nOn a pull request it also leaves a comment with the findings as a table, and\nrewrites that same comment on every push rather than adding another. A red\nbuild tells a reviewer that something is wrong; it does not tell them which\ndependency, or what changed about it, without opening the log. Set\n`comment: false` to report only in the step summary. A pull request from a fork\ngets a read-only token, so the comment is skipped there and the step still\npasses.\n\nAlso runs against `requirements.txt` and `Cargo.toml`.\n\n## Or install the App and change nothing\n\nThe Action needs a workflow file in every repository that wants it. The GitHub\nApp needs one install and then watches every repository it is given, with no\nworkflow, no key and no configuration: when a pull request adds a runtime\ndependency that is on the watchlist, it leaves one comment with what is on\nrecord — downloads, OpenSSF scorecard, advisory count, licence, last push — and\nedits that same comment on every later push.\n\nIt says nothing at all when a pull request changes no manifest, adds no\ndependency, or adds nothing that is tracked. That is the common case and it is\nthe point: a bot that comments to say it found nothing gets uninstalled. It\nnever calls a package safe, unsafe or recommended, because none of those are\nthings this project measures.\n\nThe Action fails a build; the App only reports. Both read the same published\nbundle, so they cannot disagree.\n\n## An SBOM you are allowed to hand over\n\n[/stack](https://sighttrue.com/stack) exports the readout as a CycloneDX 1.6\ndocument, with each dependency's advisory count, scorecard, licence, publish\ndate and bus factor attached as properties. Built in the browser from the\npasted manifest, like everything else on that page — nothing is uploaded, and\nthere is no endpoint to send a manifest to.\n\nIt states no versions. A manifest declares `^1.6.0`; it does not say what was\ninstalled, and it says nothing about the transitive tree underneath. The\ndocument says both of those things in its own metadata rather than leaving a\nreader to notice, because an SBOM that guessed would be worse than none: a\ncompliance artefact asserting something nobody resolved.\n\n## Suggest something to watch\n\nThe watchlist is curated and partial, and it was chosen by hand with no method\nbeyond judgement — its weakest point. [Open an issue](../../issues/new?template=watch-a-repository.yml)\nto argue for a repository. Every change to the list is a reviewed commit, so\nthat issue is where the review happens.\n\n## For coding agents\n\nAn MCP server over the same readings, so an agent can answer \"is this\ndependency healthy\" from a measurement taken today rather than from training\ndata a year old.\n\n```json\n{ \"mcpServers\": { \"readout\": { \"url\": \"https://sighttrue.com/api/mcp\" } } }\n```\n\n<!-- figures:tools -->Nine tools free, twenty-two paid.<!-- /figures:tools --> `check_before_install` is the one to reach for while writing code:\ngiven a package it returns only what a reviewer would be annoyed to discover\nafterwards — a publisher that withdrew it, scripts it runs on the installing\nmachine, an archived repository, advisories, a source-available licence, a long\nsilence — each with the address of the body that published it. It does not say\nwhether to install. It says what is on record so the decision is made knowing\nit, and an empty result says plainly that it means nothing was found rather\nthan that the package is safe.\n\nThen <!-- figures:free -->`check_package`, `check_stack`, `search_repositories`, `compare_repositories`, `find_model`, `check_eol`, `check_provider`, `list_readings`<!-- /figures:free -->. Read-only, no key, no account. Every result carries the\nlimits of what it can support, because an agent will paste these figures into a\ncode review and a scorecard quoted without \"measures declared practices, not\nwhether the project is safe\" is a claim this project does not make.\n\nWithout MCP, one GET returns the same thing:\n\n```\ncurl 'https://sighttrue.com/api/verdict?pkg=npm:axios'\ncurl 'https://sighttrue.com/api/verdict?pkg=pypi:django&version=4.2'\n```\n\nAdvisories, licence, when the registry last shipped it, the bus factor, and\nwhether the release is still supported — each with the address of the body that\npublished it, so a figure quoted into a review can be checked in one click.\nDespite the name there is no verdict in it: no score, no rank, no\nrecommendation. Those would be this project's judgement of somebody else's work\nwearing the costume of a measurement.\n\n<!-- figures:scale -->One agent watches 417 open-source repositories and takes\neleven readings, most of which never touch GitHub: 807 provider incidents kept\nafter their own status pages dropped them, 522 release lines on the end-of-life\nclock, 382 model prices, 182 packages by real ship date, 416 commit histories\nfor the bus factor.<!-- /figures:scale --> It runs every four hours on GitHub\nActions, commits what it reads to this repository, and publishes a static site.\n\nEvery page and every bundle is a file. There are five dynamic routes and no page\ndepends on any of them: `/api/ask`, `/api/mcp`, `/api/chain`,\n`/api/github/webhook` for the App, and the sign-in and watchlist endpoints under\n`/api/auth` and `/api/watchlist`. Signing in with\nGitHub saves a watchlist and nothing else — the readings on a signed-in page are\nthe same published bundle anyone can download.\n\nThe commit history of `data/` is the point. It is an audit trail: every reading\nis timestamped, append-only, and checkable against GitHub directly.\n\n## What it reports\n\nEleven readings, each named by the question it answers rather than by the\ncollector that produces it. The same list drives the site's navigation, so the\ntwo cannot drift — they had, three times over, before it was written down once.\n\n| Reading | Question it answers | Touches GitHub |\n|---|---|---|\n| Live | What changed in the last few hours? | yes |\n| Ships | What released a new version? | yes |\n| Forks | What is being copied faster than its own baseline? | yes |\n| Demand | What are developers asking for, across more than one project? | yes |\n| Dependencies | What is being added, dropped, or jumped a major version? | yes |\n| Lineage | Which models say they were built on which? | no |\n| Model prices | What does a million tokens cost, and when did that change? | no |\n| Outages | Does the thing I depend on go down, and how often? | no |\n| Ecosystem | What do the registries, advisories and forums say? | no |\n| Depended on | What does everything else quietly rely on? | no |\n| This week | What would I have missed looking once a week? | — |\n\nThe six that never touch GitHub are the answer to the fair complaint that a\nGitHub summariser is worth only what GitHub already shows you.\n\nWhether each detector's threshold is reachable at all is published too, on the\nindex under Our record. A detector nothing has ever come close to is not a quiet\ndetector, it is a misconfigured one, and the site says so about itself.\n\n## How to read it\n\n**Every comparison is against a repository's own history**, not against other\nrepositories. \"27× baseline\" means 27 times what that project normally does, and\nthe baseline is drawn on the chart so you can see what normal means.\n\n**Confidence is stated, never implied.**\n\n| State | Meaning |\n|---|---|\n| `forming` | Under 14 days of history. Raw counts only. No multiplier is computed and none is implied. |\n| `detected` | Crossed the threshold once. Neutral treatment. |\n| `confirmed` | Persisted across two consecutive daily snapshots. |\n\nOnly `confirmed` signals are treated as findings. That costs up to a day of\nspeed and buys the thing that cannot be bought back.\n\n**Generated prose is set in a different typeface from measured values.** Where a\nsentence explains a number, every figure in that sentence is checked against the\nsource record before it is published; if any of them is not in the record, the\nsentence is discarded and a templated one is used instead.\n\n## What this does not claim\n\n- The watchlist is **curated and partial**. It is chosen by hand and is not a\n  survey of open source. Dependency and demand findings describe the\n  repositories being watched, not the ecosystem.\n- The data is **not real-time**. Four hours is the floor, and scheduled runs are\n  routinely delayed.\n- Nothing here predicts anything, and nothing here says a repository is good,\n  bad, safe, or unsafe.\n- Appearing on the watchlist is an observation, not a relationship. No project\n  listed here has endorsed this.\n\nPublished findings that turn out to be wrong are superseded by a correction\nevent carrying the same prominence. Events are never deleted and history is\nnever rewritten.\n\n## The data\n\nEvery bundle the site reads is served as JSON, so any claim can be checked\nagainst the same file the page used.\n\n```\ndata/\n├── live/state.jsonl          Latest reading per repository. Sorted, rewritten each pulse.\n├── live/window.jsonl         Timestamped fork samples, for the rolling 24h delta.\n├── live/manifests.jsonl      Last-seen dependency set, diffed daily.\n├── history/YYYY-MM-DD.jsonl  One immutable snapshot per day.\n├── events/YYYY-MM.jsonl      Append-only. Never rewritten, never pruned.\n├── summaries.jsonl           Generated prose, keyed by event id.\n├── watchlist.jsonl           What is watched, and since when.\n└── meta.json                 Last run status.\n```\n\nFiles are sorted with a fixed key order so a repository that did not change\nproduces no diff. That is what keeps a repository committed to six times a day\nfrom growing without bound.\n\n## Running it\n\nNode 24. Types are stripped natively, so there is no build step and no runtime\ndependencies.\n\nIt said 22.18+ until the D1 schema arrived. The tests load `migrations/` into\n`node:sqlite`, which is stable in 24 and behind a flag in 22 — so on 22 the\nsuite fails on an import rather than on an assertion, which is a confusing way\nto learn a version requirement.\n\n```sh\nnpm install          # dev dependencies only: typescript, vitest, fonts\nnpm test\nnpm run typecheck\n\nnode scripts/pulse.ts --limit=20   # needs GITHUB_PAT\nnode scripts/daily.ts\nnode scripts/build.ts              # emits dist/\n```\n\n### Watchlist maintenance\n\nThe watchlist is curated. Deriving it from a search query was tried and produced\na worse list — topic search only finds repositories that tagged themselves, and\nsorting by stars ranks tutorials and link collections above infrastructure.\n`derive-watchlist.ts` is kept for proposing candidates a curator might have\nmissed, and because the negative result is worth being able to reproduce.\n\n```sh\nnode scripts/verify-watchlist.ts   # check every entry against the API\nnode scripts/retire-watchlist.ts   # mark archived and deleted ones inactive\nnode scripts/derive-watchlist.ts   # propose candidates, writes nothing\nnode scripts/derive-packages.ts    # map repositories to packages, writes nothing\n```\n\n`derive-packages.ts` fills the `packages` field, which is what lets the agent\nask what a project's downloads are doing rather than only what its repository is\ndoing. It never maps on a name match: a candidate is proposed, the registry's own\nrecord for that name is fetched, and the mapping is kept only when the registry\npoints back at this repository. That rule is not decoration — the first version\nmatched on substring and mapped `angular/angular` to the npm package `angular`,\nwhich belongs to the archived `angular/angular.js`, and would have credited a\ndead project's downloads to a live one.\n\nNothing is ever removed. Retired entries stay on the list with `active: false`,\nbecause deleting one would erase the record that it was watched at all, and the\nfindings collected while it was still link to it.\n\nTwo scheduled workflows do the rest. `pulse.yml` runs every four hours for\nrepository base and releases; `daily.yml` writes the canonical snapshot,\nclassifies spikes, and collects issues and manifests. Both commit every run,\nincluding when nothing changed — scheduled workflows are disabled after 60 days\nof repository inactivity, and that commit is what prevents it.\n\n### Configuration\n\n| Secret | Purpose |\n|---|---|\n| `SIGNAL_GITHUB_PAT` | Fine-grained token, public repository read only. Secret names cannot begin with `GITHUB_`. |\n| `CLOUDFLARE_API_TOKEN` | Cloudflare Pages: Edit |\n| `CLOUDFLARE_ACCOUNT_ID` | |\n| `GROQ_API_KEY` | Optional. Without it every reading still publishes, with numbers and no prose. |\n\nBoth optional groups are genuinely optional: unset, their steps skip and say so.\nNothing is marked as a failed run, because choosing not to configure something\nis not a fault, and a warning that is always on is a warning nobody reads.\n\n## License\n\nMIT. See [LICENSE](LICENSE).\n\n## Cost\n\nCloudflare Pages, GitHub Actions on a public repository, and Groq's free tier.\nStatic assets and bandwidth on Pages are unlimited, so visitor traffic has no\nceiling. Every remaining limit applies to the build side, which is bounded and\npredictable.\n",
  "bytes": 14160,
  "sha": "38f2291e935a262d1b36635642552a981ea44726ef9ddefafa62d494b06f2146",
  "repo_slug": "kaitzyy-dev/readout",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_kaitzyy_dev_readout_c90e65c4/readme"
}